summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2021-11-29 17:19:16 -0500
committerMoonchild <moonchild@palemoon.org>2022-04-06 23:28:22 +0200
commit63b8aaa49509ef54628061db640bc0afdf0b5a1a (patch)
treea1a55db5f262bfbb78402251d2b832f75871b1a3
parent4897e3653a1da346ac7f6f48c77717582e6c9c79 (diff)
downloaduxp-63b8aaa49509ef54628061db640bc0afdf0b5a1a.tar.gz
Issue #1845 - Remove Marionette files
-rw-r--r--old-configure.in6
-rw-r--r--testing/firefox-ui/.flake83
-rw-r--r--testing/firefox-ui/harness/MANIFEST.in2
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/__init__.py8
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py6
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py18
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/arguments/update.py65
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py21
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/cli_update.py21
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py6
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/runners/base.py45
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/runners/update.py101
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/testcases.py420
-rw-r--r--testing/firefox-ui/harness/requirements.txt5
-rw-r--r--testing/firefox-ui/harness/setup.py44
-rw-r--r--testing/firefox-ui/mach_commands.py120
-rw-r--r--testing/firefox-ui/moz.build11
-rw-r--r--testing/firefox-ui/resources/addons/extensions/restartless_addon_signed.xpibin186036 -> 0 bytes
-rw-r--r--testing/firefox-ui/resources/addons/extensions/restartless_addon_unsigned.xpibin177535 -> 0 bytes
-rw-r--r--testing/firefox-ui/resources/cookies/cookie_single.html16
-rw-r--r--testing/firefox-ui/resources/images/firefox_favicon.icobin1150 -> 0 bytes
-rw-r--r--testing/firefox-ui/resources/images/mozilla_favicon.icobin1406 -> 0 bytes
-rw-r--r--testing/firefox-ui/resources/images/mozilla_logo.jpgbin3298 -> 0 bytes
-rw-r--r--testing/firefox-ui/resources/layout/mozilla.html45
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_community.html57
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_contribute.html70
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_governance.html38
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_grants.html72
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_mission.html51
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_organizations.html39
-rw-r--r--testing/firefox-ui/resources/layout/mozilla_projects.html60
-rw-r--r--testing/firefox-ui/resources/private_browsing/about.html10
-rw-r--r--testing/firefox-ui/resources/security/enable_privilege.html21
-rw-r--r--testing/firefox-ui/resources/support.html19
-rw-r--r--testing/firefox-ui/tests/functional/keyboard_shortcuts/manifest.ini4
-rw-r--r--testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py56
-rw-r--r--testing/firefox-ui/tests/functional/locationbar/manifest.ini9
-rw-r--r--testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py60
-rw-r--r--testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py56
-rw-r--r--testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py62
-rw-r--r--testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py96
-rw-r--r--testing/firefox-ui/tests/functional/manifest.ini5
-rw-r--r--testing/firefox-ui/tests/functional/private_browsing/manifest.ini4
-rw-r--r--testing/firefox-ui/tests/functional/private_browsing/test_about_private_browsing.py60
-rw-r--r--testing/firefox-ui/tests/functional/security/manifest.ini22
-rw-r--r--testing/firefox-ui/tests/functional/security/test_dv_certificate.py85
-rw-r--r--testing/firefox-ui/tests/functional/security/test_enable_privilege.py17
-rw-r--r--testing/firefox-ui/tests/functional/security/test_ev_certificate.py112
-rw-r--r--testing/firefox-ui/tests/functional/security/test_mixed_content_page.py55
-rw-r--r--testing/firefox-ui/tests/functional/security/test_mixed_script_content_blocking.py87
-rw-r--r--testing/firefox-ui/tests/functional/security/test_no_certificate.py81
-rw-r--r--testing/firefox-ui/tests/functional/security/test_safe_browsing_initial_download.py84
-rw-r--r--testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py149
-rw-r--r--testing/firefox-ui/tests/functional/security/test_safe_browsing_warning_pages.py115
-rw-r--r--testing/firefox-ui/tests/functional/security/test_security_notification.py62
-rw-r--r--testing/firefox-ui/tests/functional/security/test_ssl_disabled_error_page.py60
-rw-r--r--testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py124
-rw-r--r--testing/firefox-ui/tests/functional/security/test_submit_unencrypted_info_warning.py65
-rw-r--r--testing/firefox-ui/tests/functional/security/test_unknown_issuer.py34
-rw-r--r--testing/firefox-ui/tests/functional/security/test_untrusted_connection_error_page.py35
-rw-r--r--testing/firefox-ui/tests/functional/sessionstore/manifest.ini5
-rw-r--r--testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_restart.py150
-rw-r--r--testing/firefox-ui/tests/puppeteer/manifest.ini24
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_about_window.py74
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_appinfo.py31
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_l10n.py51
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_menubar.py30
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_notifications.py82
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_page_info_window.py100
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_places.py85
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_security.py45
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_software_update.py134
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_tabbar.py191
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_toolbars.py283
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_update_wizard.py67
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_utils.py48
-rw-r--r--testing/firefox-ui/tests/puppeteer/test_windows.py259
-rw-r--r--testing/firefox-ui/tests/update/direct/manifest.ini4
-rw-r--r--testing/firefox-ui/tests/update/direct/test_direct_update.py21
-rw-r--r--testing/firefox-ui/tests/update/fallback/manifest.ini4
-rw-r--r--testing/firefox-ui/tests/update/fallback/test_fallback_update.py22
-rw-r--r--testing/firefox-ui/tests/update/manifest.ini2
-rw-r--r--testing/mach_commands.py22
-rw-r--r--testing/marionette/accessibility.js441
-rw-r--r--testing/marionette/action.js1348
-rw-r--r--testing/marionette/addon.js104
-rw-r--r--testing/marionette/assert.js322
-rw-r--r--testing/marionette/atom.js192
-rw-r--r--testing/marionette/browser.js436
-rw-r--r--testing/marionette/capture.js193
-rw-r--r--testing/marionette/cert.js139
-rw-r--r--testing/marionette/chrome/test.xul25
-rw-r--r--testing/marionette/chrome/test2.xul19
-rw-r--r--testing/marionette/chrome/test_anonymous_content.xul37
-rw-r--r--testing/marionette/chrome/test_dialog.dtd7
-rw-r--r--testing/marionette/chrome/test_dialog.properties7
-rw-r--r--testing/marionette/chrome/test_dialog.xul36
-rw-r--r--testing/marionette/chrome/test_nested_iframe.xul9
-rw-r--r--testing/marionette/client/.flake83
-rw-r--r--testing/marionette/client/MANIFEST.in2
-rw-r--r--testing/marionette/client/docs/Makefile153
-rw-r--r--testing/marionette/client/docs/advanced/actions.rst46
-rw-r--r--testing/marionette/client/docs/advanced/debug.rst54
-rw-r--r--testing/marionette/client/docs/advanced/findelement.rst126
-rw-r--r--testing/marionette/client/docs/advanced/landing.rst13
-rw-r--r--testing/marionette/client/docs/advanced/stale.rst71
-rw-r--r--testing/marionette/client/docs/basics.rst185
-rw-r--r--testing/marionette/client/docs/conf.py259
-rw-r--r--testing/marionette/client/docs/index.rst16
-rw-r--r--testing/marionette/client/docs/interactive.rst55
-rw-r--r--testing/marionette/client/docs/make.bat190
-rw-r--r--testing/marionette/client/docs/reference.rst51
-rw-r--r--testing/marionette/client/marionette_driver/__init__.py26
-rw-r--r--testing/marionette/client/marionette_driver/addons.py70
-rw-r--r--testing/marionette/client/marionette_driver/by.py27
-rw-r--r--testing/marionette/client/marionette_driver/date_time_value.py49
-rw-r--r--testing/marionette/client/marionette_driver/decorators.py69
-rw-r--r--testing/marionette/client/marionette_driver/errors.py179
-rw-r--r--testing/marionette/client/marionette_driver/expected.py311
-rw-r--r--testing/marionette/client/marionette_driver/geckoinstance.py464
-rw-r--r--testing/marionette/client/marionette_driver/gestures.py93
-rw-r--r--testing/marionette/client/marionette_driver/keys.py84
-rw-r--r--testing/marionette/client/marionette_driver/localization.py54
-rw-r--r--testing/marionette/client/marionette_driver/marionette.py2153
-rw-r--r--testing/marionette/client/marionette_driver/selection.py227
-rw-r--r--testing/marionette/client/marionette_driver/timeout.py98
-rw-r--r--testing/marionette/client/marionette_driver/transport.py300
-rw-r--r--testing/marionette/client/marionette_driver/wait.py167
-rw-r--r--testing/marionette/client/requirements.txt2
-rw-r--r--testing/marionette/client/setup.py49
-rw-r--r--testing/marionette/components/marionette.js237
-rw-r--r--testing/marionette/components/marionette.manifest4
-rw-r--r--testing/marionette/components/moz.build9
-rw-r--r--testing/marionette/cookies.js131
-rw-r--r--testing/marionette/dispatcher.js228
-rw-r--r--testing/marionette/driver.js2907
-rw-r--r--testing/marionette/element.js1171
-rw-r--r--testing/marionette/error.js500
-rw-r--r--testing/marionette/evaluate.js494
-rw-r--r--testing/marionette/event.js1365
-rw-r--r--testing/marionette/frame.js260
-rw-r--r--testing/marionette/harness/.flake83
-rw-r--r--testing/marionette/harness/MANIFEST.in3
-rw-r--r--testing/marionette/harness/README.rst30
-rw-r--r--testing/marionette/harness/marionette_harness/__init__.py35
-rw-r--r--testing/marionette/harness/marionette_harness/marionette_test/__init__.py31
-rw-r--r--testing/marionette/harness/marionette_harness/marionette_test/decorators.py239
-rw-r--r--testing/marionette/harness/marionette_harness/marionette_test/testcases.py504
-rw-r--r--testing/marionette/harness/marionette_harness/runner/__init__.py22
-rw-r--r--testing/marionette/harness/marionette_harness/runner/base.py1076
-rw-r--r--testing/marionette/harness/marionette_harness/runner/httpd.py142
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/__init__.py13
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/History.md57
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/__init__.py6
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/client.py326
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/server.py106
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/webdriver_event_listener.py34
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/Makefile153
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/.buildinfo4
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/browsermobproxy.html98
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/index.html90
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/client.txt8
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/index.txt72
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/server.txt8
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/basic.css537
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/default.css256
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/doctools.js238
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/jquery.js2
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/pygments.css62
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/searchtools.js622
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/sidebar.js159
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/underscore.js31
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/websupport.js808
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/client.html404
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/genindex.html297
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/index.html174
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/objects.inv6
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/py-modindex.html112
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/search.html105
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/searchindex.js1
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/server.html157
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/client.rst8
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/conf.py243
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/index.rst72
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/make.bat190
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/server.rst8
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/readme.md88
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/setup.py20
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_client.py247
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_remote.py31
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_webdriver.py60
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/browsermob.py80
-rw-r--r--testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py129
-rwxr-xr-xtesting/marionette/harness/marionette_harness/runner/serve.py227
-rw-r--r--testing/marionette/harness/marionette_harness/runner/test.cert86
-rw-r--r--testing/marionette/harness/marionette_harness/runner/test.key28
-rw-r--r--testing/marionette/harness/marionette_harness/runtests.py98
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/conftest.py100
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_httpd.py90
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py32
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_harness.py108
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py442
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_test_result.py54
-rw-r--r--testing/marionette/harness/marionette_harness/tests/harness_unit/test_serve.py67
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit-tests.ini11
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/importanotherscript.js1
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/importscript.js1
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/mn-restartless-unsigned.xpibin1552 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/single_finger_functions.py131
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_about_pages.py134
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_accessibility.py210
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_addons.py58
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py90
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_browsermobproxy.py34
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py253
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_checkbox.py17
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_checkbox_chrome.py36
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_chrome.py51
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js6
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_chrome_element_css.py23
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_clearing.py72
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_click.py271
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py35
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py117
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_cookies.py115
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_crash.py155
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_data_driven.py67
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_date_time_value.py29
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_element_retrieval.py483
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_element_state.py162
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py85
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_elementsize.py17
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_elementsize_chrome.py34
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_errors.py77
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_execute_async_script.py156
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_execute_isolate.py37
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_execute_sandboxes.py79
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py402
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_expected.py228
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_expectedfail.py11
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_file_upload.py152
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py82
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_geckoinstance.py25
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_getactiveframe_oop.py93
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_implicit_waits.py26
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_import_script.py138
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_key_actions.py91
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_localization.py56
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_log.py64
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py67
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py198
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py114
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py447
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_pagesource.py33
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_pagesource_chrome.py29
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_position.py19
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py167
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py34
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_proxy.py252
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py173
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_rendered_element.py34
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_report.py29
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_run_js_test.py10
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_screen_orientation.py86
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py428
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_select.py164
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_session.py56
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_set_window_size.py84
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_shadow_dom.py80
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js12
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js16
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js12
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py107
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js16
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_single_finger_desktop.py123
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_skip_setup.py35
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py183
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame_chrome.py56
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_switch_remote_frame.py118
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_chrome.py124
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_content.py171
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_teardown_context_preserved.py21
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_text.py224
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_text_chrome.py44
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_timeouts.py115
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_transport.py172
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_typing.py332
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_using_permissions.py46
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_visibility.py121
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_wait.py347
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_close_chrome.py80
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py81
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_chrome.py207
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_content.py96
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_position.py42
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_title.py12
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py26
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py27
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/test_with_using_context.py66
-rw-r--r--testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini132
-rw-r--r--testing/marionette/harness/marionette_harness/tests/webapi-tests.ini5
-rw-r--r--testing/marionette/harness/marionette_harness/www/black.pngbin150 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/bug814037.html55
-rw-r--r--testing/marionette/harness/marionette_harness/www/click_out_of_bounds_overflow.html90
-rw-r--r--testing/marionette/harness/marionette_harness/www/clicks.html39
-rw-r--r--testing/marionette/harness/marionette_harness/www/cssTransform.html61
-rw-r--r--testing/marionette/harness/marionette_harness/www/cssTransform2.html20
-rw-r--r--testing/marionette/harness/marionette_harness/www/datetimePage.html15
-rw-r--r--testing/marionette/harness/marionette_harness/www/deletingFrame.html29
-rw-r--r--testing/marionette/harness/marionette_harness/www/double_click.html18
-rw-r--r--testing/marionette/harness/marionette_harness/www/element_bottom.html12
-rw-r--r--testing/marionette/harness/marionette_harness/www/element_left.html12
-rw-r--r--testing/marionette/harness/marionette_harness/www/element_outside_viewport.html41
-rw-r--r--testing/marionette/harness/marionette_harness/www/element_right.html12
-rw-r--r--testing/marionette/harness/marionette_harness/www/element_top.html12
-rw-r--r--testing/marionette/harness/marionette_harness/www/empty.html12
-rw-r--r--testing/marionette/harness/marionette_harness/www/formPage.html116
-rw-r--r--testing/marionette/harness/marionette_harness/www/frameset.html14
-rw-r--r--testing/marionette/harness/marionette_harness/www/framesetPage2.html7
-rw-r--r--testing/marionette/harness/marionette_harness/www/hidden.html5
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/blue.jpgbin92 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/boolean_attributes.html2
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/geolocation.js18
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/green.jpgbin92 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/offline.html1
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/red.jpgbin92 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/status.html1
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/test.appcache11
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/test_html_inputs.html2
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5/yellow.jpgbin92 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/html5Page.html45
-rw-r--r--testing/marionette/harness/marionette_harness/www/javascriptPage.html278
-rw-r--r--testing/marionette/harness/marionette_harness/www/macbeth.html5254
-rw-r--r--testing/marionette/harness/marionette_harness/www/modal_dialogs.html39
-rw-r--r--testing/marionette/harness/marionette_harness/www/nestedElements.html9
-rw-r--r--testing/marionette/harness/marionette_harness/www/rectangles.html40
-rw-r--r--testing/marionette/harness/marionette_harness/www/resultPage.html17
-rw-r--r--testing/marionette/harness/marionette_harness/www/scroll.html30
-rw-r--r--testing/marionette/harness/marionette_harness/www/scroll2.html24
-rw-r--r--testing/marionette/harness/marionette_harness/www/scroll3.html18
-rw-r--r--testing/marionette/harness/marionette_harness/www/scroll4.html15
-rw-r--r--testing/marionette/harness/marionette_harness/www/scroll5.html20
-rw-r--r--testing/marionette/harness/marionette_harness/www/shim.js282
-rw-r--r--testing/marionette/harness/marionette_harness/www/test.html38
-rw-r--r--testing/marionette/harness/marionette_harness/www/testAction.html94
-rw-r--r--testing/marionette/harness/marionette_harness/www/testPageSource.html14
-rw-r--r--testing/marionette/harness/marionette_harness/www/testPageSource.xml5
-rw-r--r--testing/marionette/harness/marionette_harness/www/testPageSourceWithUnicodeChars.html11
-rw-r--r--testing/marionette/harness/marionette_harness/www/testSize.html9
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_accessibility.html57
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_columns.html31
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_cursor.html31
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_display_none.html10
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_iframe.html20
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_longtext.html9
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_multipleline.html24
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_multiplerange.html19
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_carets_selection.html38
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_clearing.html24
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_dynamic.html38
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_iframe.html16
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_inner_iframe.html13
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_nested_iframe.html13
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_oop_1.html15
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_oop_2.html15
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_shadow_dom.html26
-rw-r--r--testing/marionette/harness/marionette_harness/www/test_windows.html14
-rw-r--r--testing/marionette/harness/marionette_harness/www/white.pngbin150 -> 0 bytes
-rw-r--r--testing/marionette/harness/marionette_harness/www/windowHandles.html16
-rw-r--r--testing/marionette/harness/marionette_harness/www/xhtmlTest.html79
-rw-r--r--testing/marionette/harness/requirements.txt14
-rw-r--r--testing/marionette/harness/setup.py59
-rw-r--r--testing/marionette/interaction.js505
-rw-r--r--testing/marionette/jar.mn43
-rw-r--r--testing/marionette/l10n.js95
-rw-r--r--testing/marionette/legacyaction.js477
-rw-r--r--testing/marionette/listener.js1816
-rw-r--r--testing/marionette/logging.js75
-rw-r--r--testing/marionette/mach_commands.py81
-rw-r--r--testing/marionette/mach_test_package_commands.py67
-rw-r--r--testing/marionette/marionette.eslintrc.js8
-rw-r--r--testing/marionette/message.js285
-rw-r--r--testing/marionette/modal.js113
-rw-r--r--testing/marionette/moz.build13
-rw-r--r--testing/marionette/navigate.js119
-rw-r--r--testing/marionette/proxy.js376
-rw-r--r--testing/marionette/puppeteer/.flake83
-rw-r--r--testing/marionette/puppeteer/firefox/MANIFEST.in2
-rw-r--r--testing/marionette/puppeteer/firefox/docs/Makefile177
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/appinfo.rst15
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/keys.rst12
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/l10n.rst11
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/places.rst13
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/security.rst13
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/software_update.rst30
-rw-r--r--testing/marionette/puppeteer/firefox/docs/api/utils.rst12
-rw-r--r--testing/marionette/puppeteer/firefox/docs/conf.py270
-rw-r--r--testing/marionette/puppeteer/firefox/docs/index.rst85
-rw-r--r--testing/marionette/puppeteer/firefox/docs/make.bat242
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/about_window/window.rst59
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/browser/notifications.rst44
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/browser/tabbar.rst22
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/browser/toolbars.rst28
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/browser/window.rst11
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/deck.rst9
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/menu.rst10
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/pageinfo/window.rst30
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/update_wizard/dialog.rst128
-rw-r--r--testing/marionette/puppeteer/firefox/docs/ui/windows.rst16
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/__init__.py9
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/__init__.py0
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/appinfo.py45
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/keys.py17
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/l10n.py125
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/places.py150
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/security.py68
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py411
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/api/utils.py140
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/base.py14
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/decorators.py35
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/errors.py21
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/mixins.py101
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/puppeteer.py84
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/__init__.py0
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/__init__.py0
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py174
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py32
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/base.py54
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/__init__.py3
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py116
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py388
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py641
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py260
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/deck.py17
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/menu.py110
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/__init__.py0
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py204
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py61
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/__init__.py5
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py46
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py291
-rw-r--r--testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py435
-rw-r--r--testing/marionette/puppeteer/firefox/requirements-docs.txt5
-rw-r--r--testing/marionette/puppeteer/firefox/requirements.txt2
-rw-r--r--testing/marionette/puppeteer/firefox/setup.py36
-rw-r--r--testing/marionette/server.js144
-rw-r--r--testing/marionette/session.js457
-rw-r--r--testing/marionette/simpletest.js208
-rw-r--r--testing/marionette/test_action.js627
-rw-r--r--testing/marionette/test_assert.js126
-rw-r--r--testing/marionette/test_element.js55
-rw-r--r--testing/marionette/test_error.js431
-rw-r--r--testing/marionette/test_message.js204
-rw-r--r--testing/marionette/test_navigate.js67
-rw-r--r--testing/marionette/test_session.js370
-rw-r--r--testing/marionette/unit.ini16
456 files changed, 0 insertions, 60175 deletions
diff --git a/old-configure.in b/old-configure.in
index 0d617a2236..46a710f9f2 100644
--- a/old-configure.in
+++ b/old-configure.in
@@ -4540,12 +4540,6 @@ if test "$NECKO_COOKIES"; then
_NON_GLOBAL_ACDEFINES="$_NON_GLOBAL_ACDEFINES NECKO_COOKIES"
fi
-dnl
-dnl Always build Marionette
-dnl
-AC_DEFINE(ENABLE_MARIONETTE)
-AC_SUBST(ENABLE_MARIONETTE)
-
dnl ========================================================
dnl =
dnl = Miscellaneous (former toolkit/moz.configure)
diff --git a/testing/firefox-ui/.flake8 b/testing/firefox-ui/.flake8
deleted file mode 100644
index ad0819adf8..0000000000
--- a/testing/firefox-ui/.flake8
+++ /dev/null
@@ -1,3 +0,0 @@
-[flake8]
-max-line-length = 99
-exclude = __init__.py,
diff --git a/testing/firefox-ui/harness/MANIFEST.in b/testing/firefox-ui/harness/MANIFEST.in
deleted file mode 100644
index cf628b039c..0000000000
--- a/testing/firefox-ui/harness/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-exclude MANIFEST.in
-include requirements.txt
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/__init__.py
deleted file mode 100644
index 02ae10cdf4..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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/.
-
-__version__ = '1.4.0'
-
-import cli_functional
-import cli_update
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py
deleted file mode 100644
index 57dc77f607..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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_ui_harness.arguments.base import FirefoxUIArguments
-from firefox_ui_harness.arguments.update import UpdateArguments
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py b/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py
deleted file mode 100644
index e6427e764d..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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_harness import BaseMarionetteArguments
-
-
-class FirefoxUIBaseArguments(object):
- name = 'Firefox UI Tests'
- args = []
-
-
-class FirefoxUIArguments(BaseMarionetteArguments):
-
- def __init__(self, **kwargs):
- super(FirefoxUIArguments, self).__init__(**kwargs)
-
- self.register_argument_container(FirefoxUIBaseArguments())
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/arguments/update.py b/testing/firefox-ui/harness/firefox_ui_harness/arguments/update.py
deleted file mode 100644
index 9b6d3e5e01..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/arguments/update.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# 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 base import FirefoxUIArguments
-
-
-class UpdateBaseArguments(object):
- name = 'Firefox UI Update Tests'
- args = [
- [['--update-allow-mar-channel'], {
- 'dest': 'update_mar_channels',
- 'default': [],
- 'action': 'append',
- 'metavar': 'MAR_CHANNEL',
- 'help': 'Additional MAR channel to be allowed for updates, '
- 'e.g. "firefox-mozilla-beta" for updating a release '
- 'build to the latest beta build.'
- }],
- [['--update-channel'], {
- 'dest': 'update_channel',
- 'metavar': 'CHANNEL',
- 'help': 'Channel to use for the update check.'
- }],
- [['--update-direct-only'], {
- 'dest': 'update_direct_only',
- 'default': False,
- 'action': 'store_true',
- 'help': 'Only perform a direct update'
- }],
- [['--update-fallback-only'], {
- 'dest': 'update_fallback_only',
- 'default': False,
- 'action': 'store_true',
- 'help': 'Only perform a fallback update'
- }],
- [['--update-override-url'], {
- 'dest': 'update_override_url',
- 'metavar': 'URL',
- 'help': 'Force specified URL to use for update checks.'
- }],
- [['--update-target-version'], {
- 'dest': 'update_target_version',
- 'metavar': 'VERSION',
- 'help': 'Version of the updated build.'
- }],
- [['--update-target-buildid'], {
- 'dest': 'update_target_buildid',
- 'metavar': 'BUILD_ID',
- 'help': 'Build ID of the updated build.'
- }],
- ]
-
- def verify_usage_handler(self, args):
- if args.update_direct_only and args.update_fallback_only:
- raise ValueError('Arguments --update-direct-only and --update-fallback-only '
- 'are mutually exclusive.')
-
-
-class UpdateArguments(FirefoxUIArguments):
-
- def __init__(self, **kwargs):
- super(UpdateArguments, self).__init__(**kwargs)
-
- self.register_argument_container(UpdateBaseArguments())
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py b/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py
deleted file mode 100644
index e83d88b51e..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-# 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_harness.runtests import cli as mn_cli
-
-from firefox_ui_harness.arguments import FirefoxUIArguments
-from firefox_ui_harness.runners import FirefoxUITestRunner
-
-
-def cli(args=None):
- mn_cli(runner_class=FirefoxUITestRunner,
- parser_class=FirefoxUIArguments,
- args=args,
- )
-
-
-if __name__ == '__main__':
- cli()
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/cli_update.py b/testing/firefox-ui/harness/firefox_ui_harness/cli_update.py
deleted file mode 100644
index 27446a0998..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/cli_update.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-# 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_harness.runtests import cli as mn_cli
-
-from firefox_ui_harness.arguments import UpdateArguments
-from firefox_ui_harness.runners import UpdateTestRunner
-
-
-def cli(args=None):
- mn_cli(runner_class=UpdateTestRunner,
- parser_class=UpdateArguments,
- args=args,
- )
-
-
-if __name__ == '__main__':
- cli()
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py
deleted file mode 100644
index 9022a45b84..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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_ui_harness.runners.base import FirefoxUITestRunner
-from firefox_ui_harness.runners.update import UpdateTestRunner
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py b/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
deleted file mode 100644
index 66c2a53087..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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
-import shutil
-import tempfile
-
-import mozfile
-import mozinfo
-
-from marionette_harness import BaseMarionetteTestRunner, MarionetteTestCase
-
-
-class FirefoxUITestRunner(BaseMarionetteTestRunner):
-
- def __init__(self, **kwargs):
- super(FirefoxUITestRunner, self).__init__(**kwargs)
-
- # select the appropriate GeckoInstance
- self.app = 'fxdesktop'
-
- self.test_handlers = [MarionetteTestCase]
-
- def duplicate_application(self, application_folder):
- """Creates a copy of the specified binary."""
-
- if self.workspace:
- target_folder = os.path.join(self.workspace_path, 'application.copy')
- else:
- target_folder = tempfile.mkdtemp('.application.copy')
-
- self.logger.info('Creating a copy of the application at "%s".' % target_folder)
- mozfile.remove(target_folder)
- shutil.copytree(application_folder, target_folder)
-
- return target_folder
-
- def get_application_folder(self, binary):
- """Returns the directory of the application."""
- if mozinfo.isMac:
- end_index = binary.find('.app') + 4
- return binary[:end_index]
- else:
- return os.path.dirname(binary)
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/runners/update.py b/testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
deleted file mode 100644
index fe4936f68d..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# 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 sys
-
-import mozfile
-import mozinstall
-
-from firefox_ui_harness.runners import FirefoxUITestRunner
-from firefox_ui_harness.testcases import UpdateTestCase
-
-
-DEFAULT_PREFS = {
- # Bug 1355026: Re-enable when support for the new simplified UI update is available
- 'app.update.doorhanger': False,
- 'app.update.log': True,
- 'startup.homepage_override_url': 'about:blank',
-}
-
-
-class UpdateTestRunner(FirefoxUITestRunner):
-
- def __init__(self, **kwargs):
- super(UpdateTestRunner, self).__init__(**kwargs)
-
- self.original_bin = self.bin
-
- self.prefs.update(DEFAULT_PREFS)
-
- # In case of overriding the update URL, set the appropriate preference
- override_url = kwargs.pop('update_override_url', None)
- if override_url:
- self.prefs.update({'app.update.url.override': override_url})
-
- self.run_direct_update = not kwargs.pop('update_fallback_only', False)
- self.run_fallback_update = not kwargs.pop('update_direct_only', False)
-
- self.test_handlers = [UpdateTestCase]
-
- def run_tests(self, tests):
- # Used to store the last occurred exception because we execute
- # run_tests() multiple times
- self.exc_info = None
-
- failed = 0
- source_folder = self.get_application_folder(self.original_bin)
-
- results = {}
-
- def _run_tests(tags):
- application_folder = None
-
- try:
- # Backup current tags
- test_tags = self.test_tags
-
- application_folder = self.duplicate_application(source_folder)
- self.bin = mozinstall.get_binary(application_folder, 'Firefox')
-
- self.test_tags = tags
- super(UpdateTestRunner, self).run_tests(tests)
-
- except Exception:
- self.exc_info = sys.exc_info()
- self.logger.error('Failure during execution of the update test.',
- exc_info=self.exc_info)
-
- finally:
- self.test_tags = test_tags
-
- self.logger.info('Removing copy of the application at "%s"' % application_folder)
- try:
- mozfile.remove(application_folder)
- except IOError as e:
- self.logger.error('Cannot remove copy of application: "%s"' % str(e))
-
- # Run direct update tests if wanted
- if self.run_direct_update:
- _run_tests(tags=['direct'])
- failed += self.failed
- results['Direct'] = False if self.failed else True
-
- # Run fallback update tests if wanted
- if self.run_fallback_update:
- _run_tests(tags=['fallback'])
- failed += self.failed
- results['Fallback'] = False if self.failed else True
-
- self.logger.info("Summary of update tests:")
- for test_type, result in results.iteritems():
- self.logger.info("\t%s update test ran and %s" %
- (test_type, 'PASSED' if result else 'FAILED'))
-
- # Combine failed tests for all run_test() executions
- self.failed = failed
-
- # If exceptions happened, re-throw the last one
- if self.exc_info:
- ex_type, exception, tb = self.exc_info
- raise ex_type, exception, tb
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/testcases.py b/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
deleted file mode 100644
index abcbd65550..0000000000
--- a/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
+++ /dev/null
@@ -1,420 +0,0 @@
-# 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
-import pprint
-from datetime import datetime
-
-import mozfile
-
-from firefox_puppeteer import PuppeteerMixin
-from firefox_puppeteer.api.software_update import SoftwareUpdate
-from firefox_puppeteer.ui.update_wizard import UpdateWizardDialog
-from marionette_driver import Wait
-from marionette_driver.errors import NoSuchWindowException
-from marionette_harness import MarionetteTestCase
-
-
-class UpdateTestCase(PuppeteerMixin, MarionetteTestCase):
-
- TIMEOUT_UPDATE_APPLY = 300
- TIMEOUT_UPDATE_CHECK = 30
- TIMEOUT_UPDATE_DOWNLOAD = 720
-
- # 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):
- super(UpdateTestCase, self).__init__(*args, **kwargs)
-
- self.update_channel = kwargs.pop('update_channel')
- self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
-
- self.target_buildid = kwargs.pop('update_target_buildid')
- self.target_version = kwargs.pop('update_target_version')
-
- def setUp(self, is_fallback=False):
- super(UpdateTestCase, self).setUp()
-
- self.software_update = SoftwareUpdate(self.marionette)
- self.download_duration = None
-
- # If a custom update channel has to be set, force a restart of
- # Firefox to actually get it applied as a default pref. Use the clean
- # option to force a non in_app restart, which would allow Firefox to
- # dump the logs to the console.
- if self.update_channel:
- self.software_update.update_channel = self.update_channel
- self.restart(clean=True)
-
- self.assertEqual(self.software_update.update_channel, self.update_channel)
-
- # If requested modify the list of allowed MAR channels
- if self.update_mar_channels:
- self.software_update.mar_channels.add_channels(self.update_mar_channels)
-
- self.assertTrue(self.update_mar_channels.issubset(
- self.software_update.mar_channels.channels),
- 'Allowed MAR channels have been set: expected "{}" in "{}"'.format(
- ', '.join(self.update_mar_channels),
- ', '.join(self.software_update.mar_channels.channels)))
-
- # Ensure that there exists no already partially downloaded update
- self.remove_downloaded_update()
-
- # Dictionary which holds the information for each update
- self.update_status = {
- 'build_pre': self.software_update.build_info,
- 'build_post': None,
- 'fallback': is_fallback,
- 'patch': {},
- 'success': False,
- }
-
- # Check if the user has permissions to run the update
- self.assertTrue(self.software_update.allowed,
- 'Current user has permissions to update the application.')
-
- def tearDown(self):
- try:
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.selected_tab])
-
- # Add content of the update log file for detailed failures when applying an update
- self.update_status['update_log'] = self.read_update_log()
-
- # Print results for now until we have treeherder integration
- output = pprint.pformat(self.update_status)
- self.logger.info('Update test results: \n{}'.format(output))
- finally:
- super(UpdateTestCase, self).tearDown()
-
- # Ensure that no trace of an partially downloaded update remain
- self.remove_downloaded_update()
-
- @property
- def patch_info(self):
- """ Returns information about the active update in the queue.
-
- :returns: A dictionary with information about the active patch
- """
- patch = self.software_update.patch_info
- patch['download_duration'] = self.download_duration
-
- return patch
-
- def check_for_updates(self, about_window, timeout=TIMEOUT_UPDATE_CHECK):
- """Clicks on "Check for Updates" button, and waits for check to complete.
-
- :param about_window: Instance of :class:`AboutWindow`.
- :param timeout: How long to wait for the update check to finish. Optional,
- defaults to 60s.
-
- :returns: True, if an update is available.
- """
- self.assertEqual(about_window.deck.selected_panel,
- about_window.deck.check_for_updates)
-
- about_window.deck.check_for_updates.button.click()
- Wait(self.marionette, timeout=self.TIMEOUT_UPDATE_CHECK).until(
- lambda _: about_window.deck.selected_panel not in
- (about_window.deck.check_for_updates, about_window.deck.checking_for_updates),
- message='Check for updates has been finished.')
-
- return about_window.deck.selected_panel != about_window.deck.no_updates_found
-
- def check_update_applied(self):
- """Check that the update has been applied correctly"""
- self.update_status['build_post'] = self.software_update.build_info
-
- # Ensure that the target version is the same or higher. No downgrade
- # should have happened.
- version_check = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- return Services.vc.compare(arguments[0], arguments[1]);
- """, script_args=(self.update_status['build_post']['version'],
- self.update_status['build_pre']['version']))
-
- self.assertGreaterEqual(version_check, 0,
- 'A downgrade from version {} to {} is not allowed'.format(
- self.update_status['build_pre']['version'],
- self.update_status['build_post']['version']))
-
- self.assertNotEqual(self.update_status['build_post']['buildid'],
- self.update_status['build_pre']['buildid'],
- 'The staged update to buildid {} has not been applied'.format(
- self.update_status['patch']['buildid']))
-
- self.assertEqual(self.update_status['build_post']['buildid'],
- self.update_status['patch']['buildid'],
- 'Unexpected target buildid after applying the patch, {} != {}'.format(
- self.update_status['build_post']['buildid'],
- self.update_status['patch']['buildid']))
-
- self.assertEqual(self.update_status['build_post']['locale'],
- self.update_status['build_pre']['locale'],
- 'Unexpected change of the locale from {} to {}'.format(
- self.update_status['build_pre']['locale'],
- self.update_status['build_post']['locale']))
-
- self.assertEqual(self.update_status['build_post']['disabled_addons'],
- self.update_status['build_pre']['disabled_addons'],
- 'Application-wide addons have been unexpectedly disabled: {}'.format(
- ', '.join(set(self.update_status['build_pre']['locale']) -
- set(self.update_status['build_post']['locale']))
- ))
-
- if self.target_version:
- self.assertEqual(self.update_status['build_post']['version'],
- self.target_version,
- 'Current target version {} does not match expected version {}'.format(
- self.update_status['build_post']['version'], self.target_version))
-
- if self.target_buildid:
- self.assertEqual(self.update_status['build_post']['buildid'],
- self.target_buildid,
- 'Current target buildid {} does not match expected buildid {}'.format(
- self.update_status['build_post']['buildid'], self.target_buildid))
-
- self.update_status['success'] = True
-
- def check_update_not_applied(self):
- """Check that the update has not been applied due to a forced invalidation of the patch"""
- build_info = self.software_update.build_info
-
- # Ensure that the version has not been changed
- version_check = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- return Services.vc.compare(arguments[0], arguments[1]);
- """, script_args=(build_info['version'],
- self.update_status['build_pre']['version']))
-
- self.assertEqual(version_check, 0,
- 'An update from version {} to {} has been unexpectedly applied'.format(
- self.update_status['build_pre']['version'],
- build_info['version']))
-
- # Check that the build id of the source build and the current build are identical
- self.assertEqual(build_info['buildid'],
- self.update_status['build_pre']['buildid'],
- 'The build id has been unexpectedly changed from {} to {}'.format(
- self.update_status['build_pre']['buildid'], build_info['buildid']))
-
- def download_update(self, window, wait_for_finish=True, timeout=TIMEOUT_UPDATE_DOWNLOAD):
- """ Download the update patch.
-
- :param window: Instance of :class:`AboutWindow` or :class:`UpdateWizardDialog`.
- :param wait_for_finish: If True the function has to wait for the download to be finished.
- Optional, default to `True`.
- :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`.
- """
- self.marionette.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()
-
- # If incompatible add-on are installed, skip over the wizard page
- # TODO: Remove once we no longer support version Firefox 45.0ESR
- if self.puppeteer.utils.compare_version(self.puppeteer.appinfo.version,
- '49.0a1') == -1:
- if dialog.wizard.selected_panel == dialog.wizard.incompatible_list:
- dialog.select_next_page()
-
- # Updates were stored in the cache, so no download is necessary
- if dialog.wizard.selected_panel in [dialog.wizard.finished,
- dialog.wizard.finished_background,
- ]:
- pass
-
- # Download the update
- elif dialog.wizard.selected_panel == dialog.wizard.downloading:
- if wait_for_finish:
- start_time = datetime.now()
- self.wait_for_download_finished(dialog, timeout)
- self.download_duration = (datetime.now() - start_time).total_seconds()
-
- Wait(self.marionette).until(lambda _: (
- dialog.wizard.selected_panel in [dialog.wizard.finished,
- dialog.wizard.finished_background,
- ]),
- message='Final wizard page has been selected.')
-
- else:
- raise Exception('Invalid wizard page for downloading an update: {}'.format(
- dialog.wizard.selected_panel))
-
- finally:
- self.marionette.clear_pref(self.PREF_APP_UPDATE_ALTWINDOWTYPE)
-
- # The old update wizard dialog has to be handled differently. It's necessary
- # for fallback updates and invalid add-on versions.
- if isinstance(window, UpdateWizardDialog):
- download_via_update_wizard(window)
- return
-
- if window.deck.selected_panel == window.deck.download_and_install:
- window.deck.download_and_install.button.click()
-
- # Wait for the download to start
- Wait(self.marionette).until(lambda _: (
- window.deck.selected_panel != window.deck.download_and_install),
- message='Download of the update has been started.')
-
- if wait_for_finish:
- start_time = datetime.now()
- self.wait_for_download_finished(window, timeout)
- self.download_duration = (datetime.now() - start_time).total_seconds()
-
- def download_and_apply_available_update(self, force_fallback=False):
- """Checks, downloads, and applies an available update.
-
- :param force_fallback: Optional, if `True` invalidate current update status.
- Defaults to `False`.
- """
- # Open the about window and check for updates
- about_window = self.browser.open_about_window()
-
- try:
- update_available = self.check_for_updates(about_window)
- self.assertTrue(update_available,
- "Available update has been found")
-
- # Download update and wait until it has been applied
- self.download_update(about_window)
- self.wait_for_update_applied(about_window)
-
- finally:
- self.update_status['patch'] = self.patch_info
-
- if force_fallback:
- # Set the downloaded update into failed state
- self.software_update.force_fallback()
-
- # Restart Firefox to apply the downloaded update
- self.restart()
-
- def download_and_apply_forced_update(self):
- self.check_update_not_applied()
-
- # The update wizard dialog opens automatically after the restart but with a short delay
- dialog = Wait(self.marionette, ignored_exceptions=[NoSuchWindowException]).until(
- lambda _: self.puppeteer.windows.switch_to(lambda win: type(win) is UpdateWizardDialog)
- )
-
- # In case of a broken complete update the about window has to be used
- if self.update_status['patch']['is_complete']:
- about_window = None
- try:
- self.assertEqual(dialog.wizard.selected_panel,
- dialog.wizard.error)
- dialog.close()
-
- # Open the about window and check for updates
- about_window = self.browser.open_about_window()
- update_available = self.check_for_updates(about_window)
- self.assertTrue(update_available,
- 'Available update has been found')
-
- # Download update and wait until it has been applied
- self.download_update(about_window)
- self.wait_for_update_applied(about_window)
-
- finally:
- if about_window:
- self.update_status['patch'] = self.patch_info
-
- else:
- try:
- self.assertEqual(dialog.wizard.selected_panel,
- dialog.wizard.error_patching)
-
- # Start downloading the fallback update
- self.download_update(dialog)
-
- finally:
- self.update_status['patch'] = self.patch_info
-
- # Restart Firefox to apply the update
- self.restart()
-
- def read_update_log(self):
- """Read the content of the update log file for the last update attempt."""
- path = os.path.join(os.path.dirname(self.software_update.staging_directory),
- 'last-update.log')
- try:
- with open(path, 'rb') as f:
- return f.read().splitlines()
- except IOError as exc:
- self.logger.warning(str(exc))
- return None
-
- def remove_downloaded_update(self):
- """Remove an already downloaded update from the update staging directory.
-
- Hereby not only remove the update subdir but everything below 'updates'.
- """
- path = os.path.dirname(self.software_update.staging_directory)
- self.logger.info('Clean-up update staging directory: {}'.format(path))
- mozfile.remove(path)
-
- def wait_for_download_finished(self, window, timeout=TIMEOUT_UPDATE_DOWNLOAD):
- """ Waits until download is completed.
-
- :param window: Instance of :class:`AboutWindow` or :class:`UpdateWizardDialog`.
- :param timeout: How long to wait for the download to finish. Optional,
- default to 360 seconds.
- """
- # The old update wizard dialog has to be handled differently. It's necessary
- # for fallback updates and invalid add-on versions.
- if isinstance(window, UpdateWizardDialog):
- Wait(self.marionette, timeout=timeout).until(
- lambda _: window.wizard.selected_panel != window.wizard.downloading,
- message='Download has been completed.')
-
- self.assertNotIn(window.wizard.selected_panel,
- [window.wizard.error, window.wizard.error_extra])
- return
-
- Wait(self.marionette, timeout=timeout).until(
- lambda _: window.deck.selected_panel not in
- (window.deck.download_and_install, window.deck.downloading),
- message='Download has been completed.')
-
- self.assertNotEqual(window.deck.selected_panel,
- window.deck.download_failed)
-
- def wait_for_update_applied(self, about_window, timeout=TIMEOUT_UPDATE_APPLY):
- """ Waits until the downloaded update has been applied.
-
- :param about_window: Instance of :class:`AboutWindow`.
- :param timeout: How long to wait for the update to apply. Optional,
- default to 300 seconds
- """
- Wait(self.marionette, timeout=timeout).until(
- lambda _: about_window.deck.selected_panel == about_window.deck.apply,
- message='Final wizard page has been selected.')
-
- # Wait for update to be staged because for update tests we modify the update
- # status file to enforce the fallback update. If we modify the file before
- # Firefox does, Firefox will override our change and we will have no fallback update.
- Wait(self.marionette, timeout=timeout).until(
- lambda _: 'applied' in self.software_update.active_update.state,
- message='Update has been applied.')
diff --git a/testing/firefox-ui/harness/requirements.txt b/testing/firefox-ui/harness/requirements.txt
deleted file mode 100644
index 54114debb9..0000000000
--- a/testing/firefox-ui/harness/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-firefox-puppeteer >= 52.1.0, <53.0.0
-marionette-harness >= 4.0.0
-mozfile >= 1.2
-mozinfo >= 0.8
-mozinstall >= 1.12
diff --git a/testing/firefox-ui/harness/setup.py b/testing/firefox-ui/harness/setup.py
deleted file mode 100644
index 1799d50578..0000000000
--- a/testing/firefox-ui/harness/setup.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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
-import re
-from setuptools import setup, find_packages
-
-THIS_DIR = os.path.dirname(os.path.realpath(__name__))
-
-
-def read(*parts):
- with open(os.path.join(THIS_DIR, *parts)) as f:
- return f.read()
-
-
-def get_version():
- return re.findall("__version__ = '([\d\.]+)'",
- read('firefox_ui_harness', '__init__.py'), re.M)[0]
-
-long_description = """Custom Marionette runner classes and entry scripts for Firefox Desktop
-specific Marionette tests.
-"""
-
-setup(name='firefox-ui-harness',
- version=get_version(),
- description="Firefox UI Harness",
- long_description=long_description,
- classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
- keywords='mozilla',
- author='Auto-tools',
- author_email='tools-marionette@lists.mozilla.org',
- url='https://wiki.mozilla.org/Auto-tools/Projects/Marionette/Harnesses/FirefoxUI',
- license='MPL',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=read('requirements.txt').splitlines(),
- entry_points="""
- [console_scripts]
- firefox-ui-functional = firefox_ui_harness.cli_functional:cli
- firefox-ui-update = firefox_ui_harness.cli_update:cli
- """,
- )
diff --git a/testing/firefox-ui/mach_commands.py b/testing/firefox-ui/mach_commands.py
deleted file mode 100644
index 368b673a22..0000000000
--- a/testing/firefox-ui/mach_commands.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# 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 __future__ import absolute_import, unicode_literals
-
-import os
-import sys
-
-from mozbuild.base import (
- MachCommandBase,
- MachCommandConditions as conditions,
-)
-
-from mach.decorators import (
- Command,
- CommandProvider,
-)
-
-
-def setup_argument_parser_functional():
- from firefox_ui_harness.arguments.base import FirefoxUIArguments
- from mozlog.structured import commandline
- parser = FirefoxUIArguments()
- commandline.add_logging_group(parser)
- return parser
-
-
-def setup_argument_parser_update():
- from firefox_ui_harness.arguments.update import UpdateArguments
- from mozlog.structured import commandline
- parser = UpdateArguments()
- commandline.add_logging_group(parser)
- return parser
-
-
-def run_firefox_ui_test(testtype=None, topsrcdir=None, **kwargs):
- from mozlog.structured import commandline
- from argparse import Namespace
- import firefox_ui_harness
-
- if testtype == 'functional':
- parser = setup_argument_parser_functional()
- else:
- parser = setup_argument_parser_update()
-
- test_types = {
- 'functional': {
- 'default_tests': [
- os.path.join('puppeteer', 'manifest.ini'),
- os.path.join('functional', 'manifest.ini'),
- ],
- 'cli_module': firefox_ui_harness.cli_functional,
- },
- 'update': {
- 'default_tests': [
- os.path.join('update', 'manifest.ini'),
- ],
- 'cli_module': firefox_ui_harness.cli_update,
- }
- }
-
- fxui_dir = os.path.join(topsrcdir, 'testing', 'firefox-ui')
-
- # Set the resources path which is used to serve test data via wptserve
- if not kwargs['server_root']:
- kwargs['server_root'] = os.path.join(fxui_dir, 'resources')
-
- # If called via "mach test" a dictionary of tests is passed in
- if 'test_objects' in kwargs:
- tests = []
- for obj in kwargs['test_objects']:
- tests.append(obj['file_relpath'])
- kwargs['tests'] = tests
- elif not kwargs.get('tests'):
- # If no tests have been selected, set default ones
- kwargs['tests'] = [os.path.join(fxui_dir, 'tests', test)
- for test in test_types[testtype]['default_tests']]
-
- kwargs['logger'] = commandline.setup_logging('Firefox UI - {} Tests'.format(testtype),
- {"mach": sys.stdout})
-
- args = Namespace()
-
- for k, v in kwargs.iteritems():
- setattr(args, k, v)
-
- parser.verify_usage(args)
-
- failed = test_types[testtype]['cli_module'].cli(args=vars(args))
-
- if failed > 0:
- return 1
- else:
- return 0
-
-
-@CommandProvider
-class MachCommands(MachCommandBase):
- """Mach command provider for Firefox ui tests."""
-
- @Command('firefox-ui-functional', category='testing',
- conditions=[conditions.is_firefox],
- description='Run the functional test suite of Firefox UI tests.',
- parser=setup_argument_parser_functional,
- )
- def run_firefox_ui_functional(self, **kwargs):
- kwargs['binary'] = kwargs['binary'] or self.get_binary_path('app')
- return run_firefox_ui_test(testtype='functional',
- topsrcdir=self.topsrcdir, **kwargs)
-
- @Command('firefox-ui-update', category='testing',
- conditions=[conditions.is_firefox],
- description='Run the update test suite of Firefox UI tests.',
- parser=setup_argument_parser_update,
- )
- def run_firefox_ui_update(self, **kwargs):
- kwargs['binary'] = kwargs['binary'] or self.get_binary_path('app')
- return run_firefox_ui_test(testtype='update',
- topsrcdir=self.topsrcdir, **kwargs)
diff --git a/testing/firefox-ui/moz.build b/testing/firefox-ui/moz.build
deleted file mode 100644
index dd7311c038..0000000000
--- a/testing/firefox-ui/moz.build
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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/.
-
-FIREFOX_UI_FUNCTIONAL_MANIFESTS += ["tests/functional/manifest.ini"]
-FIREFOX_UI_UPDATE_MANIFESTS += ["tests/update/manifest.ini"]
-# TODO: Move to testing/marionette/puppeteer/firefox
-PUPPETEER_FIREFOX_MANIFESTS += ["tests/puppeteer/manifest.ini"]
-
-with Files("**"):
- BUG_COMPONENT = ("Testing", "Firefox UI Tests")
diff --git a/testing/firefox-ui/resources/addons/extensions/restartless_addon_signed.xpi b/testing/firefox-ui/resources/addons/extensions/restartless_addon_signed.xpi
deleted file mode 100644
index ed86213e79..0000000000
--- a/testing/firefox-ui/resources/addons/extensions/restartless_addon_signed.xpi
+++ /dev/null
Binary files differ
diff --git a/testing/firefox-ui/resources/addons/extensions/restartless_addon_unsigned.xpi b/testing/firefox-ui/resources/addons/extensions/restartless_addon_unsigned.xpi
deleted file mode 100644
index d0768103d5..0000000000
--- a/testing/firefox-ui/resources/addons/extensions/restartless_addon_unsigned.xpi
+++ /dev/null
Binary files differ
diff --git a/testing/firefox-ui/resources/cookies/cookie_single.html b/testing/firefox-ui/resources/cookies/cookie_single.html
deleted file mode 100644
index d4a02b45b8..0000000000
--- a/testing/firefox-ui/resources/cookies/cookie_single.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
-<script type="text/javascript">
- function setCookie()
- {
- var date = new Date();
- date.setDate(new Date().getDate() + 36);
- document.cookie = "litmus_1=true;expires=" + date.toGMTString();
- }
-</script>
-</head>
-
-<body onload="setCookie()">
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/images/firefox_favicon.ico b/testing/firefox-ui/resources/images/firefox_favicon.ico
deleted file mode 100644
index 2c2f81768d..0000000000
--- a/testing/firefox-ui/resources/images/firefox_favicon.ico
+++ /dev/null
Binary files differ
diff --git a/testing/firefox-ui/resources/images/mozilla_favicon.ico b/testing/firefox-ui/resources/images/mozilla_favicon.ico
deleted file mode 100644
index d44438903b..0000000000
--- a/testing/firefox-ui/resources/images/mozilla_favicon.ico
+++ /dev/null
Binary files differ
diff --git a/testing/firefox-ui/resources/images/mozilla_logo.jpg b/testing/firefox-ui/resources/images/mozilla_logo.jpg
deleted file mode 100644
index 231b385ee4..0000000000
--- a/testing/firefox-ui/resources/images/mozilla_logo.jpg
+++ /dev/null
Binary files differ
diff --git a/testing/firefox-ui/resources/layout/mozilla.html b/testing/firefox-ui/resources/layout/mozilla.html
deleted file mode 100644
index 9224533bf0..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla</title>
- <link rel="shortcut icon" type="image/ico" href="../images/mozilla_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#community">Community</a> |
- <a href="#project">Project</a> |
- <a href="#organization">Organization</a>
-
- <div id="content">
- <h1 id="page-title">
- <strong>We believe</strong> that the internet should be public,
- open and accessible.
- </h1>
-
- <h2><a name="community">Community</a></h2>
- <p id="community">
- We're a global community of thousands who believe in the power
- of technology to enrich people's lives.
- <a href="mozilla_community.html">More</a>
- </p>
-
- <h2><a name="project">Project</a></h2>
- <p id="project">
- We're an open source project whose code is used for some of the
- Internet's most innovative applications.
- <a href="mozilla_projects.html">More</a>
- </p>
-
- <h2><a name="organization">Organization</a></h2>
- <p id="organization">
- We're a public benefit organization dedicated to making the
- Internet better for everyone.
- <a href="mozilla_mission.html">More</a>
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_community.html b/testing/firefox-ui/resources/layout/mozilla_community.html
deleted file mode 100644
index c8da6afd84..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_community.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Community</title>
- <link rel="shortcut icon" type="image/ico" href="../images/seamonkey_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#history">History</a> |
- <a href="#communicate">Communicate</a> |
- <a href="#more">More</a>
-
- <div id="content">
- <h1 id="page-title" name="page-title">Our Community</h1>
-
- <h2><a name="history">History</a></h2>
- <p id="history">
- When www.mozilla.org was launched in 1998 all community activity
- occurred right here on this site. Since then the community has
- grown much bigger and there are now many different sites,
- forums, blogs and newsgroups in different places that track
- different parts of the project. These pages aim to be a
- comprehensive list to all of the different community resources
- available. If you know of something that's not on these lists
- that should be, please contact us and we'll update these
- pages.
- </p>
-
- <h2><a name="communicate">Communicate</a></h2>
- <p id="communicate">
- There are a number of different ways community members
- communicate and coordinate (people use mailing lists and
- newsgroups, blogs, forums, wikis and they even meet in real
- life sometimes too) and all of these options might be
- overwhelming at first. Hopefully this set of links will provide
- some useful pointers to help you figure out where to go to find
- what you're looking for. If you do get lost though and need
- some help, feel free to ask for more information.
- </p>
-
- <h2><a name="more">More</a></h2>
- <p id="more">
- Please note that this is intended to be an entry point that
- provides a high-level overview of the different community areas.
- If you're looking for more detailed information about a specific
- topic, please look at our Developer,
- <a href="mozilla_contribute.html">Contribute</a> and Support
- pages or take a look at the other information referenced
- throughout this site.
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_contribute.html b/testing/firefox-ui/resources/layout/mozilla_contribute.html
deleted file mode 100644
index cf5e54b85f..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_contribute.html
+++ /dev/null
@@ -1,70 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Contribute</title>
- <link rel="shortcut icon" type="image/ico" href="../images/thunderbird_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#summary">Summary</a> |
- <a href="#contribute">Contribute</a>
-
- <div id="content">
- <h1 id="page-title">Get Involved</h1>
-
- <h2><a name="summary">Summary</a></h2>
- <p id="summary">
- You can <a href="mozilla_mission.html">build a better Internet</a>
- by getting involved with Mozilla. You don't have to be a C++
- guru (or even know what that means!) and you don't need to spend
- lots of time. Take a look at the opportunities below and feel
- free to ask if you have any questions.
- </p>
-
- <h2><a name="contribute">Contribute</a></h2>
- <p id="contribute">
- <h3>Area of Interest</h3>
- <i>Browse contribution opportunities by area of interest.</i>
-
- <ul id="areas_of_interest">
- <li id="browser_choice">
- <h4>Web Browser Choice</h4>
- <p>
- Mozilla has always believed that the freedom to
- make informed choices should be central to making
- the Web, and the world, a better place. Tell us
- why having a choice of browser is important to you
- and help us spread the word about how others can
- take control of their online lives.
- </p>
- </li>
- <li id="helping_users">
- <h4>Helping Users</h4>
- <p>
- Interested in helping others get the most out of
- using Firefox and other Mozilla projects? Our
- support process relies on enthusiastic
- contributors like you. Find out more about
- supporting Firefox, Thunderbird and other Mozilla
- projects.
- </p>
- </li>
- <li id="localization">
- <h4>Localization</h4>
- <p>
- Get involved with Mozilla by making Firefox,
- Thunderbird and other projects available in your
- language. Also help us tell the world about how
- Mozilla is building a better Internet by
- translating content on our web sites.
- </p>
- </li>
- </ul>
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_governance.html b/testing/firefox-ui/resources/layout/mozilla_governance.html
deleted file mode 100644
index 8e25aaabde..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_governance.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Governance</title>
- <link rel="shortcut icon" type="image/ico" href="../images/firefox_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#summary">Summary</a> |
- <a href="#more">More</a>
-
- <div id="content">
- <h1 id="page-title">Governance</h1>
-
- <h2><a name="summary">Summary</a></h2>
- <p id="summary">
- Mozilla is an open source project governed as a meritocracy. Our
- community is structured as a virtual organization where
- authority is distributed to both volunteer and employed
- community members as they show their abilities through
- contributions to the project.
- </p>
-
- <h2><a name="more">More</a></h2>
- <p id="more">
- <ul id="list">
- <li id="roles">Roles and Responsibilities</li>
- <li id="policies">Policies</li>
- <li id="discussion">Discussion</li>
- </ul>
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_grants.html b/testing/firefox-ui/resources/layout/mozilla_grants.html
deleted file mode 100644
index c8935c4fb5..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_grants.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Grants</title>
- <link rel="shortcut icon" type="image/ico" href="../images/mozilla_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#summary">Summary</a> |
- <a href="#goals">Goals</a>
-
- <div id="content">
- <h1 id="page-title">Mozilla Grants</h1>
-
- <h2><a name="summary">Summary</a></h2>
- <p id="summary">
- Since 2006, Mozilla has awarded over two million dollars to fund
- projects that contribute to the health of the Open Web. The
- Mozilla Grants program is jointly funded by the Mozilla
- Corporation and the Mozilla Foundation, and awards financial
- support to individuals and organizations whose work supports and
- enhances the mission and values of the Mozilla Project.
- </p>
-
- <h2><a name="goals">Goals</a></h2>
- <p id="goals">
- Mozilla makes grants to individuals and organizations all over
- the world. We mainly fund activity that supports the Mozilla
- Grants program's four target areas:
-
- <ul id="goal_list">
- <li id="accessibility">
- <strong>Accessibility:</strong> Mozilla believes that
- the Internet truly is for everyone, and that those with
- disabilities should be able to participate on the Web
- along with their sighted and hearing peers. As part of
- our accessibility strategy, we are funding the
- development of free, open source options for those with
- visual and auditory impairments.
- </li>
-
- <li id="community">
- <strong>Community:</strong> Mozilla offers suppport to
- the broader free culture and open source community, as
- part of Mozilla's general effort to 'give back', aiding
- in the creation of technologies and projects that
- increase the health of the open Web ecosystem.
- </li>
-
- <li id="education">
- <strong>Education:</strong> As part of Mozilla's broader
- education initiative, we support educational
- institutions that are producing the next generation of
- innovative creators of software.
- </li>
-
- <li id="open_source">
- <strong>Open Source:</strong> These grants support the
- creation and adoption of Web standards, open source
- principles, and the overall principles of transparency,
- collaboration, and openness that free and open source
- software projects adhere to.
- </li>
- </ul>
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_mission.html b/testing/firefox-ui/resources/layout/mozilla_mission.html
deleted file mode 100644
index c9ed2bd850..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_mission.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Mission</title>
- <link rel="shortcut icon" type="image/ico" href="../images/seamonkey_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#mission">Mission</a> |
- <a href="#organization">Organization</a> |
- <a href="#goal">Goal</a>
-
- <div id="content" name="content">
- <h1 id="page-title" name="page-title">Mission</h1>
-
- <h2><a name="mission">Mission</a></h2>
- <p id="mission_statement">
- Mozilla's mission is to <strong>promote openness, innovation,
- and opportunity on the web</strong>. We do this by creating
- great software, like the Firefox browser, and building
- movements, like Drumbeat, that give people tools to take control
- of their online lives.
- </p>
-
- <h2><a name="organization">Organization</a></h2>
- <p id="organization">
- As a non-profit organization, we define success in terms of
- building communities and enriching people's lives instead of
- benefiting our shareholders (guess what: we don't even have
- shareholders). We believe in the power and potential of the
- Internet and want to see it thrive for everyone, everywhere.
- </p>
-
- <h2><a name="goal">Goal</a></h2>
- <p id="goal">
- <strong>
- Building a better Internet is an ambitious goal, but we
- believe that it is possible
- </strong>
- when people who share our passion get involved. Coders, artists,
- writers, testers, surfers, students, grandparents; anyone who
- uses and cares about the web can help make it even better.
- <a href="mozilla_contribute.html">Find out how you can help</a>.
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_organizations.html b/testing/firefox-ui/resources/layout/mozilla_organizations.html
deleted file mode 100644
index 9d2ae9ff08..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_organizations.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Organizations</title>
- <link rel="shortcut icon" type="image/ico" href="../images/thunderbird_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#summary">Summary</a> |
- <a href="#organization">Organization</a>
-
- <div id="content">
- <h1 id="page-title">Mozilla Organizations</h1>
-
- <h2><a name="summary">Summary</a></h2>
- <p id="summary">
- Mozilla is a global community of people creating a better
- Internet. We build public benefit into the Internet by creating
- free, open source products and technologies that improve the
- online experience for people everywhere.
- </p>
-
- <h2><a name="organization">Organization</a></h2>
- <p id="organization">
- There are several organizations that support the Mozilla
- community and Mozilla's principles. They include the non-profit
- Mozilla Foundation as well as two wholly owned taxable
- subsidiaries, the Mozilla Corporation and Mozilla Messaging.
- Mozilla considers itself a hybrid organization, combining non-
- profit and market strategies to ensure the Internet remains a
- shared public resource.
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/layout/mozilla_projects.html b/testing/firefox-ui/resources/layout/mozilla_projects.html
deleted file mode 100644
index a4ec7c8409..0000000000
--- a/testing/firefox-ui/resources/layout/mozilla_projects.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <title>Mozilla Projects</title>
- <link rel="shortcut icon" type="image/ico" href="../images/firefox_favicon.ico" />
-</head>
-
-<body>
- <a href="mozilla.html">
- <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
- </a>
-
- <a href="#summary">Summary</a> |
- <a href="#applications">Applications</a>
-
- <div id="content">
- <h1 id="page-title">Our Projects</h1>
-
- <h2><a name="summary">Summary</a></h2>
- <p id="summary">
- The Mozilla community produces a lot of great software and acts
- as an incubator for innovative ideas as a way to advance our
- <a href="mozilla_mission.html">mission</a> of building a better
- Internet.
- </p>
-
- <h2><a name="applications">Applications</a></h2>
- <p id="applications">
- <p>
- These applications are developed by the Mozilla community
- and their code is hosted on mozilla.org.
- </p>
-
- <ul id="product_list">
- <li id="bugzilla">
- <h3><strong>Bugzilla</strong></h3>
- Bugzilla is a bug tracking system designed to help teams
- manage software development. Hundreds of organizations
- across the globe are using this powerful tool to get
- organized and communicate effectively.
- </li>
-
- <li id="camino">
- <h3><strong>Camino</strong></h3>
- Camino is a Web browser optimized for Mac OS X with a
- Cocoa user interface, and powerful Gecko layout engine.
- It's the simple, secure, and fast browser for Mac OS X.
- </li>
-
- <li id="firefox">
- <h3><strong>Firefox for Desktop</strong></h3>
- The award-winning Firefox Web browser has security,
- speed and new features that will change the way you use
- the Web. Don’t settle for anything less.
- </li>
- </ul>
- </p>
- </div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/private_browsing/about.html b/testing/firefox-ui/resources/private_browsing/about.html
deleted file mode 100644
index 30b211be69..0000000000
--- a/testing/firefox-ui/resources/private_browsing/about.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-</head>
-
-<body>
- <div id="about_pb">About Private Browsing</div>
-</body>
-</html>
diff --git a/testing/firefox-ui/resources/security/enable_privilege.html b/testing/firefox-ui/resources/security/enable_privilege.html
deleted file mode 100644
index 9d18e46848..0000000000
--- a/testing/firefox-ui/resources/security/enable_privilege.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
- <head>
- <title>Test page for enablePrivilege</title>
- <script>
- function init() {
- var result = document.getElementById("result");
- try {
- netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- result.textContent = "FAIL";
- }
- catch (ex) {
- result.textContent = "PASS";
- }
- }
- </script>
- </head>
- <body onload="init();">
- <p id="result"></p>
- </body>
-</html>
diff --git a/testing/firefox-ui/resources/support.html b/testing/firefox-ui/resources/support.html
deleted file mode 100644
index b794e9ef92..0000000000
--- a/testing/firefox-ui/resources/support.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- <script type="text/javascript">
- function show() {
- var results = /\?topic=(.+)$/.exec(window.document.location);
- var topic = decodeURIComponent(results[1].replace(/\+/g, " "))
- var node = document.getElementById("topic");
-
- node.textContent = topic;
- }
- </script>
-</head>
-
-<body onload="show()">
- <div id="topic"></div>
-</body>
-</html>
diff --git a/testing/firefox-ui/tests/functional/keyboard_shortcuts/manifest.ini b/testing/firefox-ui/tests/functional/keyboard_shortcuts/manifest.ini
deleted file mode 100644
index 97ec827f17..0000000000
--- a/testing/firefox-ui/tests/functional/keyboard_shortcuts/manifest.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-tags = local
-
-[test_browser_window.py]
diff --git a/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py b/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
deleted file mode 100644
index 5b656d0e5f..0000000000
--- a/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestBrowserWindowShortcuts(PuppeteerMixin, MarionetteTestCase):
-
- 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:')
-
- # TODO: To be moved to the upcoming add-ons library
- def opener(tab):
- tab.window.send_shortcut(tab.window.localize_entity('addons.commandkey'),
- accel=True, shift=True)
- self.browser.tabbar.open_tab(opener)
-
- # TODO: Marionette currently fails to detect the correct tab
- # with self.marionette.using_content('content'):
- # self.wait_for_condition(lambda mn: mn.get_url() == "about:addons")
-
- # TODO: remove extra switch once it is done automatically
- self.browser.tabbar.tabs[1].switch_to()
- self.browser.tabbar.close_tab()
-
- def test_search_field(self):
- current_name = self.marionette.execute_script("""
- return window.document.activeElement.localName;
- """)
-
- # This doesn't test anything if we're already at input.
- self.assertNotEqual(current_name, "input")
-
- # TODO: To be moved to the upcoming search library
- if self.puppeteer.platform == 'linux':
- key = 'searchFocusUnix.commandkey'
- else:
- key = 'searchFocus.commandkey'
- self.browser.send_shortcut(self.browser.localize_entity(key),
- accel=True)
-
- # TODO: Check that the right input box is focused
- # Located below searchbar as class="autocomplete-textbox textbox-input"
- # Anon locator has not been released yet (bug 1080764)
- def has_input_selected(mn):
- selection_name = mn.execute_script("""
- return window.document.activeElement.localName;
- """)
- return selection_name == "input"
-
- Wait(self.marionette).until(has_input_selected)
diff --git a/testing/firefox-ui/tests/functional/locationbar/manifest.ini b/testing/firefox-ui/tests/functional/locationbar/manifest.ini
deleted file mode 100644
index 72adfd767f..0000000000
--- a/testing/firefox-ui/tests/functional/locationbar/manifest.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-tags = local
-
-[test_access_locationbar.py]
-disabled = Bug 1168727 - Timeout when opening auto-complete popup
-[test_escape_autocomplete.py]
-[test_favicon_in_autocomplete.py]
-[test_suggest_bookmarks.py]
-
diff --git a/testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py b/testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py
deleted file mode 100644
index 160a402c20..0000000000
--- a/testing/firefox-ui/tests/functional/locationbar/test_access_locationbar.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestAccessLocationBar(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAccessLocationBar, self).setUp()
-
- # Clear complete history so there's no interference from previous entries.
- self.puppeteer.places.remove_all_history()
-
- self.test_urls = [
- 'layout/mozilla_projects.html',
- 'layout/mozilla.html',
- 'layout/mozilla_mission.html'
- ]
- self.test_urls = [self.marionette.absolute_url(t)
- for t in self.test_urls]
-
- self.locationbar = self.browser.navbar.locationbar
- self.autocomplete_results = self.locationbar.autocomplete_results
- self.urlbar = self.locationbar.urlbar
-
- def test_access_locationbar_history(self):
-
- # Open some local pages, then about:blank
- def load_urls():
- with self.marionette.using_context('content'):
- for url in self.test_urls:
- self.marionette.navigate(url)
- self.puppeteer.places.wait_for_visited(self.test_urls, load_urls)
- with self.marionette.using_context('content'):
- self.marionette.navigate('about:blank')
-
- # Need to blur url bar or autocomplete won't load - bug 1038614
- self.marionette.execute_script("""arguments[0].blur();""", script_args=[self.urlbar])
-
- # Clear contents of url bar to focus, then arrow down for list of visited sites
- # Verify that autocomplete is open and results are displayed
- self.locationbar.clear()
- self.urlbar.send_keys(self.puppeteer.keys.ARROW_DOWN)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_open)
- Wait(self.marionette).until(lambda _: len(self.autocomplete_results.visible_results) > 1)
-
- # Arrow down again to select first item in list, appearing in reversed order, as loaded.
- # Verify first item.
- self.urlbar.send_keys(self.puppeteer.keys.ARROW_DOWN)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.selected_index == '0')
- self.assertIn('mission', self.locationbar.value)
-
- # Navigate to the currently selected url
- # Verify it loads by comparing the page url to the test url
- self.urlbar.send_keys(self.puppeteer.keys.ENTER)
- self.assertEqual(self.locationbar.value, self.test_urls[-1])
diff --git a/testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py b/testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py
deleted file mode 100644
index 209d9b0f5f..0000000000
--- a/testing/firefox-ui/tests/functional/locationbar/test_escape_autocomplete.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestEscapeAutocomplete(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestEscapeAutocomplete, self).setUp()
-
- # Clear complete history so there's no interference from previous entries.
- self.puppeteer.places.remove_all_history()
-
- self.test_urls = [
- 'layout/mozilla.html',
- 'layout/mozilla_community.html',
- ]
- self.test_urls = [self.marionette.absolute_url(t)
- for t in self.test_urls]
-
- self.test_string = 'mozilla'
-
- self.locationbar = self.browser.navbar.locationbar
- self.autocomplete_results = self.locationbar.autocomplete_results
-
- def tearDown(self):
- self.autocomplete_results.close(force=True)
-
- super(TestEscapeAutocomplete, self).tearDown()
-
- def test_escape_autocomplete(self):
- # Open some local pages
- def load_urls():
- with self.marionette.using_context('content'):
- for url in self.test_urls:
- self.marionette.navigate(url)
- self.puppeteer.places.wait_for_visited(self.test_urls, load_urls)
-
- # Clear the location bar, type the test string, check that autocomplete list opens
- self.locationbar.clear()
- self.locationbar.urlbar.send_keys(self.test_string)
- self.assertEqual(self.locationbar.value, self.test_string)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_open)
-
- # Press escape, check location bar value, check autocomplete list closed
- self.locationbar.urlbar.send_keys(self.puppeteer.keys.ESCAPE)
- self.assertEqual(self.locationbar.value, self.test_string)
- Wait(self.marionette).until(lambda _: not self.autocomplete_results.is_open)
-
- # Press escape again and check that locationbar returns to the page url
- self.locationbar.urlbar.send_keys(self.puppeteer.keys.ESCAPE)
- self.assertEqual(self.locationbar.value, self.test_urls[-1])
diff --git a/testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py b/testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py
deleted file mode 100644
index 6e8a5f6b12..0000000000
--- a/testing/firefox-ui/tests/functional/locationbar/test_favicon_in_autocomplete.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestFaviconInAutocomplete(PuppeteerMixin, MarionetteTestCase):
-
- PREF_SUGGEST_SEARCHES = 'browser.urlbar.suggest.searches'
- PREF_SUGGEST_BOOKMARK = 'browser.urlbar.suggest.bookmark'
-
- def setUp(self):
- super(TestFaviconInAutocomplete, self).setUp()
-
- # Disable suggestions for searches and bookmarks to get results only for history
- self.marionette.set_pref(self.PREF_SUGGEST_SEARCHES, False)
- self.marionette.set_pref(self.PREF_SUGGEST_BOOKMARK, False)
-
- self.puppeteer.places.remove_all_history()
-
- self.test_urls = [self.marionette.absolute_url('layout/mozilla.html')]
-
- self.test_string = 'mozilla'
- self.test_favicon = 'mozilla_favicon.ico'
-
- self.autocomplete_results = self.browser.navbar.locationbar.autocomplete_results
-
- def tearDown(self):
- try:
- self.autocomplete_results.close(force=True)
- self.marionette.clear_pref(self.PREF_SUGGEST_SEARCHES)
- self.marionette.clear_pref(self.PREF_SUGGEST_BOOKMARK)
- finally:
- super(TestFaviconInAutocomplete, self).tearDown()
-
- def test_favicon_in_autocomplete(self):
- # Open the test page
- def load_urls():
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.test_urls[0])
- self.puppeteer.places.wait_for_visited(self.test_urls, load_urls)
-
- locationbar = self.browser.navbar.locationbar
-
- # Clear the location bar, type the test string, check that autocomplete list opens
- locationbar.clear()
- locationbar.urlbar.send_keys(self.test_string)
- self.assertEqual(locationbar.value, self.test_string)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_complete)
-
- result = self.autocomplete_results.visible_results[1]
-
- result_icon = self.marionette.execute_script("""
- return arguments[0].image;
- """, script_args=[result])
-
- self.assertIn(self.test_favicon, result_icon)
-
- self.autocomplete_results.close()
diff --git a/testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py b/testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py
deleted file mode 100644
index 9abc2d6cb9..0000000000
--- a/testing/firefox-ui/tests/functional/locationbar/test_suggest_bookmarks.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import By, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestStarInAutocomplete(PuppeteerMixin, MarionetteTestCase):
- """ 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.
- """
-
- PREF_SUGGEST_SEARCHES = 'browser.urlbar.suggest.searches'
-
- def setUp(self):
- super(TestStarInAutocomplete, self).setUp()
-
- self.bookmark_panel = None
- self.test_urls = [self.marionette.absolute_url('layout/mozilla_grants.html')]
-
- # Disable search suggestions to only get results for history and bookmarks
- self.marionette.set_pref(self.PREF_SUGGEST_SEARCHES, False)
-
- with self.marionette.using_context('content'):
- self.marionette.navigate('about:blank')
-
- self.puppeteer.places.remove_all_history()
-
- def tearDown(self):
- # Close the autocomplete results
- try:
- if self.bookmark_panel:
- self.marionette.execute_script("""
- arguments[0].hidePopup();
- """, script_args=[self.bookmark_panel])
-
- self.browser.navbar.locationbar.autocomplete_results.close()
- self.puppeteer.places.restore_default_bookmarks()
- self.marionette.clear_pref(self.PREF_SUGGEST_SEARCHES)
- finally:
- super(TestStarInAutocomplete, self).tearDown()
-
- def test_star_in_autocomplete(self):
- search_string = 'grants'
-
- def visit_urls():
- with self.marionette.using_context('content'):
- for url in self.test_urls:
- self.marionette.navigate(url)
-
- # Navigate to all the urls specified in self.test_urls and wait for them to
- # be registered as visited
- self.puppeteer.places.wait_for_visited(self.test_urls, visit_urls)
-
- # Bookmark the current page using the bookmark menu
- self.browser.menubar.select_by_id('bookmarksMenu',
- 'menu_bookmarkThisPage')
-
- # TODO: Replace hard-coded selector with library method when one is available
- self.bookmark_panel = self.marionette.find_element(By.ID, 'editBookmarkPanel')
- done_button = self.marionette.find_element(By.ID, 'editBookmarkPanelDoneButton')
-
- Wait(self.marionette).until(
- lambda mn: self.bookmark_panel.get_attribute('panelopen') == 'true')
- done_button.click()
-
- # We must open the blank page so the autocomplete result isn't "Switch to tab"
- with self.marionette.using_context('content'):
- self.marionette.navigate('about:blank')
-
- self.puppeteer.places.remove_all_history()
-
- # Focus the locationbar, delete any contents there, and type the search string
- locationbar = self.browser.navbar.locationbar
- locationbar.clear()
- locationbar.urlbar.send_keys(search_string)
- autocomplete_results = locationbar.autocomplete_results
-
- # Wait for the search string to be present, for the autocomplete results to appear
- # and for there to be exactly one autocomplete result
- Wait(self.marionette).until(lambda mn: locationbar.value == search_string)
- Wait(self.marionette).until(lambda mn: autocomplete_results.is_complete)
- Wait(self.marionette).until(lambda mn: len(autocomplete_results.visible_results) == 2)
-
- # Compare the highlighted text in the autocomplete result to the search string
- first_result = autocomplete_results.visible_results[1]
- matching_titles = autocomplete_results.get_matching_text(first_result, 'title')
- for title in matching_titles:
- Wait(self.marionette).until(lambda mn: title.lower() == search_string)
-
- self.assertIn('bookmark',
- first_result.get_attribute('type'),
- 'The auto-complete result is a bookmark')
diff --git a/testing/firefox-ui/tests/functional/manifest.ini b/testing/firefox-ui/tests/functional/manifest.ini
deleted file mode 100644
index bc254e9629..0000000000
--- a/testing/firefox-ui/tests/functional/manifest.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[include:keyboard_shortcuts/manifest.ini]
-[include:locationbar/manifest.ini]
-[include:private_browsing/manifest.ini]
-[include:security/manifest.ini]
-[include:sessionstore/manifest.ini]
diff --git a/testing/firefox-ui/tests/functional/private_browsing/manifest.ini b/testing/firefox-ui/tests/functional/private_browsing/manifest.ini
deleted file mode 100644
index 4057530827..0000000000
--- a/testing/firefox-ui/tests/functional/private_browsing/manifest.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-tags = local
-
-[test_about_private_browsing.py] \ No newline at end of file
diff --git 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
deleted file mode 100644
index 4b22d03ea9..0000000000
--- a/testing/firefox-ui/tests/functional/private_browsing/test_about_private_browsing.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.ui.browser.window import BrowserWindow
-from marionette_driver import By, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestAboutPrivateBrowsing(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAboutPrivateBrowsing, self).setUp()
-
- # Use a fake local support URL
- support_url = 'about:blank?'
- self.marionette.set_pref('app.support.baseURL', support_url)
-
- self.pb_url = support_url + 'private-browsing'
-
- def tearDown(self):
- try:
- self.marionette.clear_pref('app.support.baseURL')
- finally:
- super(TestAboutPrivateBrowsing, self).tearDown()
-
- def testCheckAboutPrivateBrowsing(self):
- self.assertFalse(self.browser.is_private)
-
- with self.marionette.using_context('content'):
- self.marionette.navigate('about:privatebrowsing')
-
- status_node = self.marionette.find_element(By.CSS_SELECTOR, 'p.showNormal')
- self.assertEqual(status_node.text,
- self.browser.localize_entity('aboutPrivateBrowsing.notPrivate'),
- 'Status text indicates we are not in private browsing mode')
-
- def window_opener(win):
- with win.marionette.using_context('content'):
- button = self.marionette.find_element(By.ID, 'startPrivateBrowsing')
- button.click()
-
- pb_window = self.browser.open_window(callback=window_opener,
- expected_window_class=BrowserWindow)
-
- try:
- self.assertTrue(pb_window.is_private)
-
- def tab_opener(tab):
- with tab.marionette.using_context('content'):
- link = tab.marionette.find_element(By.ID, 'learnMore')
- link.click()
-
- tab = pb_window.tabbar.open_tab(trigger=tab_opener)
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda _: tab.location == self.pb_url)
-
- finally:
- pb_window.close()
diff --git a/testing/firefox-ui/tests/functional/security/manifest.ini b/testing/firefox-ui/tests/functional/security/manifest.ini
deleted file mode 100644
index 46aeaf5c31..0000000000
--- a/testing/firefox-ui/tests/functional/security/manifest.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[DEFAULT]
-tags = remote
-
-[test_dv_certificate.py]
-[test_enable_privilege.py]
-tags = local
-[test_ev_certificate.py]
-skip-if = true # Bug 1407663
-[test_mixed_content_page.py]
-[test_mixed_script_content_blocking.py]
-[test_no_certificate.py]
-tags = local
-[test_safe_browsing_initial_download.py]
-[test_safe_browsing_notification.py]
-[test_safe_browsing_warning_pages.py]
-[test_security_notification.py]
-[test_ssl_disabled_error_page.py]
-[test_ssl_status_after_restart.py]
-skip-if = (os == "win" && os_version == "5.1") # Bug 1167179: Fails to open popups after restart
-[test_submit_unencrypted_info_warning.py]
-[test_unknown_issuer.py]
-[test_untrusted_connection_error_page.py]
diff --git a/testing/firefox-ui/tests/functional/security/test_dv_certificate.py b/testing/firefox-ui/tests/functional/security/test_dv_certificate.py
deleted file mode 100644
index 565f64996e..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_dv_certificate.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestDVCertificate, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.browser.navbar.locationbar.identity_popup
-
- self.url = 'https://ssl-dv.mozqa.com'
-
- def tearDown(self):
- try:
- self.browser.switch_to()
- self.identity_popup.close(force=True)
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestDVCertificate, self).tearDown()
-
- def test_dv_cert(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.assertEqual(self.locationbar.identity_box.get_property('className'),
- 'verifiedDomain')
-
- # Open the identity popup
- self.locationbar.open_identity_popup()
-
- # Check the identity popup doorhanger
- self.assertEqual(self.identity_popup.element.get_attribute('connection'), 'secure')
-
- cert = self.browser.tabbar.selected_tab.certificate
-
- # The shown host equals to the certificate
- self.assertEqual(self.identity_popup.view.main.host.get_property('textContent'),
- cert['commonName'])
-
- # Only the secure label is visible in the main view
- secure_label = self.identity_popup.view.main.secure_connection_label
- self.assertNotEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.main.insecure_connection_label
- self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
-
- self.identity_popup.view.main.expander.click()
- Wait(self.marionette).until(
- lambda _: self.identity_popup.view.security.selected,
- message='Security view of identity popup has not been selected.')
-
- # Only the secure label is visible in the security view
- secure_label = self.identity_popup.view.security.secure_connection_label
- self.assertNotEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.security.insecure_connection_label
- self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
-
- verifier_label = self.browser.localize_property('identity.identified.verifier')
- self.assertEqual(self.identity_popup.view.security.verifier.get_property('textContent'),
- verifier_label.replace("%S", cert['issuerOrganization']))
-
- def opener(mn):
- self.identity_popup.view.security.more_info_button.click()
-
- page_info_window = self.browser.open_page_info_window(opener)
- deck = page_info_window.deck
-
- self.assertEqual(deck.selected_panel, deck.security)
-
- self.assertEqual(deck.security.domain.get_property('value'),
- cert['commonName'])
-
- self.assertEqual(deck.security.owner.get_property('value'),
- page_info_window.localize_property('securityNoOwner'))
-
- self.assertEqual(deck.security.verifier.get_property('value'),
- cert['issuerOrganization'])
diff --git a/testing/firefox-ui/tests/functional/security/test_enable_privilege.py b/testing/firefox-ui/tests/functional/security/test_enable_privilege.py
deleted file mode 100644
index 17e883cc54..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_enable_privilege.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestEnablePrivilege(MarionetteTestCase):
-
- def test_enable_privilege(self):
- with self.marionette.using_context('content'):
- url = self.marionette.absolute_url('security/enable_privilege.html')
- self.marionette.navigate(url)
-
- result = self.marionette.find_element(By.ID, 'result')
- self.assertEqual(result.get_property('textContent'), 'PASS')
diff --git a/testing/firefox-ui/tests/functional/security/test_ev_certificate.py b/testing/firefox-ui/tests/functional/security/test_ev_certificate.py
deleted file mode 100644
index f5acf57957..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_ev_certificate.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestEVCertificate, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- self.url = 'https://ssl-ev.mozqa.com/'
-
- def tearDown(self):
- try:
- self.browser.switch_to()
- self.identity_popup.close(force=True)
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestEVCertificate, self).tearDown()
-
- def test_ev_certificate(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- # Check the identity box
- self.assertEqual(self.locationbar.identity_box.get_property('className'),
- 'verifiedIdentity')
-
- # Get the information from the certificate
- cert = self.browser.tabbar.selected_tab.certificate
- address = self.puppeteer.security.get_address_from_certificate(cert)
-
- # Check the identity popup label displays
- self.assertEqual(self.locationbar.identity_organization_label.get_property('value'),
- cert['organization'])
- self.assertEqual(self.locationbar.identity_country_label.get_property('value'),
- '(' + address['country'] + ')')
-
- # Open the identity popup
- self.locationbar.open_identity_popup()
-
- # Check the idenity popup doorhanger
- self.assertEqual(self.identity_popup.element.get_attribute('connection'), 'secure-ev')
-
- # For EV certificates no hostname but the organization name is shown
- self.assertEqual(self.identity_popup.view.main.host.get_property('textContent'),
- cert['organization'])
-
- # Only the secure label is visible in the main view
- secure_label = self.identity_popup.view.main.secure_connection_label
- self.assertNotEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.main.insecure_connection_label
- self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
-
- self.identity_popup.view.main.expander.click()
- Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
-
- security_view = self.identity_popup.view.security
-
- # Only the secure label is visible in the security view
- secure_label = security_view.secure_connection_label
- self.assertNotEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = security_view.insecure_connection_label
- self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
-
- # Check the organization name
- self.assertEqual(security_view.owner.get_property('textContent'), cert['organization'])
-
- # Check the owner location string
- # More information:
- # hg.mozilla.org/mozilla-central/file/eab4a81e4457/browser/base/content/browser.js#l7012
- location = self.browser.localize_property('identity.identified.state_and_country')
- location = location.replace('%S', address['state'], 1).replace('%S', address['country'])
- location = address['city'] + '\n' + location
- self.assertEqual(security_view.owner_location.get_property('textContent'), location)
-
- # Check the verifier
- l10n_verifier = self.browser.localize_property('identity.identified.verifier')
- l10n_verifier = l10n_verifier.replace('%S', cert['issuerOrganization'])
- self.assertEqual(security_view.verifier.get_property('textContent'), l10n_verifier)
-
- # Open the Page Info window by clicking the More Information button
- page_info = self.browser.open_page_info_window(
- lambda _: self.identity_popup.view.security.more_info_button.click())
-
- try:
- # Verify that the current panel is the security panel
- self.assertEqual(page_info.deck.selected_panel, page_info.deck.security)
-
- # Verify the domain listed on the security panel
- self.assertIn(cert['commonName'],
- page_info.deck.security.domain.get_property('value'))
-
- # Verify the owner listed on the security panel
- self.assertEqual(page_info.deck.security.owner.get_property('value'),
- cert['organization'])
-
- # Verify the verifier listed on the security panel
- self.assertEqual(page_info.deck.security.verifier.get_property('value'),
- cert['issuerOrganization'])
- finally:
- page_info.close()
- self.browser.focus()
diff --git a/testing/firefox-ui/tests/functional/security/test_mixed_content_page.py b/testing/firefox-ui/tests/functional/security/test_mixed_content_page.py
deleted file mode 100644
index c146b46f4f..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_mixed_content_page.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_harness import MarionetteTestCase
-
-
-class TestMixedContentPage(PuppeteerMixin, MarionetteTestCase):
- def setUp(self):
- super(TestMixedContentPage, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- self.url = 'https://mozqa.com/data/firefox/security/mixedcontent.html'
-
- def tearDown(self):
- try:
- self.identity_popup.close(force=True)
- finally:
- super(TestMixedContentPage, self).tearDown()
-
- def test_mixed_content(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.assertEqual(self.locationbar.identity_box.get_property('className'),
- 'unknownIdentity mixedDisplayContent')
-
- # Open the identity popup
- self.locationbar.open_identity_popup()
-
- # Only the insecure label is visible in the main view
- secure_label = self.identity_popup.view.main.secure_connection_label
- self.assertEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.main.insecure_connection_label
- self.assertNotEqual(insecure_label.value_of_css_property('display'), 'none')
-
- # TODO: Bug 1177417 - Needs to open and close the security view, but a second
- # click on the expander doesn't hide the security view
- # self.identity_popup.view.main.expander.click()
- # Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
-
- # Only the insecure label is visible in the security view
- secure_label = self.identity_popup.view.security.secure_connection_label
- self.assertEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.security.insecure_connection_label
- self.assertNotEqual(insecure_label.value_of_css_property('display'), 'none')
-
- # owner is not visible
- owner = self.identity_popup.view.security.owner
- self.assertEqual(owner.value_of_css_property('display'), 'none')
diff --git 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
deleted file mode 100644
index 796b1dc293..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_mixed_script_content_blocking.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import By, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestMixedScriptContentBlocking(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestMixedScriptContentBlocking, self).setUp()
-
- self.url = 'https://mozqa.com/data/firefox/security/mixed_content_blocked/index.html'
-
- self.test_elements = [
- ('result1', 'Insecure script one'),
- ('result2', 'Insecure script from iFrame'),
- ('result3', 'Insecure plugin'),
- ('result4', 'Insecure stylesheet'),
- ]
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- def tearDown(self):
- try:
- self.identity_popup.close(force=True)
- finally:
- super(TestMixedScriptContentBlocking, self).tearDown()
-
- def _expect_protection_status(self, enabled):
- if enabled:
- color, identity, state = (
- 'rgb(0, 136, 0)',
- 'verifiedDomain mixedActiveBlocked',
- 'blocked'
- )
- else:
- color, identity, state = (
- 'rgb(255, 0, 0)',
- 'unknownIdentity mixedActiveContent',
- 'unblocked'
- )
-
- # First call to Wait() needs a longer timeout due to the reload of the web page.
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda _: self.locationbar.identity_box.get_property('className') == identity,
- message='Expected identity "{}" not found'.format(identity)
- )
-
- with self.marionette.using_context('content'):
- for identifier, description in self.test_elements:
- el = self.marionette.find_element(By.ID, identifier)
- Wait(self.marionette).until(
- lambda mn: el.value_of_css_property('color') == color,
- message=("%s has been %s" % (description, state))
- )
-
- def expect_protection_enabled(self):
- self._expect_protection_status(True)
-
- def expect_protection_disabled(self):
- self._expect_protection_status(False)
-
- def test_mixed_content_page(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.expect_protection_enabled()
-
- # Disable mixed content blocking via identity popup
- self.locationbar.open_identity_popup()
- self.identity_popup.view.main.expander.click()
- Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
-
- disable_button = self.identity_popup.view.security.disable_mixed_content_blocking_button
- disable_button.click()
-
- self.expect_protection_disabled()
-
- # A reload keeps blocking disabled
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.expect_protection_disabled()
diff --git a/testing/firefox-ui/tests/functional/security/test_no_certificate.py b/testing/firefox-ui/tests/functional/security/test_no_certificate.py
deleted file mode 100644
index a3b7bf98a0..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_no_certificate.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import expected, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestNoCertificate(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestNoCertificate, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- self.url = self.marionette.absolute_url('layout/mozilla.html')
-
- def tearDown(self):
- try:
- self.browser.switch_to()
- self.identity_popup.close(force=True)
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestNoCertificate, self).tearDown()
-
- def test_no_certificate(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- # Check the favicon
- # TODO: find a better way to check, e.g., mozmill's isDisplayed
- favicon_hidden = self.marionette.execute_script("""
- return arguments[0].hasAttribute("hidden");
- """, script_args=[self.browser.navbar.locationbar.identity_icon])
- self.assertFalse(favicon_hidden, 'The identity icon is visible')
-
- # Check that the identity box organization label is blank
- self.assertEqual(self.locationbar.identity_organization_label.get_property('value'), '',
- 'The organization has no label')
-
- # Open the identity popup
- self.locationbar.open_identity_popup()
-
- # Check the idenity popup doorhanger
- self.assertEqual(self.identity_popup.element.get_attribute('connection'), 'not-secure')
-
- # The expander for the security view does not exist
- expected.element_not_present(lambda m: self.identity_popup.main.expander)
-
- # Only the insecure label is visible
- secure_label = self.identity_popup.view.main.secure_connection_label
- self.assertEqual(secure_label.value_of_css_property('display'), 'none')
-
- insecure_label = self.identity_popup.view.main.insecure_connection_label
- self.assertNotEqual(insecure_label.value_of_css_property('display'), 'none')
-
- self.identity_popup.view.main.expander.click()
- Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
-
- # Open the Page Info window by clicking the "More Information" button
- page_info = self.browser.open_page_info_window(
- lambda _: self.identity_popup.view.security.more_info_button.click())
-
- # Verify that the current panel is the security panel
- self.assertEqual(page_info.deck.selected_panel, page_info.deck.security)
-
- # Check the domain listed on the security panel contains the url's host name
- self.assertIn(urlparse(self.url).hostname,
- page_info.deck.security.domain.get_property('value'))
-
- # Check the owner label equals localized 'securityNoOwner'
- self.assertEqual(page_info.deck.security.owner.get_property('value'),
- page_info.localize_property('securityNoOwner'))
-
- # Check the verifier label equals localized 'notset'
- self.assertEqual(page_info.deck.security.verifier.get_property('value'),
- page_info.localize_property('notset'))
diff --git a/testing/firefox-ui/tests/functional/security/test_safe_browsing_initial_download.py b/testing/firefox-ui/tests/functional/security/test_safe_browsing_initial_download.py
deleted file mode 100644
index 6f9c50ffbc..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_safe_browsing_initial_download.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestSafeBrowsingInitialDownload(PuppeteerMixin, MarionetteTestCase):
-
- file_extensions = [
- 'pset',
- 'sbstore',
- ]
-
- prefs_download_lists = [
- 'urlclassifier.blockedTable',
- 'urlclassifier.downloadAllowTable',
- 'urlclassifier.downloadBlockTable',
- 'urlclassifier.malwareTable',
- 'urlclassifier.phishTable',
- 'urlclassifier.trackingTable',
- 'urlclassifier.trackingWhitelistTable',
- ]
-
- prefs_provider_update_time = {
- # Force an immediate download of the safebrowsing files
- 'browser.safebrowsing.provider.google.nextupdatetime': 1,
- 'browser.safebrowsing.provider.mozilla.nextupdatetime': 1,
- }
-
- prefs_safebrowsing = {
- 'browser.safebrowsing.debug': True,
- 'browser.safebrowsing.blockedURIs.enabled': True,
- 'browser.safebrowsing.downloads.enabled': True,
- 'browser.safebrowsing.phishing.enabled': True,
- 'browser.safebrowsing.malware.enabled': True,
- 'privacy.trackingprotection.enabled': True,
- 'privacy.trackingprotection.pbmode.enabled': True,
- }
-
- def get_safebrowsing_files(self):
- files = []
- for pref_name in self.prefs_download_lists:
- base_names = self.marionette.get_pref(pref_name).split(',')
- for ext in self.file_extensions:
- files.extend(['{file}.{ext}'.format(file=f, ext=ext) for f in base_names if f])
-
- return set(sorted(files))
-
- def setUp(self):
- super(TestSafeBrowsingInitialDownload, self).setUp()
-
- # Force the preferences for the new profile
- enforce_prefs = self.prefs_safebrowsing
- enforce_prefs.update(self.prefs_provider_update_time)
- self.marionette.enforce_gecko_prefs(enforce_prefs)
-
- self.safebrowsing_path = os.path.join(self.marionette.instance.profile.profile,
- 'safebrowsing')
- self.safebrowsing_files = self.get_safebrowsing_files()
-
- def tearDown(self):
- try:
- # Restart with a fresh profile
- self.restart(clean=True)
- finally:
- super(TestSafeBrowsingInitialDownload, self).tearDown()
-
- def test_safe_browsing_initial_download(self):
- def check_downloaded(_):
- return reduce(lambda state, pref: state and int(self.marionette.get_pref(pref)) != 1,
- self.prefs_provider_update_time.keys(), True)
-
- try:
- Wait(self.marionette, timeout=60).until(
- check_downloaded, message='Not all safebrowsing files have been downloaded')
- finally:
- files_on_disk_toplevel = os.listdir(self.safebrowsing_path)
- for f in self.safebrowsing_files:
- self.assertIn(f, files_on_disk_toplevel)
diff --git a/testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py b/testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py
deleted file mode 100644
index 5fb3d03892..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_safe_browsing_notification.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import By, expected, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestSafeBrowsingNotificationBar(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSafeBrowsingNotificationBar, self).setUp()
-
- self.test_data = [
- # Unwanted software URL
- {
- # First two properties are not needed,
- # since these errors are not reported
- 'button_property': None,
- 'report_page': None,
- 'unsafe_page': 'https://www.itisatrap.org/firefox/unwanted.html'
- },
- # Phishing URL info
- {
- 'button_property': 'safebrowsing.notADeceptiveSiteButton.label',
- 'report_page': 'google.com/safebrowsing/report_error',
- 'unsafe_page': 'https://www.itisatrap.org/firefox/its-a-trap.html'
- },
- # Malware URL object
- {
- 'button_property': 'safebrowsing.notAnAttackButton.label',
- 'report_page': 'stopbadware.org',
- 'unsafe_page': 'https://www.itisatrap.org/firefox/its-an-attack.html'
- }
- ]
-
- self.marionette.set_pref('browser.safebrowsing.phishing.enabled', True)
- self.marionette.set_pref('browser.safebrowsing.malware.enabled', True)
-
- # Give the browser a little time, because SafeBrowsing.jsm takes a while
- # between start up and adding the example urls to the db.
- # hg.mozilla.org/mozilla-central/file/46aebcd9481e/browser/base/content/browser.js#l1194
- time.sleep(3)
-
- # TODO: Bug 1139544: While we don't have a reliable way to close the safe browsing
- # notification bar when a test fails, run this test in a new tab.
- self.browser.tabbar.open_tab()
-
- def tearDown(self):
- try:
- self.puppeteer.utils.permissions.remove('https://www.itisatrap.org', 'safe-browsing')
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- self.marionette.clear_pref('browser.safebrowsing.phishing.enabled')
- self.marionette.clear_pref('browser.safebrowsing.malware.enabled')
- finally:
- super(TestSafeBrowsingNotificationBar, self).tearDown()
-
- def test_notification_bar(self):
- with self.marionette.using_context('content'):
- for item in self.test_data:
- button_property = item['button_property']
- report_page, unsafe_page = item['report_page'], item['unsafe_page']
-
- # Navigate to the unsafe page
- # Check "ignore warning" link then notification bar's "not badware" button
- # Only do this if feature supports it
- if button_property is not None:
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_ignore_warning_button(unsafe_page)
- self.check_not_badware_button(button_property, report_page)
-
- # Return to the unsafe page
- # Check "ignore warning" link then notification bar's "get me out" button
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_ignore_warning_button(unsafe_page)
- self.check_get_me_out_of_here_button()
-
- # Return to the unsafe page
- # Check "ignore warning" link then notification bar's "X" button
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_ignore_warning_button(unsafe_page)
- self.check_x_button()
-
- def check_ignore_warning_button(self, unsafe_page):
- button = self.marionette.find_element(By.ID, 'ignoreWarningButton')
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_present(By.ID, 'main-feature'),
- message='Expected target element "#main-feature" has not been found',
- )
- self.assertEquals(self.marionette.get_url(), self.browser.get_final_url(unsafe_page))
-
- # Clean up here since the permission gets set in this function
- self.puppeteer.utils.permissions.remove('https://www.itisatrap.org', 'safe-browsing')
-
- # Check the not a forgery or attack button in the notification bar
- def check_not_badware_button(self, button_property, report_page):
- with self.marionette.using_context('chrome'):
- # TODO: update to use safe browsing notification bar class when bug 1139544 lands
- label = self.browser.localize_property(button_property)
- button = (self.marionette.find_element(By.ID, 'content')
- .find_element('anon attribute', {'label': label}))
-
- self.browser.tabbar.open_tab(lambda _: button.click())
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: report_page in mn.get_url(),
- message='The expected safe-browsing report page has not been opened',
- )
-
- with self.marionette.using_context('chrome'):
- self.browser.tabbar.close_tab()
-
- def check_get_me_out_of_here_button(self):
- with self.marionette.using_context('chrome'):
- # TODO: update to use safe browsing notification bar class when bug 1139544 lands
- label = self.browser.localize_property('safebrowsing.getMeOutOfHereButton.label')
- button = (self.marionette.find_element(By.ID, 'content')
- .find_element('anon attribute', {'label': label}))
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: self.browser.default_homepage in mn.get_url(),
- message='The default home page has not been loaded',
- )
-
- def check_x_button(self):
- with self.marionette.using_context('chrome'):
- # TODO: update to use safe browsing notification bar class when bug 1139544 lands
- button = (self.marionette.find_element(By.ID, 'content')
- .find_element('anon attribute', {'value': 'blocked-badware-page'})
- .find_element('anon attribute',
- {'class': 'messageCloseButton close-icon tabbable'}))
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_stale(button),
- message='The notification bar has not been closed',
- )
diff --git 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
deleted file mode 100644
index 968a9464b1..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_safe_browsing_warning_pages.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import By, expected, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestSafeBrowsingWarningPages(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSafeBrowsingWarningPages, self).setUp()
-
- self.urls = [
- # Unwanted software URL
- 'https://www.itisatrap.org/firefox/unwanted.html',
- # Phishing URL
- 'https://www.itisatrap.org/firefox/its-a-trap.html',
- # Malware URL
- 'https://www.itisatrap.org/firefox/its-an-attack.html'
- ]
-
- self.marionette.set_pref('app.support.baseURL',
- self.marionette.absolute_url("support.html?topic="))
- self.marionette.set_pref('browser.safebrowsing.phishing.enabled', True)
- self.marionette.set_pref('browser.safebrowsing.malware.enabled', True)
-
- # Give the browser a little time, because SafeBrowsing.jsm takes a
- # while between start up and adding the example urls to the db.
- # hg.mozilla.org/mozilla-central/file/46aebcd9481e/browser/base/content/browser.js#l1194
- time.sleep(3)
-
- # TODO: Bug 1139544: While we don't have a reliable way to close the safe browsing
- # notification bar when a test fails, run this test in a new tab.
- self.browser.tabbar.open_tab()
-
- def tearDown(self):
- try:
- self.puppeteer.utils.permissions.remove('https://www.itisatrap.org', 'safe-browsing')
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- self.marionette.clear_pref('app.support.baseURL')
- self.marionette.clear_pref('browser.safebrowsing.malware.enabled')
- self.marionette.clear_pref('browser.safebrowsing.phishing.enabled')
- finally:
- super(TestSafeBrowsingWarningPages, self).tearDown()
-
- def test_warning_pages(self):
- with self.marionette.using_context("content"):
- for unsafe_page in self.urls:
- # Load a test page, then test the get me out button
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_get_me_out_of_here_button(unsafe_page)
-
- # Load the test page again, then test the report button
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_report_button(unsafe_page)
-
- # Load the test page again, then test the ignore warning button
- self.marionette.navigate(unsafe_page)
- # Wait for the DOM to receive events for about:blocked
- time.sleep(1)
- self.check_ignore_warning_button(unsafe_page)
-
- def check_get_me_out_of_here_button(self, unsafe_page):
- button = self.marionette.find_element(By.ID, "getMeOutButton")
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: self.browser.default_homepage in mn.get_url())
-
- def check_report_button(self, unsafe_page):
- # Get the URL of the support site for phishing and malware. This may result in a redirect.
- with self.marionette.using_context('chrome'):
- url = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- return Services.urlFormatter.formatURLPref("app.support.baseURL")
- + "phishing-malware";
- """)
-
- button = self.marionette.find_element(By.ID, "reportButton")
- button.click()
-
- # Wait for the button to become stale, whereby a longer timeout is needed
- # here to not fail in case of slow connections.
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_stale(button))
-
- # Wait for page load to be completed, so we can verify the URL even if a redirect happens.
- # TODO: Bug 1140470: use replacement for mozmill's waitforPageLoad
- expected_url = self.browser.get_final_url(url)
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: expected_url == mn.get_url(),
- message="The expected URL '{}' has not been loaded".format(expected_url)
- )
-
- topic = self.marionette.find_element(By.ID, "topic")
- self.assertEquals(topic.text, "phishing-malware")
-
- def check_ignore_warning_button(self, unsafe_page):
- button = self.marionette.find_element(By.ID, 'ignoreWarningButton')
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_present(By.ID, 'main-feature'))
- self.assertEquals(self.marionette.get_url(), self.browser.get_final_url(unsafe_page))
-
- # Clean up by removing safe browsing permission for unsafe page
- self.puppeteer.utils.permissions.remove('https://www.itisatrap.org', 'safe-browsing')
diff --git a/testing/firefox-ui/tests/functional/security/test_security_notification.py b/testing/firefox-ui/tests/functional/security/test_security_notification.py
deleted file mode 100644
index 5825d03648..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_security_notification.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import By, Wait
-from marionette_driver.errors import MarionetteException
-from marionette_harness import MarionetteTestCase
-
-
-class TestSecurityNotification(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSecurityNotification, self).setUp()
-
- self.urls = [
- # Invalid cert page
- 'https://ssl-expired.mozqa.com',
- # Secure page
- 'https://ssl-ev.mozqa.com/',
- # Insecure page
- 'http://no-ssl.mozqa.com'
- ]
-
- self.identity_box = self.browser.navbar.locationbar.identity_box
-
- def test_invalid_cert(self):
- with self.marionette.using_context('content'):
- # Go to a site that has an invalid (expired) cert
- self.assertRaises(MarionetteException, self.marionette.navigate, self.urls[0])
-
- # Wait for the DOM to receive events
- time.sleep(1)
-
- # Verify the text in Technical Content contains the page with invalid cert
- text = self.marionette.find_element(By.ID, 'badCertTechnicalInfo')
- self.assertIn(self.urls[0][8:], text.get_property('textContent'))
-
- # Verify the "Go Back" and "Advanced" buttons appear
- self.assertIsNotNone(self.marionette.find_element(By.ID, 'returnButton'))
- self.assertIsNotNone(self.marionette.find_element(By.ID, 'advancedButton'))
-
- # Verify the error code is correct
- self.assertIn('SEC_ERROR_EXPIRED_CERTIFICATE', text.get_property('textContent'))
-
- def test_secure_website(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.urls[1])
-
- Wait(self.marionette).until(lambda _: (
- self.identity_box.get_property('className') == 'verifiedIdentity')
- )
-
- def test_insecure_website(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.urls[2])
-
- Wait(self.marionette).until(lambda _: (
- self.identity_box.get_property('className') == 'unknownIdentity')
- )
diff --git 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
deleted file mode 100644
index d1d9c531f3..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_ssl_disabled_error_page.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import By, expected, Wait
-from marionette_driver.errors import MarionetteException
-from marionette_harness import MarionetteTestCase
-
-
-class TestSSLDisabledErrorPage(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSSLDisabledErrorPage, self).setUp()
-
- self.url = 'https://tlsv1-0.mozqa.com'
-
- self.puppeteer.utils.sanitize({"sessions": True})
-
- # Disable SSL 3.0, TLS 1.0 and TLS 1.1 for secure connections
- # by forcing the use of TLS 1.2
- # see: http://kb.mozillazine.org/Security.tls.version.*#Possible_values_and_their_effects
- self.marionette.set_pref('security.tls.version.min', 3)
- self.marionette.set_pref('security.tls.version.max', 3)
-
- def tearDown(self):
- try:
- self.marionette.clear_pref('security.tls.version.min')
- self.marionette.clear_pref('security.tls.version.max')
- finally:
- super(TestSSLDisabledErrorPage, self).tearDown()
-
- def test_ssl_disabled_error_page(self):
- with self.marionette.using_context('content'):
- # Open the test page
- self.assertRaises(MarionetteException, self.marionette.navigate, self.url)
-
- # Wait for the DOM to receive events
- time.sleep(1)
-
- # Verify "Secure Connection Failed" error page title
- title = self.marionette.find_element(By.CLASS_NAME, 'title-text')
- nss_failure2title = self.browser.localize_entity('nssFailure2.title')
- self.assertEquals(title.get_property('textContent'), nss_failure2title)
-
- # Verify the error message is correct
- short_description = self.marionette.find_element(By.ID, 'errorShortDescText')
- self.assertIn('SSL_ERROR_UNSUPPORTED_VERSION',
- short_description.get_property('textContent'))
- self.assertIn('mozqa.com', short_description.get_property('textContent'))
-
- # Verify that the "Restore" button appears and works
- reset_button = self.marionette.find_element(By.ID, 'prefResetButton')
- reset_button.click()
-
- # With the preferences reset, the page has to load correctly
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_present(By.LINK_TEXT, 'http://quality.mozilla.org'))
diff --git 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
deleted file mode 100644
index f274d8f2fd..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import Wait
-from marionette_harness import MarionetteTestCase, skip_if_e10s
-
-
-class TestSSLStatusAfterRestart(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSSLStatusAfterRestart, self).setUp()
-
- self.test_data = (
- {
- 'url': 'https://ssl-dv.mozqa.com',
- 'identity': '',
- 'type': 'secure'
- },
- {
- 'url': 'https://ssl-ev.mozqa.com/',
- 'identity': 'Mozilla Corporation',
- 'type': 'secure-ev'
- },
- {
- 'url': 'https://ssl-ov.mozqa.com/',
- 'identity': '',
- 'type': 'secure'
- }
- )
-
- # Set browser to restore previous session
- self.marionette.set_pref('browser.startup.page', 3)
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- self.browser.switch_to()
- self.identity_popup.close(force=True)
- self.marionette.clear_pref('browser.startup.page')
- finally:
- super(TestSSLStatusAfterRestart, self).tearDown()
-
- @skip_if_e10s("Bug 1325047")
- def test_ssl_status_after_restart(self):
- for item in self.test_data:
- with self.marionette.using_context('content'):
- self.marionette.navigate(item['url'])
- self.verify_certificate_status(item)
- self.browser.tabbar.open_tab()
-
- self.restart()
-
- # Refresh references to elements
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- for index, item in enumerate(self.test_data):
- self.browser.tabbar.tabs[index].select()
- self.verify_certificate_status(item)
-
- def verify_certificate_status(self, item):
- url, identity, cert_type = item['url'], item['identity'], item['type']
-
- # Check the favicon
- # TODO: find a better way to check, e.g., mozmill's isDisplayed
- favicon_hidden = self.marionette.execute_script("""
- return arguments[0].hasAttribute("hidden");
- """, script_args=[self.browser.navbar.locationbar.identity_icon])
- self.assertFalse(favicon_hidden)
-
- self.locationbar.open_identity_popup()
-
- # Check the type shown on the identity popup doorhanger
- self.assertEqual(self.identity_popup.element.get_attribute('connection'),
- cert_type)
-
- self.identity_popup.view.main.expander.click()
- Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
-
- # Check the identity label
- self.assertEqual(self.locationbar.identity_organization_label.get_property('value'),
- identity)
-
- # Get the information from the certificate
- cert = self.browser.tabbar.selected_tab.certificate
-
- # Open the Page Info window by clicking the More Information button
- page_info = self.browser.open_page_info_window(
- lambda _: self.identity_popup.view.security.more_info_button.click())
-
- # Verify that the current panel is the security panel
- self.assertEqual(page_info.deck.selected_panel, page_info.deck.security)
-
- # Verify the domain listed on the security panel
- # If this is a wildcard cert, check only the domain
- if cert['commonName'].startswith('*'):
- self.assertIn(self.puppeteer.security.get_domain_from_common_name(cert['commonName']),
- page_info.deck.security.domain.get_property('value'),
- 'Expected domain found in certificate for ' + url)
- else:
- self.assertEqual(page_info.deck.security.domain.get_property('value'),
- cert['commonName'],
- 'Domain value matches certificate common name.')
-
- # Verify the owner listed on the security panel
- if identity != '':
- owner = cert['organization']
- else:
- owner = page_info.localize_property('securityNoOwner')
-
- self.assertEqual(page_info.deck.security.owner.get_property('value'), owner,
- 'Expected owner label found for ' + url)
-
- # Verify the verifier listed on the security panel
- self.assertEqual(page_info.deck.security.verifier.get_property('value'),
- cert['issuerOrganization'],
- 'Verifier matches issuer of certificate for ' + url)
- page_info.close()
diff --git 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
deleted file mode 100644
index a2f431fb52..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_submit_unencrypted_info_warning.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import By, expected, Wait
-from marionette_driver.errors import NoAlertPresentException
-from marionette_driver.marionette import Alert
-from marionette_harness import MarionetteTestCase
-
-
-class TestSubmitUnencryptedInfoWarning(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSubmitUnencryptedInfoWarning, self).setUp()
-
- self.url = 'https://ssl-dv.mozqa.com/data/firefox/security/unencryptedsearch.html'
- self.test_string = 'mozilla'
-
- self.marionette.set_pref('security.warn_submit_insecure', True)
-
- def tearDown(self):
- try:
- self.marionette.clear_pref('security.warn_submit_insecure')
- finally:
- super(TestSubmitUnencryptedInfoWarning, self).tearDown()
-
- def test_submit_unencrypted_info_warning(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- # Get the page's search box and submit button.
- searchbox = self.marionette.find_element(By.ID, 'q')
- button = self.marionette.find_element(By.ID, 'submit')
-
- # Use the page's search box to submit information.
- searchbox.send_keys(self.test_string)
- button.click()
-
- # Get the expected warning text and replace its two instances of "##" with "\n\n".
- message = self.browser.localize_property('formPostSecureToInsecureWarning.message')
- message = message.replace('##', '\n\n')
-
- # Wait for the warning, verify the expected text matches warning, accept the warning
- warning = Alert(self.marionette)
- try:
- Wait(self.marionette,
- ignored_exceptions=NoAlertPresentException,
- timeout=self.marionette.timeout.page_load).until(
- lambda _: warning.text == message)
- finally:
- warning.accept()
-
- # Wait for the search box to become stale, then wait for the page to be reloaded.
- Wait(self.marionette).until(expected.element_stale(searchbox))
-
- # TODO: Bug 1140470: use replacement for mozmill's waitforPageLoad
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.execute_script('return document.readyState == "DOMContentLoaded" ||'
- ' document.readyState == "complete";')
- )
-
- # Check that search_term contains the test string.
- search_term = self.marionette.find_element(By.ID, 'search-term')
- self.assertEqual(search_term.get_property('textContent'), self.test_string)
diff --git a/testing/firefox-ui/tests/functional/security/test_unknown_issuer.py b/testing/firefox-ui/tests/functional/security/test_unknown_issuer.py
deleted file mode 100644
index b329f25005..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_unknown_issuer.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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
-from marionette_driver.errors import MarionetteException
-from marionette_harness import MarionetteTestCase
-
-
-class TestUnknownIssuer(MarionetteTestCase):
-
- def setUp(self):
- super(TestUnknownIssuer, self).setUp()
-
- self.url = 'https://ssl-unknownissuer.mozqa.com'
-
- def test_unknown_issuer(self):
- with self.marionette.using_context('content'):
- # Go to a site that has a cert with an unknown issuer
- self.assertRaises(MarionetteException, self.marionette.navigate, self.url)
-
- # Wait for the DOM to receive events
- time.sleep(1)
-
- # Check for the correct error code
- error = self.marionette.find_element(By.ID, 'errorCode')
- self.assertEquals(error.get_property('textContent'),
- 'SEC_ERROR_UNKNOWN_ISSUER')
-
- # Verify the "Go Back" and "Advanced" buttons appear
- self.assertIsNotNone(self.marionette.find_element(By.ID, 'returnButton'))
- self.assertIsNotNone(self.marionette.find_element(By.ID, 'advancedButton'))
diff --git 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
deleted file mode 100644
index 0dbce1c8fc..0000000000
--- a/testing/firefox-ui/tests/functional/security/test_untrusted_connection_error_page.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_driver import By, Wait
-from marionette_driver.errors import MarionetteException
-from marionette_harness import MarionetteTestCase
-
-
-class TestUntrustedConnectionErrorPage(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestUntrustedConnectionErrorPage, self).setUp()
-
- self.url = 'https://ssl-selfsigned.mozqa.com'
-
- def test_untrusted_connection_error_page(self):
- self.marionette.set_context('content')
-
- # In some localized builds, the default page redirects
- target_url = self.browser.get_final_url(self.browser.default_homepage)
-
- self.assertRaises(MarionetteException, self.marionette.navigate, self.url)
-
- # Wait for the DOM to receive events
- time.sleep(1)
-
- button = self.marionette.find_element(By.ID, "returnButton")
- button.click()
-
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: target_url == self.marionette.get_url())
diff --git a/testing/firefox-ui/tests/functional/sessionstore/manifest.ini b/testing/firefox-ui/tests/functional/sessionstore/manifest.ini
deleted file mode 100644
index c2d0a02b8b..0000000000
--- a/testing/firefox-ui/tests/functional/sessionstore/manifest.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[DEFAULT]
-tags = local
-
-[test_restore_windows_after_restart.py]
-skip-if = (os == "win" || e10s) # Bug 1291844 and Bug 1228446
diff --git a/testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_restart.py b/testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_restart.py
deleted file mode 100644
index cc7de728bb..0000000000
--- a/testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_restart.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_harness import MarionetteTestCase
-
-
-class TestRestoreWindowsAfterRestart(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestRestoreWindowsAfterRestart, self).setUp()
-
- # Each list element represents a window of tabs loaded at
- # some testing URL
- self.test_windows = set([
- # Window 1. Note the comma after the absolute_url call -
- # this is Python's way of declaring a 1 item tuple.
- (self.marionette.absolute_url('layout/mozilla.html'), ),
-
- # Window 2
- (self.marionette.absolute_url('layout/mozilla_organizations.html'),
- self.marionette.absolute_url('layout/mozilla_community.html')),
-
- # Window 3
- (self.marionette.absolute_url('layout/mozilla_governance.html'),
- self.marionette.absolute_url('layout/mozilla_grants.html')),
- ])
-
- self.private_windows = set([
- (self.marionette.absolute_url('layout/mozilla_mission.html'),
- self.marionette.absolute_url('layout/mozilla_organizations.html')),
-
- (self.marionette.absolute_url('layout/mozilla_projects.html'),
- self.marionette.absolute_url('layout/mozilla_mission.html')),
- ])
-
- self.marionette.enforce_gecko_prefs({
- # Set browser to restore previous session
- 'browser.startup.page': 3,
- # Make the content load right away instead of waiting for
- # the user to click on the background tabs
- 'browser.sessionstore.restore_on_demand': False,
- # Avoid race conditions by having the content process never
- # send us session updates unless the parent has explicitly asked
- # for them via the TabStateFlusher.
- 'browser.sessionstore.debug.no_auto_updates': True,
- })
-
- def tearDown(self):
- try:
- # Create a fresh profile for subsequent tests.
- self.restart(clean=True)
- finally:
- super(TestRestoreWindowsAfterRestart, self).tearDown()
-
- def test_with_variety(self):
- """ Opens a set of windows, both standard and private, with
- some number of tabs in them. Once the tabs have loaded, restarts
- the browser, and then ensures that the standard tabs have been
- restored, and that the private ones have not.
- """
- self.open_windows(self.test_windows)
- self.open_windows(self.private_windows, is_private=True)
-
- self.restart()
-
- windows = self.puppeteer.windows.all
-
- # There's no guarantee that Marionette will return us an
- # iterator for the opened windows that will match the
- # order within our window list. Instead, we'll convert
- # the list of URLs within each open window to a set of
- # tuples that will allow us to do a direct comparison
- # while allowing the windows to be in any order.
- opened_windows = set()
- for win in windows:
- urls = tuple()
- for tab in win.tabbar.tabs:
- urls = urls + tuple([tab.location])
- opened_windows.add(urls)
-
- self.assertEqual(opened_windows, self.test_windows)
-
- def open_windows(self, window_sets, is_private=False):
- """ Opens a set of windows with tabs pointing at some
- URLs.
-
- @param window_sets (list)
- A set of URL tuples. Each tuple within window_sets
- represents a window, and each URL in the URL
- tuples represents what will be loaded in a tab.
-
- Note that if is_private is False, then the first
- URL tuple will be opened in the current window, and
- subequent tuples will be opened in new windows.
-
- Example:
-
- set(
- (self.marionette.absolute_url('layout/mozilla_1.html'),
- self.marionette.absolute_url('layout/mozilla_2.html')),
-
- (self.marionette.absolute_url('layout/mozilla_3.html'),
- self.marionette.absolute_url('layout/mozilla_4.html')),
- )
-
- This would take the currently open window, and load
- mozilla_1.html and mozilla_2.html in new tabs. It would
- then open a new, second window, and load tabs at
- mozilla_3.html and mozilla_4.html.
- @param is_private (boolean, optional)
- Whether or not any new windows should be a private browsing
- windows.
- """
-
- if (is_private):
- win = self.browser.open_browser(is_private=True)
- win.switch_to()
- else:
- win = self.browser
-
- for index, urls in enumerate(window_sets):
- if index > 0:
- win = self.browser.open_browser(is_private=is_private)
- win.switch_to()
- self.open_tabs(win, urls)
-
- def open_tabs(self, win, urls):
- """ Opens a set of URLs inside a window in new tabs.
-
- @param win (browser window)
- The browser window to load the tabs in.
- @param urls (tuple)
- A tuple of URLs to load in this window. The
- first URL will be loaded in the currently selected
- browser tab. Subsequent URLs will be loaded in
- new tabs.
- """
- # If there are any remaining URLs for this window,
- # open some new tabs and navigate to them.
- with self.marionette.using_context('content'):
- if isinstance(urls, str):
- self.marionette.navigate(urls)
- else:
- for index, url in enumerate(urls):
- if index > 0:
- with self.marionette.using_context('chrome'):
- win.tabbar.open_tab()
- self.marionette.navigate(url)
diff --git a/testing/firefox-ui/tests/puppeteer/manifest.ini b/testing/firefox-ui/tests/puppeteer/manifest.ini
deleted file mode 100644
index 2eb24b6dc0..0000000000
--- a/testing/firefox-ui/tests/puppeteer/manifest.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[DEFAULT]
-tags = local
-
-# API tests
-[test_appinfo.py]
-[test_l10n.py]
-[test_places.py]
-[test_security.py]
-tags = remote
-[test_software_update.py]
-tags = remote
-[test_utils.py]
-
-# UI tests
-[test_about_window.py]
-[test_menubar.py]
-[test_notifications.py]
-[test_page_info_window.py]
-[test_tabbar.py]
-[test_toolbars.py]
-tags = remote
-[test_update_wizard.py]
-tags = remote
-[test_windows.py]
diff --git a/testing/firefox-ui/tests/puppeteer/test_about_window.py b/testing/firefox-ui/tests/puppeteer/test_about_window.py
deleted file mode 100644
index c957211bb7..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_about_window.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.ui.deck import Panel
-from marionette_harness import MarionetteTestCase
-
-
-class TestAboutWindow(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAboutWindow, self).setUp()
-
- self.about_window = self.browser.open_about_window()
- self.deck = self.about_window.deck
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestAboutWindow, self).tearDown()
-
- def test_basic(self):
- self.assertEqual(self.about_window.window_type, 'Browser:About')
-
- def test_elements(self):
- """Test correct retrieval of elements."""
- self.assertNotEqual(self.about_window.dtds, [])
-
- self.assertEqual(self.deck.element.get_property('localName'), 'deck')
-
- # apply panel
- panel = self.deck.apply
- self.assertEqual(panel.element.get_property('localName'), 'hbox')
- self.assertEqual(panel.button.get_property('localName'), 'button')
-
- # check_for_updates panel
- panel = self.deck.check_for_updates
- self.assertEqual(panel.element.get_property('localName'), 'hbox')
- self.assertEqual(panel.button.get_property('localName'), 'button')
-
- # checking_for_updates panel
- self.assertEqual(self.deck.checking_for_updates.element.get_property('localName'), 'hbox')
-
- # download_and_install panel
- panel = self.deck.download_and_install
- self.assertEqual(panel.element.get_property('localName'), 'hbox')
- self.assertEqual(panel.button.get_property('localName'), 'button')
-
- # download_failed panel
- self.assertEqual(self.deck.download_failed.element.get_property('localName'), 'hbox')
-
- # downloading panel
- self.assertEqual(self.deck.downloading.element.get_property('localName'), 'hbox')
-
- # check deck attributes
- self.assertIsInstance(self.deck.selected_index, int)
- self.assertIsInstance(self.deck.selected_panel, Panel)
-
- def test_open_window(self):
- """Test various opening strategies."""
- def opener(win):
- self.browser.menubar.select_by_id('helpMenu', 'aboutName')
-
- open_strategies = ('menu',
- opener,
- )
-
- self.about_window.close()
- for trigger in open_strategies:
- about_window = self.browser.open_about_window(trigger=trigger)
- self.assertEquals(about_window, self.puppeteer.windows.current)
- about_window.close()
diff --git a/testing/firefox-ui/tests/puppeteer/test_appinfo.py b/testing/firefox-ui/tests/puppeteer/test_appinfo.py
deleted file mode 100644
index f0be0f6168..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_appinfo.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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 firefox_puppeteer import PuppeteerMixin
-from marionette_harness import MarionetteTestCase
-
-
-class TestAppInfo(PuppeteerMixin, MarionetteTestCase):
-
- def test_valid_properties(self):
- binary = self.marionette.bin
- version_info = mozversion.get_version(binary=binary)
-
- self.assertEqual(self.puppeteer.appinfo.ID, version_info['application_id'])
- self.assertEqual(self.puppeteer.appinfo.name, version_info['application_name'])
- self.assertEqual(self.puppeteer.appinfo.vendor, version_info['application_vendor'])
- self.assertEqual(self.puppeteer.appinfo.version, version_info['application_version'])
- # Bug 1298328 - Platform buildid mismatch due to incremental builds
- # self.assertEqual(self.puppeteer.appinfo.platformBuildID,
- # version_info['platform_buildid'])
- self.assertEqual(self.puppeteer.appinfo.platformVersion, version_info['platform_version'])
- self.assertIsNotNone(self.puppeteer.appinfo.locale)
- self.assertIsNotNone(self.puppeteer.appinfo.user_agent)
- self.assertIsNotNone(self.puppeteer.appinfo.XPCOMABI)
-
- def test_invalid_properties(self):
- with self.assertRaises(AttributeError):
- self.puppeteer.appinfo.unknown
diff --git a/testing/firefox-ui/tests/puppeteer/test_l10n.py b/testing/firefox-ui/tests/puppeteer/test_l10n.py
deleted file mode 100644
index 08f41f9d71..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_l10n.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.api.l10n import L10n
-from marionette_driver import By
-from marionette_driver.errors import NoSuchElementException
-from marionette_harness import MarionetteTestCase
-
-
-class TestL10n(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestL10n, self).setUp()
-
- self.l10n = L10n(self.marionette)
-
- def test_dtd_entity_chrome(self):
- dtds = ['chrome://global/locale/about.dtd',
- 'chrome://browser/locale/baseMenuOverlay.dtd']
-
- value = self.l10n.localize_entity(dtds, 'helpSafeMode.label')
- elm = self.marionette.find_element(By.ID, 'helpSafeMode')
- self.assertEqual(value, elm.get_attribute('label'))
-
- self.assertRaises(NoSuchElementException,
- self.l10n.localize_entity, dtds, 'notExistent')
-
- def test_dtd_entity_content(self):
- dtds = ['chrome://global/locale/about.dtd',
- 'chrome://global/locale/aboutSupport.dtd']
-
- value = self.l10n.localize_entity(dtds, 'aboutSupport.pageTitle')
-
- self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
- self.marionette.navigate('about:support')
-
- elm = self.marionette.find_element(By.TAG_NAME, 'title')
- self.assertEqual(value, elm.text)
-
- def test_properties(self):
- properties = ['chrome://global/locale/filepicker.properties',
- 'chrome://global/locale/findbar.properties']
-
- # TODO: Find a way to verify the retrieved translated string
- value = self.l10n.localize_property(properties, 'NotFound')
- self.assertNotEqual(value, '')
-
- self.assertRaises(NoSuchElementException,
- self.l10n.localize_property, properties, 'notExistent')
diff --git a/testing/firefox-ui/tests/puppeteer/test_menubar.py b/testing/firefox-ui/tests/puppeteer/test_menubar.py
deleted file mode 100644
index ddc6117bf7..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_menubar.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver.errors import NoSuchElementException
-from marionette_harness import MarionetteTestCase
-
-
-class TestMenuBar(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestMenuBar, self).setUp()
-
- def test_click_item_in_menubar(self):
- def opener(_):
- self.browser.menubar.select_by_id('file-menu',
- 'menu_newNavigatorTab')
-
- self.browser.tabbar.open_tab(trigger=opener)
-
- self.browser.tabbar.tabs[-1].close()
-
- def test_click_non_existent_menu_and_item(self):
- with self.assertRaises(NoSuchElementException):
- self.browser.menubar.select_by_id('foobar-menu',
- 'menu_newNavigatorTab')
-
- with self.assertRaises(NoSuchElementException):
- self.browser.menubar.select_by_id('file-menu', 'menu_foobar')
diff --git a/testing/firefox-ui/tests/puppeteer/test_notifications.py b/testing/firefox-ui/tests/puppeteer/test_notifications.py
deleted file mode 100644
index de44c74349..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_notifications.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.ui.browser.notifications import (
- AddOnInstallFailedNotification,
- AddOnInstallConfirmationNotification,
-)
-from marionette_driver import By
-from marionette_driver.errors import TimeoutException
-from marionette_harness import MarionetteTestCase
-
-
-class TestNotifications(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestNotifications, self).setUp()
-
- self.marionette.set_pref('extensions.install.requireSecureOrigin', False)
-
- self.addons_url = self.marionette.absolute_url('addons/extensions/')
- self.puppeteer.utils.permissions.add(self.marionette.baseurl, 'install')
-
- def tearDown(self):
- try:
- self.marionette.clear_pref('extensions.install.requireSecureOrigin')
- self.marionette.clear_pref('xpinstall.signatures.required')
-
- self.puppeteer.utils.permissions.remove(self.addons_url, 'install')
-
- if self.browser.notification:
- self.browser.notification.close(force=True)
- finally:
- super(TestNotifications, self).tearDown()
-
- def test_open_close_notification(self):
- """Trigger and dismiss a notification"""
- self.assertIsNone(self.browser.notification)
- self.trigger_addon_notification('restartless_addon_signed.xpi')
- self.browser.notification.close()
- self.assertIsNone(self.browser.notification)
-
- def test_wait_for_notification_timeout(self):
- """Wait for a notification when one is not shown"""
- message = 'No notification was shown'
- with self.assertRaisesRegexp(TimeoutException, message):
- self.browser.wait_for_notification()
-
- def test_wait_for_specific_notification_timeout(self):
- """Wait for a notification when one is not shown"""
- message = 'AddOnInstallFailedNotification was not shown'
- with self.assertRaisesRegexp(TimeoutException, message):
- self.browser.wait_for_notification(AddOnInstallFailedNotification)
-
- def test_wait_for_no_notification_timeout(self):
- """Wait for no notification when one is shown"""
- message = 'Unexpected notification shown'
- self.trigger_addon_notification('restartless_addon_signed.xpi')
- with self.assertRaisesRegexp(TimeoutException, message):
- self.browser.wait_for_notification(None)
-
- def test_notification_with_origin(self):
- """Trigger a notification with an origin"""
- self.trigger_addon_notification('restartless_addon_signed.xpi')
- self.assertIn(self.browser.notification.origin, self.marionette.baseurl)
- self.assertIsNotNone(self.browser.notification.label)
-
- def test_addon_install_failed_notification(self):
- """Trigger add-on blocked notification using an unsigned add-on"""
- # Ensure that installing unsigned extensions will fail
- self.marionette.set_pref('xpinstall.signatures.required', True)
-
- self.trigger_addon_notification(
- 'restartless_addon_unsigned.xpi',
- notification=AddOnInstallFailedNotification)
-
- def trigger_addon_notification(self, addon, notification=AddOnInstallConfirmationNotification):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.addons_url)
- self.marionette.find_element(By.LINK_TEXT, addon).click()
- self.browser.wait_for_notification(notification)
diff --git a/testing/firefox-ui/tests/puppeteer/test_page_info_window.py b/testing/firefox-ui/tests/puppeteer/test_page_info_window.py
deleted file mode 100644
index d86cbee3cb..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_page_info_window.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_harness import MarionetteTestCase
-
-
-class TestPageInfoWindow(PuppeteerMixin, MarionetteTestCase):
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestPageInfoWindow, self).tearDown()
-
- def test_elements(self):
- """Test correct retrieval of elements."""
- page_info = self.browser.open_page_info_window()
-
- self.assertNotEqual(page_info.dtds, [])
- self.assertNotEqual(page_info.properties, [])
-
- self.assertEqual(page_info.deck.element.get_property('localName'), 'deck')
-
- # feed panel
- self.assertEqual(page_info.deck.feed.element.get_property('localName'), 'vbox')
-
- # general panel
- self.assertEqual(page_info.deck.general.element.get_property('localName'), 'vbox')
-
- # media panel
- self.assertEqual(page_info.deck.media.element.get_property('localName'), 'vbox')
-
- # permissions panel
- self.assertEqual(page_info.deck.permissions.element.get_property('localName'), 'vbox')
-
- # security panel
- panel = page_info.deck.select(page_info.deck.security)
-
- self.assertEqual(panel.element.get_property('localName'), 'vbox')
-
- self.assertEqual(panel.domain.get_property('localName'), 'textbox')
- self.assertEqual(panel.owner.get_property('localName'), 'textbox')
- self.assertEqual(panel.verifier.get_property('localName'), 'textbox')
-
- self.assertEqual(panel.view_certificate.get_property('localName'), 'button')
- self.assertEqual(panel.view_cookies.get_property('localName'), 'button')
- self.assertEqual(panel.view_passwords.get_property('localName'), 'button')
-
- def test_select(self):
- """Test properties and methods for switching between panels."""
- page_info = self.browser.open_page_info_window()
- deck = page_info.deck
-
- self.assertEqual(deck.selected_panel, deck.general)
-
- self.assertEqual(deck.select(deck.security), deck.security)
- self.assertEqual(deck.selected_panel, deck.security)
-
- def test_open_window(self):
- """Test various opening strategies."""
- def opener(win):
- self.browser.menubar.select_by_id('tools-menu', 'menu_pageInfo')
-
- open_strategies = ('menu',
- 'shortcut',
- opener,
- )
-
- for trigger in open_strategies:
- if trigger == 'shortcut' and self.puppeteer.platform == 'windows_nt':
- # The shortcut for page info window does not exist on windows.
- self.assertRaises(ValueError, self.browser.open_page_info_window,
- trigger=trigger)
- continue
-
- page_info = self.browser.open_page_info_window(trigger=trigger)
- self.assertEquals(page_info, self.puppeteer.windows.current)
- page_info.close()
-
- def test_close_window(self):
- """Test various closing strategies."""
- def closer(win):
- win.send_shortcut(win.localize_entity('closeWindow.key'),
- accel=True)
-
- # Close a tab by each trigger method
- close_strategies = ('menu',
- 'shortcut',
- closer,
- )
- for trigger in close_strategies:
- # menu only works on OS X
- if trigger == 'menu' and self.puppeteer.platform != 'darwin':
- continue
-
- page_info = self.browser.open_page_info_window()
- page_info.close(trigger=trigger)
- self.assertTrue(page_info.closed)
diff --git a/testing/firefox-ui/tests/puppeteer/test_places.py b/testing/firefox-ui/tests/puppeteer/test_places.py
deleted file mode 100644
index 95d0f23a45..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_places.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import By, Wait
-from marionette_harness import MarionetteTestCase
-
-
-class TestPlaces(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestPlaces, self).setUp()
-
- self.urls = [self.marionette.absolute_url('layout/mozilla_governance.html'),
- self.marionette.absolute_url('layout/mozilla_grants.html'),
- ]
-
- def tearDown(self):
- try:
- self.puppeteer.places.restore_default_bookmarks()
- self.puppeteer.places.remove_all_history()
- finally:
- super(TestPlaces, self).tearDown()
-
- def get_all_urls_in_history(self):
- return self.marionette.execute_script("""
- let hs = Components.classes["@mozilla.org/browser/nav-history-service;1"]
- .getService(Components.interfaces.nsINavHistoryService);
- let urls = [];
-
- let options = hs.getNewQueryOptions();
- options.resultType = options.RESULTS_AS_URI;
-
- let root = hs.executeQuery(hs.getNewQuery(), options).root
- root.containerOpen = true;
- for (let i = 0; i < root.childCount; i++) {
- urls.push(root.getChild(i).uri)
- }
- root.containerOpen = false;
-
- return urls;
- """)
-
- def test_plugins(self):
- # TODO: Once we use a plugin, add a test case to verify that the data will be removed
- self.puppeteer.places.clear_plugin_data()
-
- def test_bookmarks(self):
- star_button = self.marionette.find_element(By.ID, 'bookmarks-menu-button')
-
- # Visit URLs and bookmark them all
- for url in self.urls:
- with self.marionette.using_context('content'):
- self.marionette.navigate(url)
-
- Wait(self.marionette).until(
- lambda _: self.puppeteer.places.is_bookmark_star_button_ready())
- star_button.click()
- Wait(self.marionette).until(lambda _: self.puppeteer.places.is_bookmarked(url))
-
- ids = self.puppeteer.places.get_folder_ids_for_url(url)
- self.assertEqual(len(ids), 1)
- self.assertEqual(ids[0], self.puppeteer.places.bookmark_folders.unfiled)
-
- # Restore default bookmarks, so the added URLs are gone
- self.puppeteer.places.restore_default_bookmarks()
- for url in self.urls:
- self.assertFalse(self.puppeteer.places.is_bookmarked(url))
-
- def test_history(self):
- self.assertEqual(len(self.get_all_urls_in_history()), 0)
-
- # Visit pages and check that they are all present
- def load_urls():
- with self.marionette.using_context('content'):
- for url in self.urls:
- self.marionette.navigate(url)
- self.puppeteer.places.wait_for_visited(self.urls, load_urls)
-
- self.assertEqual(self.get_all_urls_in_history(), self.urls)
-
- # Check that both pages are no longer in the remove_all_history
- self.puppeteer.places.remove_all_history()
- self.assertEqual(len(self.get_all_urls_in_history()), 0)
diff --git a/testing/firefox-ui/tests/puppeteer/test_security.py b/testing/firefox-ui/tests/puppeteer/test_security.py
deleted file mode 100644
index 879053e5a8..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_security.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.errors import NoCertificateError
-from marionette_harness import MarionetteTestCase
-
-
-class TestSecurity(PuppeteerMixin, MarionetteTestCase):
-
- def test_get_address_from_certificate(self):
- url = 'https://ssl-ev.mozqa.com'
-
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- self.marionette.navigate(url)
-
- cert = self.browser.tabbar.tabs[0].certificate
- self.assertIn(cert['commonName'], url)
- self.assertEqual(cert['organization'], 'Mozilla Corporation')
- self.assertEqual(cert['issuerOrganization'], 'DigiCert Inc')
-
- address = self.puppeteer.security.get_address_from_certificate(cert)
- self.assertIsNotNone(address)
- self.assertIsNotNone(address['city'])
- self.assertIsNotNone(address['country'])
- self.assertIsNotNone(address['postal_code'])
- self.assertIsNotNone(address['state'])
- self.assertIsNotNone(address['street'])
-
- def test_get_certificate(self):
- url_http = self.marionette.absolute_url('layout/mozilla.html')
- url_https = 'https://ssl-ev.mozqa.com'
-
- # Test EV certificate
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- self.marionette.navigate(url_https)
- cert = self.browser.tabbar.tabs[0].certificate
- self.assertIn(cert['commonName'], url_https)
-
- # HTTP connections do not have a SSL certificate
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- self.marionette.navigate(url_http)
- with self.assertRaises(NoCertificateError):
- self.browser.tabbar.tabs[0].certificate
diff --git a/testing/firefox-ui/tests/puppeteer/test_software_update.py b/testing/firefox-ui/tests/puppeteer/test_software_update.py
deleted file mode 100644
index 4bad47d94a..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_software_update.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.api.software_update import SoftwareUpdate
-from marionette_harness import MarionetteTestCase
-
-
-class TestSoftwareUpdate(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSoftwareUpdate, self).setUp()
-
- 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:
- super(TestSoftwareUpdate, self).tearDown()
-
- def test_abi(self):
- self.assertTrue(self.software_update.ABI)
-
- def test_allowed(self):
- self.assertTrue(self.software_update.allowed)
-
- def test_build_info(self):
- build_info = self.software_update.build_info
- self.assertEqual(build_info['disabled_addons'], None)
- self.assertIn('Mozilla/', build_info['user_agent'])
- self.assertEqual(build_info['mar_channels'], set(['expected', 'channels']))
- self.assertTrue(build_info['version'])
- self.assertTrue(build_info['buildid'].isdigit())
- self.assertTrue(build_info['locale'])
- self.assertIn('force=1', build_info['update_url'])
- self.assertIn('xml', build_info['update_snippet'])
- self.assertEqual(build_info['channel'], self.software_update.update_channel)
-
- def test_force_fallback(self):
- status_file = os.path.join(self.software_update.staging_directory, 'update.status')
-
- try:
- self.software_update.force_fallback()
- with open(status_file, 'r') as f:
- content = f.read()
- self.assertEqual(content, 'failed: 6\n')
- finally:
- os.remove(status_file)
-
- def test_get_update_url(self):
- update_url = self.software_update.get_update_url()
- self.assertIn('Firefox', update_url)
- self.assertNotIn('force=1', update_url)
- update_url = self.software_update.get_update_url(True)
- self.assertIn('Firefox', update_url)
- self.assertIn('force=1', update_url)
-
- def test_os_version(self):
- self.assertTrue(self.software_update.os_version)
-
- def test_staging_directory(self):
- self.assertTrue(self.software_update.staging_directory)
-
-
-class TestUpdateChannel(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestUpdateChannel, self).setUp()
-
- self.software_update = SoftwareUpdate(self.marionette)
-
- self.saved_channel = self.software_update.update_channel
- self.software_update.update_channel = 'expected_channel'
-
- def tearDown(self):
- try:
- self.software_update.update_channel = self.saved_channel
- finally:
- super(TestUpdateChannel, self).tearDown()
-
- def test_update_channel_default_channel(self):
- # Without a restart the update channel will not change.
- self.assertEqual(self.software_update.update_channel, self.saved_channel)
-
- def test_update_channel_set_channel(self):
- try:
- # Use the clean option to force a non in_app restart, which would allow
- # Firefox to dump the logs to the console.
- self.restart(clean=True)
- self.assertEqual(self.software_update.update_channel, 'expected_channel')
- finally:
- self.software_update.update_channel = self.saved_channel
- self.restart(clean=True)
-
-
-class TestMARChannels(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestMARChannels, self).setUp()
-
- 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:
- super(TestMARChannels, self).tearDown()
-
- def test_mar_channels_channels(self):
- self.assertEqual(self.software_update.mar_channels.channels, set(['expected', 'channels']))
-
- def test_mar_channels_set_channels(self):
- self.software_update.mar_channels.channels = set(['a', 'b', 'c'])
- self.assertEqual(self.software_update.mar_channels.channels, set(['a', 'b', 'c']))
-
- def test_mar_channels_add_channels(self):
- self.software_update.mar_channels.add_channels(set(['some', 'new', 'channels']))
- self.assertEqual(
- self.software_update.mar_channels.channels,
- set(['expected', 'channels', 'some', 'new']))
-
- def test_mar_channels_remove_channels(self):
- self.software_update.mar_channels.remove_channels(set(['expected']))
- self.assertEqual(self.software_update.mar_channels.channels, set(['channels']))
diff --git a/testing/firefox-ui/tests/puppeteer/test_tabbar.py b/testing/firefox-ui/tests/puppeteer/test_tabbar.py
deleted file mode 100644
index 7da3f7ee72..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_tabbar.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.errors import NoCertificateError
-from marionette_harness import MarionetteTestCase
-
-
-class TestTabBar(PuppeteerMixin, MarionetteTestCase):
-
- def tearDown(self):
- try:
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- finally:
- super(TestTabBar, self).tearDown()
-
- def test_basics(self):
- tabbar = self.browser.tabbar
-
- self.assertEqual(tabbar.window, self.browser)
-
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
-
- self.assertEqual(tabbar.newtab_button.get_property('localName'), 'toolbarbutton')
- self.assertEqual(tabbar.toolbar.get_property('localName'), 'tabs')
-
- def test_open_close(self):
- tabbar = self.browser.tabbar
-
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.selected_index, 0)
-
- # Open with default trigger, and force closing the tab
- tabbar.open_tab()
- tabbar.close_tab(force=True)
-
- # Open a new tab by each trigger method
- open_strategies = ('button',
- 'menu',
- 'shortcut',
- lambda tab: tabbar.newtab_button.click()
- )
- for trigger in open_strategies:
- new_tab = tabbar.open_tab(trigger=trigger)
- self.assertEqual(len(tabbar.tabs), 2)
- self.assertEqual(new_tab.handle, self.marionette.current_window_handle)
- self.assertEqual(new_tab.handle, tabbar.tabs[1].handle)
-
- tabbar.close_tab()
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
- self.assertNotEqual(new_tab.handle, tabbar.tabs[0].handle)
-
- # Close a tab by each trigger method
- close_strategies = ('button',
- 'menu',
- 'shortcut',
- lambda tab: tab.close_button.click())
- for trigger in close_strategies:
- new_tab = tabbar.open_tab()
- self.assertEqual(len(tabbar.tabs), 2)
- self.assertEqual(new_tab.handle, self.marionette.current_window_handle)
- self.assertEqual(new_tab.handle, tabbar.tabs[1].handle)
-
- tabbar.close_tab(trigger=trigger)
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
- self.assertNotEqual(new_tab.handle, tabbar.tabs[0].handle)
-
- def test_close_not_selected_tab(self):
- tabbar = self.browser.tabbar
-
- new_tab = tabbar.open_tab()
- tabbar.close_tab(tabbar.tabs[0], trigger="button")
-
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(new_tab, tabbar.tabs[0])
-
- def test_close_all_tabs_except_first(self):
- tabbar = self.browser.tabbar
-
- orig_tab = tabbar.tabs[0]
-
- for i in range(0, 3):
- tabbar.open_tab()
-
- tabbar.close_all_tabs([orig_tab])
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(orig_tab.handle, self.marionette.current_window_handle)
-
- def test_switch_to(self):
- tabbar = self.browser.tabbar
-
- # Open a new tab in the foreground (will be auto-selected)
- new_tab = tabbar.open_tab()
- self.assertEqual(new_tab.handle, self.marionette.current_window_handle)
- self.assertEqual(tabbar.selected_index, 1)
- self.assertEqual(tabbar.selected_tab, new_tab)
-
- # Switch by index
- tabbar.switch_to(0)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
-
- # Switch by tab
- tabbar.switch_to(new_tab)
- self.assertEqual(new_tab.handle, self.marionette.current_window_handle)
-
- # Switch by callback
- tabbar.switch_to(lambda tab: tab.window.tabbar.selected_tab != tab)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
-
- tabbar.close_tab(tabbar.tabs[1])
-
-
-class TestTab(PuppeteerMixin, MarionetteTestCase):
-
- def tearDown(self):
- try:
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- finally:
- super(TestTab, self).tearDown()
-
- def test_basic(self):
- tab = self.browser.tabbar.tabs[0]
-
- self.assertEqual(tab.window, self.browser)
-
- self.assertEqual(tab.tab_element.get_property('localName'), 'tab')
- self.assertEqual(tab.close_button.get_property('localName'), 'toolbarbutton')
-
- def test_certificate(self):
- url = self.marionette.absolute_url('layout/mozilla.html')
-
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- self.marionette.navigate(url)
- with self.assertRaises(NoCertificateError):
- self.browser.tabbar.tabs[0].certificate
-
- def test_close(self):
- tabbar = self.browser.tabbar
-
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.selected_index, 0)
-
- # Force closing the tab
- new_tab = tabbar.open_tab()
- new_tab.close(force=True)
-
- # Close a tab by each trigger method
- close_strategies = ('button',
- 'menu',
- 'shortcut',
- lambda tab: tab.close_button.click())
- for trigger in close_strategies:
- new_tab = tabbar.open_tab()
- self.assertEqual(len(tabbar.tabs), 2)
- self.assertEqual(new_tab.handle, self.marionette.current_window_handle)
- self.assertEqual(new_tab.handle, tabbar.tabs[1].handle)
-
- new_tab.close(trigger=trigger)
- self.assertEqual(len(tabbar.tabs), 1)
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
- self.assertNotEqual(new_tab.handle, tabbar.tabs[0].handle)
-
- def test_location(self):
- url = self.marionette.absolute_url('layout/mozilla.html')
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- self.marionette.navigate(url)
- self.assertEqual(self.browser.tabbar.tabs[0].location, url)
-
- def test_switch_to(self):
- tabbar = self.browser.tabbar
-
- new_tab = tabbar.open_tab()
-
- # Switch to the first tab, which will not select it
- tabbar.tabs[0].switch_to()
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
- # Bug 1128656: We cannot test as long as switch_to_window() auto-selects the tab
- # self.assertEqual(tabbar.selected_index, 1)
- # self.assertEqual(tabbar.selected_tab, new_tab)
-
- # Now select the first tab
- tabbar.tabs[0].select()
- self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
- self.assertTrue(tabbar.tabs[0].selected)
- self.assertFalse(tabbar.tabs[1].selected)
-
- new_tab.close()
diff --git a/testing/firefox-ui/tests/puppeteer/test_toolbars.py b/testing/firefox-ui/tests/puppeteer/test_toolbars.py
deleted file mode 100644
index 8150be7e15..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_toolbars.py
+++ /dev/null
@@ -1,283 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_driver import expected, By, Wait
-from marionette_driver.errors import NoSuchElementException
-from marionette_harness import MarionetteTestCase
-
-
-class TestNavBar(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestNavBar, self).setUp()
-
- self.navbar = self.browser.navbar
- self.url = self.marionette.absolute_url('layout/mozilla.html')
-
- with self.marionette.using_context('content'):
- self.marionette.navigate('about:blank')
-
- # TODO: check why self.puppeteer.places.remove_all_history() does not work here
- self.marionette.execute_script("""
- let count = gBrowser.sessionHistory.count;
- gBrowser.sessionHistory.PurgeHistory(count);
- """)
-
- def test_elements(self):
- self.assertEqual(self.navbar.back_button.get_property('localName'), 'toolbarbutton')
- self.assertEqual(self.navbar.forward_button.get_property('localName'), 'toolbarbutton')
- self.assertEqual(self.navbar.home_button.get_property('localName'), 'toolbarbutton')
- self.assertEqual(self.navbar.menu_button.get_property('localName'), 'toolbarbutton')
- self.assertEqual(self.navbar.toolbar.get_property('localName'), 'toolbar')
-
- def test_buttons(self):
- self.marionette.set_context('content')
-
- # Load initial web page
- self.marionette.navigate(self.url)
- Wait(self.marionette).until(expected.element_present(lambda m:
- m.find_element(By.ID, 'mozilla_logo')))
-
- with self.marionette.using_context('chrome'):
- # Both buttons are disabled
- self.assertFalse(self.navbar.back_button.is_enabled())
- self.assertFalse(self.navbar.forward_button.is_enabled())
-
- # Go to the homepage
- self.navbar.home_button.click()
-
- Wait(self.marionette).until(expected.element_not_present(lambda m:
- m.find_element(By.ID, 'mozilla_logo')))
- self.assertEqual(self.marionette.get_url(), self.browser.default_homepage)
-
- with self.marionette.using_context('chrome'):
- # Only back button is enabled
- self.assertTrue(self.navbar.back_button.is_enabled())
- self.assertFalse(self.navbar.forward_button.is_enabled())
-
- # Navigate back
- self.navbar.back_button.click()
-
- Wait(self.marionette).until(expected.element_present(lambda m:
- m.find_element(By.ID, 'mozilla_logo')))
- self.assertEqual(self.marionette.get_url(), self.url)
-
- with self.marionette.using_context('chrome'):
- # Only forward button is enabled
- self.assertFalse(self.navbar.back_button.is_enabled())
- self.assertTrue(self.navbar.forward_button.is_enabled())
-
- # Navigate forward
- self.navbar.forward_button.click()
-
- Wait(self.marionette).until(expected.element_not_present(lambda m:
- m.find_element(By.ID, 'mozilla_logo')))
- self.assertEqual(self.marionette.get_url(), self.browser.default_homepage)
-
-
-class TestLocationBar(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestLocationBar, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
-
- def test_elements(self):
- self.assertEqual(self.locationbar.urlbar.get_property('localName'), 'textbox')
- self.assertIn('urlbar-input', self.locationbar.urlbar_input.get_property('className'))
-
- self.assertEqual(self.locationbar.connection_icon.get_property('localName'), 'image')
- self.assertEqual(self.locationbar.identity_box.get_property('localName'), 'box')
- self.assertEqual(self.locationbar.identity_country_label.get_property('localName'),
- 'label')
- self.assertEqual(self.locationbar.identity_organization_label.get_property('localName'),
- 'label')
- self.assertEqual(self.locationbar.identity_icon.get_property('localName'), 'image')
- self.assertEqual(self.locationbar.history_drop_marker.get_property('localName'),
- 'dropmarker')
- self.assertEqual(self.locationbar.reload_button.get_property('localName'),
- 'toolbarbutton')
- self.assertEqual(self.locationbar.stop_button.get_property('localName'),
- 'toolbarbutton')
-
- self.assertEqual(self.locationbar.contextmenu.get_property('localName'), 'menupopup')
- self.assertEqual(self.locationbar.get_contextmenu_entry('paste').get_attribute('cmd'),
- 'cmd_paste')
-
- def test_reload(self):
- event_types = ["shortcut", "shortcut2", "button"]
- for event in event_types:
- # TODO: Until we have waitForPageLoad, this only tests API
- # compatibility.
- self.locationbar.reload_url(event, force=True)
- self.locationbar.reload_url(event, force=False)
-
- def test_focus_and_clear(self):
- self.locationbar.urlbar.send_keys("zyx")
- self.locationbar.clear()
- self.assertEqual(self.locationbar.value, '')
-
- self.locationbar.urlbar.send_keys("zyx")
- self.assertEqual(self.locationbar.value, 'zyx')
-
- self.locationbar.clear()
- self.assertEqual(self.locationbar.value, '')
-
- def test_load_url(self):
- data_uri = 'data:text/html,<title>Title</title>'
- self.locationbar.load_url(data_uri)
-
- with self.marionette.using_context('content'):
- Wait(self.marionette).until(lambda mn: mn.get_url() == data_uri)
-
-
-class TestAutoCompleteResults(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAutoCompleteResults, self).setUp()
-
- self.browser.navbar.locationbar.clear()
-
- self.autocomplete_results = self.browser.navbar.locationbar.autocomplete_results
-
- def tearDown(self):
- try:
- self.autocomplete_results.close(force=True)
- except NoSuchElementException:
- # TODO: A NoSuchElementException is thrown here when tests accessing the
- # autocomplete_results element are skipped.
- pass
- finally:
- super(TestAutoCompleteResults, self).tearDown()
-
- def test_popup_elements(self):
- # TODO: This test is not very robust because it relies on the history
- # in the default profile.
- self.assertFalse(self.autocomplete_results.is_open)
- self.browser.navbar.locationbar.urlbar.send_keys('a')
- results = self.autocomplete_results.results
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_complete)
- visible_result_count = len(self.autocomplete_results.visible_results)
- self.assertTrue(visible_result_count > 0)
- self.assertEqual(visible_result_count,
- int(results.get_property('itemCount')))
-
- def test_close(self):
- self.browser.navbar.locationbar.urlbar.send_keys('a')
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_open)
- # The Wait in the library implementation will fail this if this doesn't
- # end up closing.
- self.autocomplete_results.close()
-
- def test_force_close(self):
- self.browser.navbar.locationbar.urlbar.send_keys('a')
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_open)
- # The Wait in the library implementation will fail this if this doesn't
- # end up closing.
- self.autocomplete_results.close(force=True)
-
- def test_matching_text(self):
- # The default profile always has existing bookmarks. So no sites have to
- # be visited and bookmarked.
- for input_text in ('about', 'zilla'):
- self.browser.navbar.locationbar.urlbar.clear()
- self.browser.navbar.locationbar.urlbar.send_keys(input_text)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_open)
- Wait(self.marionette).until(lambda _: self.autocomplete_results.is_complete)
- visible_results = self.autocomplete_results.visible_results
- self.assertTrue(len(visible_results) > 0)
-
- for result in visible_results:
- # check matching text only for results of type bookmark
- if result.get_attribute('type') != 'bookmark':
- continue
- title_matches = self.autocomplete_results.get_matching_text(result, "title")
- url_matches = self.autocomplete_results.get_matching_text(result, "url")
- all_matches = title_matches + url_matches
- self.assertTrue(len(all_matches) > 0)
- for match_fragment in all_matches:
- self.assertIn(match_fragment.lower(), input_text)
-
- self.autocomplete_results.close()
-
-
-class TestIdentityPopup(PuppeteerMixin, MarionetteTestCase):
- def setUp(self):
- super(TestIdentityPopup, self).setUp()
-
- self.locationbar = self.browser.navbar.locationbar
- self.identity_popup = self.locationbar.identity_popup
-
- self.url = 'https://ssl-ev.mozqa.com'
-
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- def tearDown(self):
- try:
- self.identity_popup.close(force=True)
- finally:
- super(TestIdentityPopup, self).tearDown()
-
- def test_elements(self):
- self.locationbar.open_identity_popup()
-
- # Test main view elements
- main = self.identity_popup.view.main
- self.assertEqual(main.element.get_property('localName'), 'panelview')
-
- self.assertEqual(main.expander.get_property('localName'), 'button')
- self.assertEqual(main.host.get_property('localName'), 'label')
- self.assertEqual(main.insecure_connection_label.get_property('localName'),
- 'description')
- self.assertEqual(main.internal_connection_label.get_property('localName'),
- 'description')
- self.assertEqual(main.secure_connection_label.get_property('localName'),
- 'description')
-
- self.assertEqual(main.permissions.get_property('localName'), 'vbox')
-
- # Test security view elements
- security = self.identity_popup.view.security
- self.assertEqual(security.element.get_property('localName'), 'panelview')
-
- self.assertEqual(security.host.get_property('localName'), 'label')
- self.assertEqual(security.insecure_connection_label.get_property('localName'),
- 'description')
- self.assertEqual(security.secure_connection_label.get_property('localName'),
- 'description')
-
- self.assertEqual(security.owner.get_property('localName'), 'description')
- self.assertEqual(security.owner_location.get_property('localName'), 'description')
- self.assertEqual(security.verifier.get_property('localName'), 'description')
-
- self.assertEqual(security.disable_mixed_content_blocking_button.get_property('localName'),
- 'button')
- self.assertEqual(security.enable_mixed_content_blocking_button.get_property('localName'),
- 'button')
-
- self.assertEqual(security.more_info_button.get_property('localName'), 'button')
-
- def test_open_close(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.assertFalse(self.identity_popup.is_open)
-
- self.locationbar.open_identity_popup()
-
- self.identity_popup.close()
- self.assertFalse(self.identity_popup.is_open)
-
- def test_force_close(self):
- with self.marionette.using_context('content'):
- self.marionette.navigate(self.url)
-
- self.assertFalse(self.identity_popup.is_open)
-
- self.locationbar.open_identity_popup()
-
- self.identity_popup.close(force=True)
- self.assertFalse(self.identity_popup.is_open)
diff --git a/testing/firefox-ui/tests/puppeteer/test_update_wizard.py b/testing/firefox-ui/tests/puppeteer/test_update_wizard.py
deleted file mode 100644
index 7170ea8e25..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_update_wizard.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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 import PuppeteerMixin
-from firefox_puppeteer.ui.deck import Panel
-from firefox_puppeteer.ui.update_wizard import UpdateWizardDialog
-from marionette_harness import MarionetteTestCase
-
-
-class TestUpdateWizard(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestUpdateWizard, self).setUp()
-
- def opener(win):
- self.marionette.execute_script("""
- let updatePrompt = Components.classes["@mozilla.org/updates/update-prompt;1"]
- .createInstance(Components.interfaces.nsIUpdatePrompt);
- updatePrompt.checkForUpdates();
- """)
-
- self.dialog = self.browser.open_window(callback=opener,
- expected_window_class=UpdateWizardDialog)
- self.wizard = self.dialog.wizard
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestUpdateWizard, self).tearDown()
-
- def test_basic(self):
- self.assertEqual(self.dialog.window_type, 'Update:Wizard')
- self.assertNotEqual(self.dialog.dtds, [])
- self.assertNotEqual(self.dialog.properties, [])
-
- def test_elements(self):
- """Test correct retrieval of elements."""
- self.assertEqual(self.wizard.element.get_property('localName'), 'wizard')
-
- buttons = ('cancel_button', 'extra1_button', 'extra2_button',
- 'finish_button', 'next_button', 'previous_button',
- )
- for button in buttons:
- self.assertEqual(getattr(self.wizard, button).get_property('localName'),
- 'button')
-
- panels = ('checking', 'downloading', 'dummy', 'error_patching', 'error',
- 'error_extra', 'finished', 'finished_background',
- 'manual_update', 'no_updates_found', 'updates_found_basic',
- )
- for panel in panels:
- self.assertEqual(getattr(self.wizard, panel).element.get_property('localName'),
- 'wizardpage')
-
- # elements of the checking panel
- self.assertEqual(self.wizard.checking.progress.get_property('localName'),
- 'progressmeter')
-
- # elements of the downloading panel
- self.assertEqual(self.wizard.downloading.progress.get_property('localName'),
- 'progressmeter')
-
- # check wizard attributes
- self.assertIsInstance(self.wizard.selected_index, int)
- self.assertIsInstance(self.wizard.selected_panel, Panel)
diff --git a/testing/firefox-ui/tests/puppeteer/test_utils.py b/testing/firefox-ui/tests/puppeteer/test_utils.py
deleted file mode 100644
index 664722cce4..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_utils.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# 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 import PuppeteerMixin
-from marionette_harness import MarionetteTestCase
-
-
-class TestSanitize(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSanitize, self).setUp()
-
- # Clear all previous history and cookies.
- self.puppeteer.places.remove_all_history()
- with self.marionette.using_context('content'):
- self.marionette.delete_all_cookies()
-
- self.urls = [
- 'layout/mozilla_projects.html',
- 'layout/mozilla.html',
- 'layout/mozilla_mission.html',
- 'cookies/cookie_single.html'
- ]
- self.urls = [self.marionette.absolute_url(url) for url in self.urls]
-
- # Open the test urls, including the single cookie setting page.
- def load_urls():
- with self.marionette.using_context('content'):
- for url in self.urls:
- self.marionette.navigate(url)
- self.puppeteer.places.wait_for_visited(self.urls, load_urls)
-
- def test_sanitize_history(self):
- """ Clears history. """
- self.assertEqual(self.puppeteer.places.get_all_urls_in_history(), self.urls)
- self.puppeteer.utils.sanitize(data_type={"history": True})
- self.assertEqual(self.puppeteer.places.get_all_urls_in_history(), [])
-
- def test_sanitize_cookies(self):
- """ Clears cookies. """
- with self.marionette.using_context('content'):
- self.assertIsNotNone(self.marionette.get_cookie('litmus_1'))
-
- self.puppeteer.utils.sanitize(data_type={"cookies": True})
-
- with self.marionette.using_context('content'):
- self.assertIsNone(self.marionette.get_cookie('litmus_1'))
diff --git a/testing/firefox-ui/tests/puppeteer/test_windows.py b/testing/firefox-ui/tests/puppeteer/test_windows.py
deleted file mode 100644
index 1ba13fa375..0000000000
--- a/testing/firefox-ui/tests/puppeteer/test_windows.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# 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 firefox_puppeteer.errors as errors
-
-from firefox_puppeteer import PuppeteerMixin
-from firefox_puppeteer.ui.windows import BaseWindow
-from marionette_driver import By, Wait
-from marionette_driver.errors import NoSuchWindowException
-from marionette_harness import MarionetteTestCase
-
-
-class BaseWindowTestCase(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- """
- These tests open and close windows pretty rapidly, which
- (since bug 1261842) can cause content processes to be
- spawned and discarded in large numbers. By default, Firefox
- has a 5 second timeout for shutting down content processes,
- but we can get into cases where the content process just
- doesn't have enough time to get itself all sorted before
- the timeout gets hit, which results in the parent killing
- the content process manually, which generates a crash report,
- which causes these tests to orange. We side-step this by
- setting dom.ipc.tabs.shutdownTimeoutSecs to 0, which disables
- the shutdown timer.
- """
- super(BaseWindowTestCase, self).setUp()
-
- self.marionette.set_pref('dom.ipc.tabs.shutdownTimeoutSecs', 0)
-
- def tearDown(self):
- try:
- self.marionette.clear_pref('dom.ipc.tabs.shutdownTimeoutSecs')
- finally:
- super(BaseWindowTestCase, self).tearDown()
-
-
-class TestWindows(BaseWindowTestCase):
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- super(TestWindows, self).tearDown()
-
- def test_switch_to(self):
- url = self.marionette.absolute_url('layout/mozilla.html')
-
- # Open two more windows
- for index in range(0, 2):
- self.marionette.execute_script(""" window.open(); """)
-
- windows = self.puppeteer.windows.all
- self.assertEquals(len(windows), 3)
-
- # Switch to the 2nd window
- self.puppeteer.windows.switch_to(windows[1].handle)
- self.assertEquals(windows[1].handle, self.marionette.current_chrome_window_handle)
-
- # TODO: Needs updated tabs module for improved navigation
- with self.marionette.using_context('content'):
- self.marionette.navigate(url)
-
- # Switch to the last window and find 2nd window by URL
- self.puppeteer.windows.switch_to(windows[2].handle)
-
- # TODO: A window can have multiple tabs, so this may need an update
- # when the tabs module gets implemented
- def find_by_url(win):
- with win.marionette.using_context('content'):
- return win.marionette.get_url() == url
-
- self.puppeteer.windows.switch_to(find_by_url)
- self.assertEquals(windows[1].handle, self.marionette.current_chrome_window_handle)
-
- self.puppeteer.windows.switch_to(find_by_url)
-
- # Switching to an unknown handles has to fail
- self.assertRaises(NoSuchWindowException,
- self.puppeteer.windows.switch_to, "humbug")
- self.assertRaises(NoSuchWindowException,
- self.puppeteer.windows.switch_to, lambda win: False)
-
- self.puppeteer.windows.close_all([self.browser])
- self.browser.switch_to()
-
- self.assertEqual(len(self.puppeteer.windows.all), 1)
-
- def test_switch_to_unknown_window_type(self):
- def open_by_js(_):
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script("""
- window.open('chrome://browser/content/safeMode.xul', '_blank',
- 'chrome,centerscreen,resizable=no');
- """)
-
- win = self.browser.open_window(callback=open_by_js, expected_window_class=BaseWindow)
- win.close()
- self.browser.switch_to()
-
-
-class TestBaseWindow(BaseWindowTestCase):
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- BaseWindowTestCase.tearDown(self)
-
- def test_basics(self):
- # force BaseWindow instance
- 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(errors.UnknownWindowError,
- 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(self.marionette, self.browser.handle)
-
- # Open a new window (will be focused), and check states
- win2 = win1.open_window()
-
- # force BaseWindow instance
- 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)
- self.assertEquals(len(self.marionette.chrome_window_handles), 1)
- self.assertEquals(win2.handle, self.marionette.current_chrome_window_handle)
- Wait(self.marionette).until(lambda _: win1.focused) # catch the no focused window
-
- win1.focus()
-
- # Open and close a new window by a custom callback
- def opener(window):
- 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(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.puppeteer.windows.close_all([win1])
-
- def test_switch_to_and_focus(self):
- # force BaseWindow instance
- 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(self.marionette, win2.handle)
-
- self.assertEquals(win2.handle, self.marionette.current_chrome_window_handle)
- self.assertEquals(win2.handle, self.puppeteer.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()
- self.assertEquals(win1.handle, self.marionette.current_chrome_window_handle)
- self.assertTrue(win2.focused)
-
- win1.focus()
- self.assertTrue(win1.focused)
-
- # Switch back to win2 by focusing it directly
- win2.focus()
- self.assertEquals(win2.handle, self.marionette.current_chrome_window_handle)
- self.assertEquals(win2.handle, self.puppeteer.windows.focused_chrome_window_handle)
- self.assertTrue(win2.focused)
-
- # Close win2, and check that it keeps active but looses focus
- win2.switch_to()
- win2.close()
-
- win1.switch_to()
-
-
-class TestBrowserWindow(BaseWindowTestCase):
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- BaseWindowTestCase.tearDown(self)
-
- def test_basic(self):
- self.assertNotEqual(self.browser.dtds, [])
- self.assertNotEqual(self.browser.properties, [])
-
- self.assertFalse(self.browser.is_private)
-
- self.assertIsNotNone(self.browser.menubar)
- self.assertIsNotNone(self.browser.navbar)
- self.assertIsNotNone(self.browser.tabbar)
-
- def test_open_close(self):
- # open and close a new browser windows by menu
- win2 = self.browser.open_browser(trigger='menu')
- self.assertEquals(win2, self.puppeteer.windows.current)
- self.assertFalse(self.browser.is_private)
- win2.close(trigger='menu')
-
- # open and close a new browser window by shortcut
- win2 = self.browser.open_browser(trigger='shortcut')
- self.assertEquals(win2, self.puppeteer.windows.current)
- self.assertFalse(self.browser.is_private)
- win2.close(trigger='shortcut')
-
- # open and close a new private browsing window
- win2 = self.browser.open_browser(is_private=True)
- self.assertEquals(win2, self.puppeteer.windows.current)
- self.assertTrue(win2.is_private)
- win2.close()
-
- # open and close a new private browsing window
- win2 = self.browser.open_browser(trigger='shortcut', is_private=True)
- self.assertEquals(win2, self.puppeteer.windows.current)
- self.assertTrue(win2.is_private)
- win2.close()
-
- # force closing a window
- win2 = self.browser.open_browser()
- self.assertEquals(win2, self.puppeteer.windows.current)
- win2.close(force=True)
diff --git a/testing/firefox-ui/tests/update/direct/manifest.ini b/testing/firefox-ui/tests/update/direct/manifest.ini
deleted file mode 100644
index f5edb3c109..0000000000
--- a/testing/firefox-ui/tests/update/direct/manifest.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-tags = direct
-
-[test_direct_update.py]
diff --git a/testing/firefox-ui/tests/update/direct/test_direct_update.py b/testing/firefox-ui/tests/update/direct/test_direct_update.py
deleted file mode 100644
index 41842349e1..0000000000
--- a/testing/firefox-ui/tests/update/direct/test_direct_update.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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_ui_harness.testcases import UpdateTestCase
-
-
-class TestDirectUpdate(UpdateTestCase):
-
- def setUp(self):
- UpdateTestCase.setUp(self, is_fallback=False)
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- UpdateTestCase.tearDown(self)
-
- def test_update(self):
- self.download_and_apply_available_update(force_fallback=False)
- self.check_update_applied()
diff --git a/testing/firefox-ui/tests/update/fallback/manifest.ini b/testing/firefox-ui/tests/update/fallback/manifest.ini
deleted file mode 100644
index 704686db7d..0000000000
--- a/testing/firefox-ui/tests/update/fallback/manifest.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-tags = fallback
-
-[test_fallback_update.py]
diff --git a/testing/firefox-ui/tests/update/fallback/test_fallback_update.py b/testing/firefox-ui/tests/update/fallback/test_fallback_update.py
deleted file mode 100644
index 264142bd82..0000000000
--- a/testing/firefox-ui/tests/update/fallback/test_fallback_update.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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_ui_harness.testcases import UpdateTestCase
-
-
-class TestFallbackUpdate(UpdateTestCase):
-
- def setUp(self):
- UpdateTestCase.setUp(self, is_fallback=True)
-
- def tearDown(self):
- try:
- self.puppeteer.windows.close_all([self.browser])
- finally:
- UpdateTestCase.tearDown(self)
-
- def test_update(self):
- self.download_and_apply_available_update(force_fallback=True)
- self.download_and_apply_forced_update()
- self.check_update_applied()
diff --git a/testing/firefox-ui/tests/update/manifest.ini b/testing/firefox-ui/tests/update/manifest.ini
deleted file mode 100644
index 2a126e3318..0000000000
--- a/testing/firefox-ui/tests/update/manifest.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[include:direct/manifest.ini]
-[include:fallback/manifest.ini]
diff --git a/testing/mach_commands.py b/testing/mach_commands.py
index 866bc530ca..a744b0c44f 100644
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -56,16 +56,6 @@ TEST_SUITES = {
'mach_command': 'crashtest',
'kwargs': {'test_file': None},
},
- 'firefox-ui-functional': {
- 'aliases': ('Fxfn',),
- 'mach_command': 'firefox-ui-functional',
- 'kwargs': {},
- },
- 'firefox-ui-update': {
- 'aliases': ('Fxup',),
- 'mach_command': 'firefox-ui-update',
- 'kwargs': {},
- },
'jetpack': {
'aliases': ('J',),
'mach_command': 'jetpack-test',
@@ -139,18 +129,6 @@ TEST_FLAVORS = {
'mach_command': 'mochitest',
'kwargs': {'flavor': 'chrome', 'test_paths': []},
},
- 'firefox-ui-functional': {
- 'mach_command': 'firefox-ui-functional',
- 'kwargs': {'tests': []},
- },
- 'firefox-ui-update': {
- 'mach_command': 'firefox-ui-update',
- 'kwargs': {'tests': []},
- },
- 'marionette': {
- 'mach_command': 'marionette-test',
- 'kwargs': {'tests': []},
- },
'mochitest': {
'mach_command': 'mochitest',
'kwargs': {'flavor': 'mochitest', 'test_paths': []},
diff --git a/testing/marionette/accessibility.js b/testing/marionette/accessibility.js
deleted file mode 100644
index 4ada0b88d3..0000000000
--- a/testing/marionette/accessibility.js
+++ /dev/null
@@ -1,441 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Log.jsm");
-
-const logger = Log.repository.getLogger("Marionette");
-
-Cu.import("chrome://marionette/content/error.js");
-
-XPCOMUtils.defineLazyModuleGetter(
- this, "setInterval", "resource://gre/modules/Timer.jsm");
-XPCOMUtils.defineLazyModuleGetter(
- this, "clearInterval", "resource://gre/modules/Timer.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "service", () => {
- let service;
- try {
- service = Cc["@mozilla.org/accessibilityService;1"].getService(
- Ci.nsIAccessibilityService);
- } catch (e) {
- logger.warn("Accessibility module is not present");
- } finally {
- return service;
- }
-});
-
-this.EXPORTED_SYMBOLS = ["accessibility"];
-
-/**
- * Number of attempts to get an accessible object for an element.
- * We attempt more than once because accessible tree can be out of sync
- * with the DOM tree for a short period of time.
- */
-const GET_ACCESSIBLE_ATTEMPTS = 100;
-
-/**
- * An interval between attempts to retrieve an accessible object for an
- * element.
- */
-const GET_ACCESSIBLE_ATTEMPT_INTERVAL = 10;
-
-this.accessibility = {
- get service() {
- return service;
- }
-};
-
-/**
- * Accessible states used to check element"s state from the accessiblity API
- * perspective.
- * Note: if gecko is built with --disable-accessibility, the interfaces are not
- * defined. This is why we use getters instead to be able to use these
- * statically.
- */
-accessibility.State = {
- get Unavailable() {
- return Ci.nsIAccessibleStates.STATE_UNAVAILABLE;
- },
- get Focusable() {
- return Ci.nsIAccessibleStates.STATE_FOCUSABLE;
- },
- get Selectable() {
- return Ci.nsIAccessibleStates.STATE_SELECTABLE;
- },
- get Selected() {
- return Ci.nsIAccessibleStates.STATE_SELECTED;
- }
-};
-
-/**
- * Accessible object roles that support some action.
- */
-accessibility.ActionableRoles = new Set([
- "checkbutton",
- "check menu item",
- "check rich option",
- "combobox",
- "combobox option",
- "entry",
- "key",
- "link",
- "listbox option",
- "listbox rich option",
- "menuitem",
- "option",
- "outlineitem",
- "pagetab",
- "pushbutton",
- "radiobutton",
- "radio menu item",
- "rowheader",
- "slider",
- "spinbutton",
- "switch",
-]);
-
-
-/**
- * Factory function that constructs a new {@code accessibility.Checks}
- * object with enforced strictness or not.
- */
-accessibility.get = function (strict = false) {
- return new accessibility.Checks(!!strict);
-};
-
-/**
- * Component responsible for interacting with platform accessibility
- * API.
- *
- * Its methods serve as wrappers for testing content and chrome
- * accessibility as well as accessibility of user interactions.
- */
-accessibility.Checks = class {
-
- /**
- * @param {boolean} strict
- * Flag indicating whether the accessibility issue should be logged
- * or cause an error to be thrown. Default is to log to stdout.
- */
- constructor(strict) {
- this.strict = strict;
- }
-
- /**
- * Get an accessible object for an element.
- *
- * @param {DOMElement|XULElement} element
- * Element to get the accessible object for.
- * @param {boolean=} mustHaveAccessible
- * Flag indicating that the element must have an accessible object.
- * Defaults to not require this.
- *
- * @return {Promise: nsIAccessible}
- * Promise with an accessibility object for the given element.
- */
- getAccessible(element, mustHaveAccessible = false) {
- if (!this.strict) {
- return Promise.resolve();
- }
-
- return new Promise((resolve, reject) => {
- if (!accessibility.service) {
- reject();
- return;
- }
-
- let acc = accessibility.service.getAccessibleFor(element);
- if (acc || !mustHaveAccessible) {
- // if accessible object is found, return it;
- // if it is not required, also resolve
- resolve(acc);
- } else {
- // if we require an accessible object, we need to poll for it
- // because accessible tree might be
- // out of sync with DOM tree for a short time
- let attempts = GET_ACCESSIBLE_ATTEMPTS;
- let intervalId = setInterval(() => {
- let acc = accessibility.service.getAccessibleFor(element);
- if (acc || --attempts <= 0) {
- clearInterval(intervalId);
- if (acc) {
- resolve(acc);
- } else {
- reject();
- }
- }
- }, GET_ACCESSIBLE_ATTEMPT_INTERVAL);
- }
- }).catch(() => this.error(
- "Element does not have an accessible object", element));
- };
-
- /**
- * Test if the accessible has a role that supports some arbitrary
- * action.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- *
- * @return {boolean}
- * True if an actionable role is found on the accessible, false
- * otherwise.
- */
- isActionableRole(accessible) {
- return accessibility.ActionableRoles.has(
- accessibility.service.getStringRole(accessible.role));
- }
-
- /**
- * Test if an accessible has at least one action that it supports.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- *
- * @return {boolean}
- * True if the accessible has at least one supported action,
- * false otherwise.
- */
- hasActionCount(accessible) {
- return accessible.actionCount > 0;
- }
-
- /**
- * Test if an accessible has a valid name.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- *
- * @return {boolean}
- * True if the accessible has a non-empty valid name, or false if
- * this is not the case.
- */
- hasValidName(accessible) {
- return accessible.name && accessible.name.trim();
- }
-
- /**
- * Test if an accessible has a {@code hidden} attribute.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- *
- * @return {boolean}
- * True if the accesible object has a {@code hidden} attribute,
- * false otherwise.
- */
- hasHiddenAttribute(accessible) {
- let hidden = false;
- try {
- hidden = accessible.attributes.getStringProperty("hidden");
- } finally {
- // if the property is missing, error will be thrown
- return hidden && hidden === "true";
- }
- }
-
- /**
- * Verify if an accessible has a given state.
- * Test if an accessible has a given state.
- *
- * @param {nsIAccessible} accessible
- * Accessible object to test.
- * @param {number} stateToMatch
- * State to match.
- *
- * @return {boolean}
- * True if |accessible| has |stateToMatch|, false otherwise.
- */
- matchState(accessible, stateToMatch) {
- let state = {};
- accessible.getState(state, {});
- return !!(state.value & stateToMatch);
- }
-
- /**
- * Test if an accessible is hidden from the user.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- *
- * @return {boolean}
- * True if element is hidden from user, false otherwise.
- */
- isHidden(accessible) {
- while (accessible) {
- if (this.hasHiddenAttribute(accessible)) {
- return true;
- }
- accessible = accessible.parent;
- }
- return false;
- }
-
- /**
- * Test if the element's visible state corresponds to its accessibility
- * API visibility.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- * @param {DOMElement|XULElement} element
- * Element associated with |accessible|.
- * @param {boolean} visible
- * Visibility state of |element|.
- *
- * @throws ElementNotAccessibleError
- * If |element|'s visibility state does not correspond to
- * |accessible|'s.
- */
- assertVisible(accessible, element, visible) {
- if (!accessible) {
- return;
- }
-
- let hiddenAccessibility = this.isHidden(accessible);
-
- let message;
- if (visible && hiddenAccessibility) {
- message = "Element is not currently visible via the accessibility API " +
- "and may not be manipulated by it";
- } else if (!visible && !hiddenAccessibility) {
- message = "Element is currently only visible via the accessibility API " +
- "and can be manipulated by it";
- }
- this.error(message, element);
- }
-
- /**
- * Test if the element's unavailable accessibility state matches the
- * enabled state.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- * @param {DOMElement|XULElement} element
- * Element associated with |accessible|.
- * @param {boolean} enabled
- * Enabled state of |element|.
- *
- * @throws ElementNotAccessibleError
- * If |element|'s enabled state does not match |accessible|'s.
- */
- assertEnabled(accessible, element, enabled) {
- if (!accessible) {
- return;
- }
-
- let win = element.ownerDocument.defaultView;
- let disabledAccessibility = this.matchState(
- accessible, accessibility.State.Unavailable);
- let explorable = win.getComputedStyle(element)
- .getPropertyValue("pointer-events") !== "none";
-
- let message;
- if (!explorable && !disabledAccessibility) {
- message = "Element is enabled but is not explorable via the " +
- "accessibility API";
- } else if (enabled && disabledAccessibility) {
- message = "Element is enabled but disabled via the accessibility API";
- } else if (!enabled && !disabledAccessibility) {
- message = "Element is disabled but enabled via the accessibility API";
- }
- this.error(message, element);
- }
-
- /**
- * Test if it is possible to activate an element with the accessibility
- * API.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- * @param {DOMElement|XULElement} element
- * Element associated with |accessible|.
- *
- * @throws ElementNotAccessibleError
- * If it is impossible to activate |element| with |accessible|.
- */
- assertActionable(accessible, element) {
- if (!accessible) {
- return;
- }
-
- let message;
- if (!this.hasActionCount(accessible)) {
- message = "Element does not support any accessible actions";
- } else if (!this.isActionableRole(accessible)) {
- message = "Element does not have a correct accessibility role " +
- "and may not be manipulated via the accessibility API";
- } else if (!this.hasValidName(accessible)) {
- message = "Element is missing an accessible name";
- } else if (!this.matchState(accessible, accessibility.State.Focusable)) {
- message = "Element is not focusable via the accessibility API";
- }
-
- this.error(message, element);
- }
-
- /**
- * Test that an element's selected state corresponds to its
- * accessibility API selected state.
- *
- * @param {nsIAccessible} accessible
- * Accessible object.
- * @param {DOMElement|XULElement}
- * Element associated with |accessible|.
- * @param {boolean} selected
- * The |element|s selected state.
- *
- * @throws ElementNotAccessibleError
- * If |element|'s selected state does not correspond to
- * |accessible|'s.
- */
- assertSelected(accessible, element, selected) {
- if (!accessible) {
- return;
- }
-
- // element is not selectable via the accessibility API
- if (!this.matchState(accessible, accessibility.State.Selectable)) {
- return;
- }
-
- let selectedAccessibility = this.matchState(accessible, accessibility.State.Selected);
-
- let message;
- if (selected && !selectedAccessibility) {
- message = "Element is selected but not selected via the accessibility API";
- } else if (!selected && selectedAccessibility) {
- message = "Element is not selected but selected via the accessibility API";
- }
- this.error(message, element);
- }
-
- /**
- * Throw an error if strict accessibility checks are enforced and log
- * the error to the log.
- *
- * @param {string} message
- * @param {DOMElement|XULElement} element
- * Element that caused an error.
- *
- * @throws ElementNotAccessibleError
- * If |strict| is true.
- */
- error(message, element) {
- if (!message || !this.strict) {
- return;
- }
- if (element) {
- let {id, tagName, className} = element;
- message += `: id: ${id}, tagName: ${tagName}, className: ${className}`;
- }
-
- throw new ElementNotAccessibleError(message);
- }
-
-};
diff --git a/testing/marionette/action.js b/testing/marionette/action.js
deleted file mode 100644
index 2eb39810be..0000000000
--- a/testing/marionette/action.js
+++ /dev/null
@@ -1,1348 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Task.jsm");
-
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/event.js");
-
-this.EXPORTED_SYMBOLS = ["action"];
-
-// TODO? With ES 2016 and Symbol you can make a safer approximation
-// to an enum e.g. https://gist.github.com/xmlking/e86e4f15ec32b12c4689
-/**
- * Implements WebDriver Actions API: a low-level interface for providing
- * virtualised device input to the web browser.
- */
-this.action = {
- Pause: "pause",
- KeyDown: "keyDown",
- KeyUp: "keyUp",
- PointerDown: "pointerDown",
- PointerUp: "pointerUp",
- PointerMove: "pointerMove",
- PointerCancel: "pointerCancel",
-};
-
-const ACTIONS = {
- none: new Set([action.Pause]),
- key: new Set([action.Pause, action.KeyDown, action.KeyUp]),
- pointer: new Set([
- action.Pause,
- action.PointerDown,
- action.PointerUp,
- action.PointerMove,
- action.PointerCancel,
- ]),
-};
-
-/** Map from normalized key value to UI Events modifier key name */
-const MODIFIER_NAME_LOOKUP = {
- "Alt": "alt",
- "Shift": "shift",
- "Control": "ctrl",
- "Meta": "meta",
-};
-
-/** Map from raw key (codepoint) to normalized key value */
-const NORMALIZED_KEY_LOOKUP = {
- "\uE000": "Unidentified",
- "\uE001": "Cancel",
- "\uE002": "Help",
- "\uE003": "Backspace",
- "\uE004": "Tab",
- "\uE005": "Clear",
- "\uE006": "Return",
- "\uE007": "Enter",
- "\uE008": "Shift",
- "\uE009": "Control",
- "\uE00A": "Alt",
- "\uE00B": "Pause",
- "\uE00C": "Escape",
- "\uE00D": " ",
- "\uE00E": "PageUp",
- "\uE00F": "PageDown",
- "\uE010": "End",
- "\uE011": "Home",
- "\uE012": "ArrowLeft",
- "\uE013": "ArrowUp",
- "\uE014": "ArrowRight",
- "\uE015": "ArrowDown",
- "\uE016": "Insert",
- "\uE017": "Delete",
- "\uE018": ";",
- "\uE019": "=",
- "\uE01A": "0",
- "\uE01B": "1",
- "\uE01C": "2",
- "\uE01D": "3",
- "\uE01E": "4",
- "\uE01F": "5",
- "\uE020": "6",
- "\uE021": "7",
- "\uE022": "8",
- "\uE023": "9",
- "\uE024": "*",
- "\uE025": "+",
- "\uE026": ",",
- "\uE027": "-",
- "\uE028": ".",
- "\uE029": "/",
- "\uE031": "F1",
- "\uE032": "F2",
- "\uE033": "F3",
- "\uE034": "F4",
- "\uE035": "F5",
- "\uE036": "F6",
- "\uE037": "F7",
- "\uE038": "F8",
- "\uE039": "F9",
- "\uE03A": "F10",
- "\uE03B": "F11",
- "\uE03C": "F12",
- "\uE03D": "Meta",
- "\uE040": "ZenkakuHankaku",
- "\uE050": "Shift",
- "\uE051": "Control",
- "\uE052": "Alt",
- "\uE053": "Meta",
- "\uE054": "PageUp",
- "\uE055": "PageDown",
- "\uE056": "End",
- "\uE057": "Home",
- "\uE058": "ArrowLeft",
- "\uE059": "ArrowUp",
- "\uE05A": "ArrowRight",
- "\uE05B": "ArrowDown",
- "\uE05C": "Insert",
- "\uE05D": "Delete",
-};
-
-/** Map from raw key (codepoint) to key location */
-const KEY_LOCATION_LOOKUP = {
- "\uE007": 1,
- "\uE008": 1,
- "\uE009": 1,
- "\uE00A": 1,
- "\uE01A": 3,
- "\uE01B": 3,
- "\uE01C": 3,
- "\uE01D": 3,
- "\uE01E": 3,
- "\uE01F": 3,
- "\uE020": 3,
- "\uE021": 3,
- "\uE022": 3,
- "\uE023": 3,
- "\uE024": 3,
- "\uE025": 3,
- "\uE026": 3,
- "\uE027": 3,
- "\uE028": 3,
- "\uE029": 3,
- "\uE03D": 1,
- "\uE050": 2,
- "\uE051": 2,
- "\uE052": 2,
- "\uE053": 2,
- "\uE054": 3,
- "\uE055": 3,
- "\uE056": 3,
- "\uE057": 3,
- "\uE058": 3,
- "\uE059": 3,
- "\uE05A": 3,
- "\uE05B": 3,
- "\uE05C": 3,
- "\uE05D": 3,
-};
-
-const KEY_CODE_LOOKUP = {
- "\uE00A": "AltLeft",
- "\uE052": "AltRight",
- "\uE015": "ArrowDown",
- "\uE012": "ArrowLeft",
- "\uE014": "ArrowRight",
- "\uE013": "ArrowUp",
- "`": "Backquote",
- "~": "Backquote",
- "\\": "Backslash",
- "|": "Backslash",
- "\uE003": "Backspace",
- "[": "BracketLeft",
- "{": "BracketLeft",
- "]": "BracketRight",
- "}": "BracketRight",
- ",": "Comma",
- "<": "Comma",
- "\uE009": "ControlLeft",
- "\uE051": "ControlRight",
- "\uE017": "Delete",
- ")": "Digit0",
- "0": "Digit0",
- "!": "Digit1",
- "1": "Digit1",
- "2": "Digit2",
- "@": "Digit2",
- "#": "Digit3",
- "3": "Digit3",
- "$": "Digit4",
- "4": "Digit4",
- "%": "Digit5",
- "5": "Digit5",
- "6": "Digit6",
- "^": "Digit6",
- "&": "Digit7",
- "7": "Digit7",
- "*": "Digit8",
- "8": "Digit8",
- "(": "Digit9",
- "9": "Digit9",
- "\uE010": "End",
- "\uE006": "Enter",
- "+": "Equal",
- "=": "Equal",
- "\uE00C": "Escape",
- "\uE031": "F1",
- "\uE03A": "F10",
- "\uE03B": "F11",
- "\uE03C": "F12",
- "\uE032": "F2",
- "\uE033": "F3",
- "\uE034": "F4",
- "\uE035": "F5",
- "\uE036": "F6",
- "\uE037": "F7",
- "\uE038": "F8",
- "\uE039": "F9",
- "\uE002": "Help",
- "\uE011": "Home",
- "\uE016": "Insert",
- "<": "IntlBackslash",
- ">": "IntlBackslash",
- "A": "KeyA",
- "a": "KeyA",
- "B": "KeyB",
- "b": "KeyB",
- "C": "KeyC",
- "c": "KeyC",
- "D": "KeyD",
- "d": "KeyD",
- "E": "KeyE",
- "e": "KeyE",
- "F": "KeyF",
- "f": "KeyF",
- "G": "KeyG",
- "g": "KeyG",
- "H": "KeyH",
- "h": "KeyH",
- "I": "KeyI",
- "i": "KeyI",
- "J": "KeyJ",
- "j": "KeyJ",
- "K": "KeyK",
- "k": "KeyK",
- "L": "KeyL",
- "l": "KeyL",
- "M": "KeyM",
- "m": "KeyM",
- "N": "KeyN",
- "n": "KeyN",
- "O": "KeyO",
- "o": "KeyO",
- "P": "KeyP",
- "p": "KeyP",
- "Q": "KeyQ",
- "q": "KeyQ",
- "R": "KeyR",
- "r": "KeyR",
- "S": "KeyS",
- "s": "KeyS",
- "T": "KeyT",
- "t": "KeyT",
- "U": "KeyU",
- "u": "KeyU",
- "V": "KeyV",
- "v": "KeyV",
- "W": "KeyW",
- "w": "KeyW",
- "X": "KeyX",
- "x": "KeyX",
- "Y": "KeyY",
- "y": "KeyY",
- "Z": "KeyZ",
- "z": "KeyZ",
- "-": "Minus",
- "_": "Minus",
- "\uE01A": "Numpad0",
- "\uE05C": "Numpad0",
- "\uE01B": "Numpad1",
- "\uE056": "Numpad1",
- "\uE01C": "Numpad2",
- "\uE05B": "Numpad2",
- "\uE01D": "Numpad3",
- "\uE055": "Numpad3",
- "\uE01E": "Numpad4",
- "\uE058": "Numpad4",
- "\uE01F": "Numpad5",
- "\uE020": "Numpad6",
- "\uE05A": "Numpad6",
- "\uE021": "Numpad7",
- "\uE057": "Numpad7",
- "\uE022": "Numpad8",
- "\uE059": "Numpad8",
- "\uE023": "Numpad9",
- "\uE054": "Numpad9",
- "\uE024": "NumpadAdd",
- "\uE026": "NumpadComma",
- "\uE028": "NumpadDecimal",
- "\uE05D": "NumpadDecimal",
- "\uE029": "NumpadDivide",
- "\uE007": "NumpadEnter",
- "\uE024": "NumpadMultiply",
- "\uE026": "NumpadSubtract",
- "\uE03D": "OSLeft",
- "\uE053": "OSRight",
- "\uE01E": "PageDown",
- "\uE01F": "PageUp",
- ".": "Period",
- ">": "Period",
- "\"": "Quote",
- "'": "Quote",
- ":": "Semicolon",
- ";": "Semicolon",
- "\uE008": "ShiftLeft",
- "\uE050": "ShiftRight",
- "/": "Slash",
- "?": "Slash",
- "\uE00D": "Space",
- " ": "Space",
- "\uE004": "Tab",
-};
-
-/** Represents possible values for a pointer-move origin. */
-action.PointerOrigin = {
- Viewport: "viewport",
- Pointer: "pointer",
-};
-
-/**
- * Look up a PointerOrigin.
- *
- * @param {?} obj
- * Origin for a pointerMove action.
- *
- * @return {?}
- * A pointer origin that is either "viewport" (default), "pointer", or a
- * web-element reference.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not a valid origin.
- */
-action.PointerOrigin.get = function(obj) {
- let origin = obj;
- if (typeof obj == "undefined") {
- origin = this.Viewport;
- } else if (typeof obj == "string") {
- let name = capitalize(obj);
- assert.in(name, this, error.pprint`Unknown pointer-move origin: ${obj}`);
- origin = this[name];
- } else if (!element.isWebElementReference(obj)) {
- throw new InvalidArgumentError("Expected 'origin' to be a string or a " +
- `web element reference, got: ${obj}`);
- }
- return origin;
-};
-
-/** Represents possible subtypes for a pointer input source. */
-action.PointerType = {
- Mouse: "mouse",
- // TODO For now, only mouse is supported
- //Pen: "pen",
- //Touch: "touch",
-};
-
-/**
- * Look up a PointerType.
- *
- * @param {string} str
- * Name of pointer type.
- *
- * @return {string}
- * A pointer type for processing pointer parameters.
- *
- * @throws {InvalidArgumentError}
- * If |str| is not a valid pointer type.
- */
-action.PointerType.get = function (str) {
- let name = capitalize(str);
- assert.in(name, this, error.pprint`Unknown pointerType: ${str}`);
- return this[name];
-};
-
-/**
- * Input state associated with current session. This is a map between input ID and
- * the device state for that input source, with one entry for each active input source.
- *
- * Initialized in listener.js
- */
-action.inputStateMap = undefined;
-
-/**
- * List of |action.Action| associated with current session. Used to manage dispatching
- * events when resetting the state of the input sources. Reset operations are assumed
- * to be idempotent.
- *
- * Initialized in listener.js
- */
-action.inputsToCancel = undefined;
-
-/**
- * Represents device state for an input source.
- */
-class InputState {
- constructor() {
- this.type = this.constructor.name.toLowerCase();
- }
-
- /**
- * Check equality of this InputState object with another.
- *
- * @para{?} other
- * Object representing an input state.
- * @return {boolean}
- * True if |this| has the same |type| as |other|.
- */
- is(other) {
- if (typeof other == "undefined") {
- return false;
- }
- return this.type === other.type;
- }
-
- toString() {
- return `[object ${this.constructor.name}InputState]`;
- }
-
- /**
- * @param {?} obj
- * Object with property |type| and optionally |parameters| or |pointerType|,
- * representing an action sequence or an action item.
- *
- * @return {action.InputState}
- * An |action.InputState| object for the type of the |actionSequence|.
- *
- * @throws {InvalidArgumentError}
- * If |actionSequence.type| is not valid.
- */
- static fromJson(obj) {
- let type = obj.type;
- assert.in(type, ACTIONS, error.pprint`Unknown action type: ${type}`);
- let name = type == "none" ? "Null" : capitalize(type);
- if (name == "Pointer") {
- if (!obj.pointerType && (!obj.parameters || !obj.parameters.pointerType)) {
- throw new InvalidArgumentError(
- error.pprint`Expected obj to have pointerType, got: ${obj}`);
- }
- let pointerType = obj.pointerType || obj.parameters.pointerType;
- return new action.InputState[name](pointerType);
- } else {
- return new action.InputState[name]();
- }
- }
-}
-
-/** Possible kinds of |InputState| for supported input sources. */
-action.InputState = {};
-
-/**
- * Input state associated with a keyboard-type device.
- */
-action.InputState.Key = class Key extends InputState {
- constructor() {
- super();
- this.pressed = new Set();
- this.alt = false;
- this.shift = false;
- this.ctrl = false;
- this.meta = false;
- }
-
- /**
- * Update modifier state according to |key|.
- *
- * @param {string} key
- * Normalized key value of a modifier key.
- * @param {boolean} value
- * Value to set the modifier attribute to.
- *
- * @throws {InvalidArgumentError}
- * If |key| is not a modifier.
- */
- setModState(key, value) {
- if (key in MODIFIER_NAME_LOOKUP) {
- this[MODIFIER_NAME_LOOKUP[key]] = value;
- } else {
- throw new InvalidArgumentError("Expected 'key' to be one of " +
- `${Object.keys(MODIFIER_NAME_LOOKUP)}; got: ${key}`);
- }
- }
-
- /**
- * Check whether |key| is pressed.
- *
- * @param {string} key
- * Normalized key value.
- *
- * @return {boolean}
- * True if |key| is in set of pressed keys.
- */
- isPressed(key) {
- return this.pressed.has(key);
- }
-
- /**
- * Add |key| to the set of pressed keys.
- *
- * @param {string} key
- * Normalized key value.
- *
- * @return {boolean}
- * True if |key| is in list of pressed keys.
- */
- press(key) {
- return this.pressed.add(key);
- }
-
- /**
- * Remove |key| from the set of pressed keys.
- *
- * @param {string} key
- * Normalized key value.
- *
- * @return {boolean}
- * True if |key| was present before removal, false otherwise.
- */
- release(key) {
- return this.pressed.delete(key);
- }
-};
-
-/**
- * Input state not associated with a specific physical device.
- */
-action.InputState.Null = class Null extends InputState {
- constructor() {
- super();
- this.type = "none";
- }
-};
-
-/**
- * Input state associated with a pointer-type input device.
- *
- * @param {string} subtype
- * Kind of pointing device: mouse, pen, touch.
- *
- * @throws {InvalidArgumentError}
- * If subtype is undefined or an invalid pointer type.
- */
-action.InputState.Pointer = class Pointer extends InputState {
- constructor(subtype) {
- super();
- this.pressed = new Set();
- assert.defined(subtype, error.pprint`Expected subtype to be defined, got: ${subtype}`);
- this.subtype = action.PointerType.get(subtype);
- this.x = 0;
- this.y = 0;
- }
-
- /**
- * Check whether |button| is pressed.
- *
- * @param {number} button
- * Positive integer that refers to a mouse button.
- *
- * @return {boolean}
- * True if |button| is in set of pressed buttons.
- */
- isPressed(button) {
- assert.positiveInteger(button);
- return this.pressed.has(button);
- }
-
- /**
- * Add |button| to the set of pressed keys.
- *
- * @param {number} button
- * Positive integer that refers to a mouse button.
- *
- * @return {Set}
- * Set of pressed buttons.
- */
- press(button) {
- assert.positiveInteger(button);
- return this.pressed.add(button);
- }
-
- /**
- * Remove |button| from the set of pressed buttons.
- *
- * @param {number} button
- * A positive integer that refers to a mouse button.
- *
- * @return {boolean}
- * True if |button| was present before removals, false otherwise.
- */
- release(button) {
- assert.positiveInteger(button);
- return this.pressed.delete(button);
- }
-};
-
-/**
- * Repesents an action for dispatch. Used in |action.Chain| and |action.Sequence|.
- *
- * @param {string} id
- * Input source ID.
- * @param {string} type
- * Action type: none, key, pointer.
- * @param {string} subtype
- * Action subtype: pause, keyUp, keyDown, pointerUp, pointerDown, pointerMove, pointerCancel.
- *
- * @throws {InvalidArgumentError}
- * If any parameters are undefined.
- */
-action.Action = class {
- constructor(id, type, subtype) {
- if ([id, type, subtype].includes(undefined)) {
- throw new InvalidArgumentError("Missing id, type or subtype");
- }
- for (let attr of [id, type, subtype]) {
- assert.string(attr, error.pprint`Expected string, got: ${attr}`);
- }
- this.id = id;
- this.type = type;
- this.subtype = subtype;
- };
-
- toString() {
- return `[action ${this.type}]`;
- }
-
- /**
- * @param {?} actionSequence
- * Object representing sequence of actions from one input source.
- * @param {?} actionItem
- * Object representing a single action from |actionSequence|.
- *
- * @return {action.Action}
- * An action that can be dispatched; corresponds to |actionItem|.
- *
- * @throws {InvalidArgumentError}
- * If any |actionSequence| or |actionItem| attributes are invalid.
- * @throws {UnsupportedOperationError}
- * If |actionItem.type| is |pointerCancel|.
- */
- static fromJson(actionSequence, actionItem) {
- let type = actionSequence.type;
- let id = actionSequence.id;
- let subtypes = ACTIONS[type];
- if (!subtypes) {
- throw new InvalidArgumentError("Unknown type: " + type);
- }
- let subtype = actionItem.type;
- if (!subtypes.has(subtype)) {
- throw new InvalidArgumentError(`Unknown subtype for ${type} action: ${subtype}`);
- }
-
- let item = new action.Action(id, type, subtype);
- if (type === "pointer") {
- action.processPointerAction(id,
- action.PointerParameters.fromJson(actionSequence.parameters), item);
- }
-
- switch (item.subtype) {
- case action.KeyUp:
- case action.KeyDown:
- let key = actionItem.value;
- // TODO countGraphemes
- // TODO key.value could be a single code point like "\uE012" (see rawKey)
- // or "grapheme cluster"
- assert.string(key,
- error.pprint("Expected 'value' to be a string that represents single code point " +
- `or grapheme cluster, got: ${key}`));
- item.value = key;
- break;
-
- case action.PointerDown:
- case action.PointerUp:
- assert.positiveInteger(actionItem.button,
- error.pprint`Expected 'button' (${actionItem.button}) to be >= 0`);
- item.button = actionItem.button;
- break;
-
- case action.PointerMove:
- item.duration = actionItem.duration;
- if (typeof item.duration != "undefined"){
- assert.positiveInteger(item.duration,
- error.pprint`Expected 'duration' (${item.duration}) to be >= 0`);
- }
- item.origin = action.PointerOrigin.get(actionItem.origin);
- item.x = actionItem.x;
- if (typeof item.x != "undefined") {
- assert.integer(item.x, error.pprint`Expected 'x' (${item.x}) to be an Integer`);
- }
- item.y = actionItem.y;
- if (typeof item.y != "undefined") {
- assert.integer(item.y, error.pprint`Expected 'y' (${item.y}) to be an Integer`);
- }
- break;
-
- case action.PointerCancel:
- throw new UnsupportedOperationError();
- break;
-
- case action.Pause:
- item.duration = actionItem.duration;
- if (typeof item.duration != "undefined") {
- assert.positiveInteger(item.duration,
- error.pprint`Expected 'duration' (${item.duration}) to be >= 0`);
- }
- break;
- }
-
- return item;
- }
-};
-
-/**
- * Represents a series of ticks, specifying which actions to perform at each tick.
- */
-action.Chain = class extends Array {
- toString() {
- return `[chain ${super.toString()}]`;
- }
-
- /**
- * @param {Array.<?>} actions
- * Array of objects that each represent an action sequence.
- *
- * @return {action.Chain}
- * Transpose of |actions| such that actions to be performed in a single tick
- * are grouped together.
- *
- * @throws {InvalidArgumentError}
- * If |actions| is not an Array.
- */
- static fromJson(actions) {
- assert.array(actions,
- error.pprint`Expected 'actions' to be an Array, got: ${actions}`);
- let actionsByTick = new action.Chain();
- // TODO check that each actionSequence in actions refers to a different input ID
- for (let actionSequence of actions) {
- let inputSourceActions = action.Sequence.fromJson(actionSequence);
- for (let i = 0; i < inputSourceActions.length; i++) {
- // new tick
- if (actionsByTick.length < (i + 1)) {
- actionsByTick.push([]);
- }
- actionsByTick[i].push(inputSourceActions[i]);
- }
- }
- return actionsByTick;
- }
-};
-
-/**
- * Represents one input source action sequence; this is essentially an |Array.<action.Action>|.
- */
-action.Sequence = class extends Array {
- toString() {
- return `[sequence ${super.toString()}]`;
- }
-
- /**
- * @param {?} actionSequence
- * Object that represents a sequence action items for one input source.
- *
- * @return {action.Sequence}
- * Sequence of actions that can be dispatched.
- *
- * @throws {InvalidArgumentError}
- * If |actionSequence.id| is not a string or it's aleady mapped
- * to an |action.InputState} incompatible with |actionSequence.type|.
- * If |actionSequence.actions| is not an Array.
- */
- static fromJson(actionSequence) {
- // used here to validate 'type' in addition to InputState type below
- let inputSourceState = InputState.fromJson(actionSequence);
- let id = actionSequence.id;
- assert.defined(id, "Expected 'id' to be defined");
- assert.string(id, error.pprint`Expected 'id' to be a string, got: ${id}`);
- let actionItems = actionSequence.actions;
- assert.array(actionItems,
- error.pprint("Expected 'actionSequence.actions' to be an Array, " +
- `got: ${actionSequence.actions}`));
- if (!action.inputStateMap.has(id)) {
- action.inputStateMap.set(id, inputSourceState);
- } else if (!action.inputStateMap.get(id).is(inputSourceState)) {
- throw new InvalidArgumentError(
- `Expected ${id} to be mapped to ${inputSourceState}, ` +
- `got: ${action.inputStateMap.get(id)}`);
- }
- let actions = new action.Sequence();
- for (let actionItem of actionItems) {
- actions.push(action.Action.fromJson(actionSequence, actionItem));
- }
- return actions;
- }
-};
-
-/**
- * Represents parameters in an action for a pointer input source.
- *
- * @param {string=} pointerType
- * Type of pointing device. If the parameter is undefined, "mouse" is used.
- */
-action.PointerParameters = class {
- constructor(pointerType = "mouse") {
- this.pointerType = action.PointerType.get(pointerType);
- }
-
- toString() {
- return `[pointerParameters ${this.pointerType}]`;
- }
-
- /**
- * @param {?} parametersData
- * Object that represents pointer parameters.
- *
- * @return {action.PointerParameters}
- * Validated pointer paramters.
- */
- static fromJson(parametersData) {
- if (typeof parametersData == "undefined") {
- return new action.PointerParameters();
- } else {
- return new action.PointerParameters(parametersData.pointerType);
- }
- }
-};
-
-/**
- * Adds |pointerType| attribute to Action |act|. Helper function
- * for |action.Action.fromJson|.
- *
- * @param {string} id
- * Input source ID.
- * @param {action.PointerParams} pointerParams
- * Input source pointer parameters.
- * @param {action.Action} act
- * Action to be updated.
- *
- * @throws {InvalidArgumentError}
- * If |id| is already mapped to an |action.InputState| that is
- * not compatible with |act.type| or |pointerParams.pointerType|.
- */
-action.processPointerAction = function processPointerAction(id, pointerParams, act) {
- if (action.inputStateMap.has(id) && action.inputStateMap.get(id).type !== act.type) {
- throw new InvalidArgumentError(
- `Expected 'id' ${id} to be mapped to InputState whose type is ` +
- `${action.inputStateMap.get(id).type}, got: ${act.type}`);
- }
- let pointerType = pointerParams.pointerType;
- if (action.inputStateMap.has(id) && action.inputStateMap.get(id).subtype !== pointerType) {
- throw new InvalidArgumentError(
- `Expected 'id' ${id} to be mapped to InputState whose subtype is ` +
- `${action.inputStateMap.get(id).subtype}, got: ${pointerType}`);
- }
- act.pointerType = pointerParams.pointerType;
-};
-
-/** Collect properties associated with KeyboardEvent */
-action.Key = class {
- constructor(rawKey) {
- this.key = NORMALIZED_KEY_LOOKUP[rawKey] || rawKey;
- this.code = KEY_CODE_LOOKUP[rawKey];
- this.location = KEY_LOCATION_LOOKUP[rawKey] || 0;
- this.altKey = false;
- this.shiftKey = false;
- this.ctrlKey = false;
- this.metaKey = false;
- this.repeat = false;
- this.isComposing = false;
- // Prevent keyCode from being guessed in event.js; we don't want to use it anyway.
- this.keyCode = 0;
- }
-
- update(inputState) {
- this.altKey = inputState.alt;
- this.shiftKey = inputState.shift;
- this.ctrlKey = inputState.ctrl;
- this.metaKey = inputState.meta;
- }
-};
-
-/** Collect properties associated with MouseEvent */
-action.Mouse = class {
- constructor(type, button = 0) {
- this.type = type;
- assert.positiveInteger(button);
- this.button = button;
- this.buttons = 0;
- }
-
- update(inputState) {
- let allButtons = Array.from(inputState.pressed);
- this.buttons = allButtons.reduce((a, i) => a + Math.pow(2, i), 0);
- }
-};
-
-/**
- * Dispatch a chain of actions over |chain.length| ticks.
- *
- * This is done by creating a Promise for each tick that resolves once all the
- * Promises for individual tick-actions are resolved. The next tick's actions are
- * not dispatched until the Promise for the current tick is resolved.
- *
- * @param {action.Chain} chain
- * Actions grouped by tick; each element in |chain| is a sequence of
- * actions for one tick.
- * @param {element.Store} seenEls
- * Element store.
- * @param {?} container
- * Object with |frame| attribute of type |nsIDOMWindow|.
- *
- * @return {Promise}
- * Promise for dispatching all actions in |chain|.
- */
-action.dispatch = function(chain, seenEls, container) {
- let chainEvents = Task.spawn(function*() {
- for (let tickActions of chain) {
- yield action.dispatchTickActions(
- tickActions, action.computeTickDuration(tickActions), seenEls, container);
- }
- });
- return chainEvents;
-};
-
-/**
- * Dispatch sequence of actions for one tick.
- *
- * This creates a Promise for one tick that resolves once the Promise for each
- * tick-action is resolved, which takes at least |tickDuration| milliseconds.
- * The resolved set of events for each tick is followed by firing of pending DOM events.
- *
- * Note that the tick-actions are dispatched in order, but they may have different
- * durations and therefore may not end in the same order.
- *
- * @param {Array.<action.Action>} tickActions
- * List of actions for one tick.
- * @param {number} tickDuration
- * Duration in milliseconds of this tick.
- * @param {element.Store} seenEls
- * Element store.
- * @param {?} container
- * Object with |frame| attribute of type |nsIDOMWindow|.
- *
- * @return {Promise}
- * Promise for dispatching all tick-actions and pending DOM events.
- */
-action.dispatchTickActions = function(tickActions, tickDuration, seenEls, container) {
- let pendingEvents = tickActions.map(toEvents(tickDuration, seenEls, container));
- return Promise.all(pendingEvents).then(() => flushEvents(container));
-};
-
-/**
- * Compute tick duration in milliseconds for a collection of actions.
- *
- * @param {Array.<action.Action>} tickActions
- * List of actions for one tick.
- *
- * @return {number}
- * Longest action duration in |tickActions| if any, or 0.
- */
-action.computeTickDuration = function(tickActions) {
- let max = 0;
- for (let a of tickActions) {
- let affectsWallClockTime = a.subtype == action.Pause ||
- (a.type == "pointer" && a.subtype == action.PointerMove);
- if (affectsWallClockTime && a.duration) {
- max = Math.max(a.duration, max);
- }
- }
- return max;
-};
-
-/**
- * Compute viewport coordinates of pointer target based on given origin.
- *
- * @param {action.Action} a
- * Action that specifies pointer origin and x and y coordinates of target.
- * @param {action.InputState} inputState
- * Input state that specifies current x and y coordinates of pointer.
- * @param {Map.<string, number>=} center
- * Object representing x and y coordinates of an element center-point.
- * This is only used if |a.origin| is a web element reference.
- *
- * @return {Map.<string, number>}
- * x and y coordinates of pointer destination.
- */
-action.computePointerDestination = function(a, inputState, center = undefined) {
- let {x, y} = a;
- switch (a.origin) {
- case action.PointerOrigin.Viewport:
- break;
- case action.PointerOrigin.Pointer:
- x += inputState.x;
- y += inputState.y;
- break;
- default:
- // origin represents web element
- assert.defined(center);
- assert.in("x", center);
- assert.in("y", center);
- x += center.x;
- y += center.y;
- }
- return {"x": x, "y": y};
-};
-
-/**
- * Create a closure to use as a map from action definitions to Promise events.
- *
- * @param {number} tickDuration
- * Duration in milliseconds of this tick.
- * @param {element.Store} seenEls
- * Element store.
- * @param {?} container
- * Object with |frame| attribute of type |nsIDOMWindow|.
- *
- * @return {function(action.Action): Promise}
- * Function that takes an action and returns a Promise for dispatching
- * the event that corresponds to that action.
- */
-function toEvents(tickDuration, seenEls, container) {
- return function (a) {
- let inputState = action.inputStateMap.get(a.id);
- switch (a.subtype) {
- case action.KeyUp:
- return dispatchKeyUp(a, inputState, container.frame);
-
- case action.KeyDown:
- return dispatchKeyDown(a, inputState, container.frame);
-
- case action.PointerDown:
- return dispatchPointerDown(a, inputState, container.frame);
-
- case action.PointerUp:
- return dispatchPointerUp(a, inputState, container.frame);
-
- case action.PointerMove:
- return dispatchPointerMove(a, inputState, tickDuration, seenEls, container);
-
- case action.PointerCancel:
- throw new UnsupportedOperationError();
-
- case action.Pause:
- return dispatchPause(a, tickDuration);
- }
- };
-}
-
-/**
- * Dispatch a keyDown action equivalent to pressing a key on a keyboard.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {action.InputState} inputState
- * Input state for this action's input source.
- * @param {nsIDOMWindow} win
- * Current window.
- *
- * @return {Promise}
- * Promise to dispatch at least a keydown event, and keypress if appropriate.
- */
-function dispatchKeyDown(a, inputState, win) {
- return new Promise(resolve => {
- let keyEvent = new action.Key(a.value);
- keyEvent.repeat = inputState.isPressed(keyEvent.key);
- inputState.press(keyEvent.key);
- if (keyEvent.key in MODIFIER_NAME_LOOKUP) {
- inputState.setModState(keyEvent.key, true);
- }
- // Append a copy of |a| with keyUp subtype
- action.inputsToCancel.push(Object.assign({}, a, {subtype: action.KeyUp}));
- keyEvent.update(inputState);
- event.sendKeyDown(keyEvent.key, keyEvent, win);
-
- resolve();
- });
-}
-
-/**
- * Dispatch a keyUp action equivalent to releasing a key on a keyboard.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {action.InputState} inputState
- * Input state for this action's input source.
- * @param {nsIDOMWindow} win
- * Current window.
- *
- * @return {Promise}
- * Promise to dispatch a keyup event.
- */
-function dispatchKeyUp(a, inputState, win) {
- return new Promise(resolve => {
- let keyEvent = new action.Key(a.value);
- if (!inputState.isPressed(keyEvent.key)) {
- resolve();
- return;
- }
- if (keyEvent.key in MODIFIER_NAME_LOOKUP) {
- inputState.setModState(keyEvent.key, false);
- }
- inputState.release(keyEvent.key);
- keyEvent.update(inputState);
- event.sendKeyUp(keyEvent.key, keyEvent, win);
-
- resolve();
- });
-}
-
-/**
- * Dispatch a pointerDown action equivalent to pressing a pointer-device
- * button.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {action.InputState} inputState
- * Input state for this action's input source.
- * @param {nsIDOMWindow} win
- * Current window.
- *
- * @return {Promise}
- * Promise to dispatch at least a pointerdown event.
- */
-function dispatchPointerDown(a, inputState, win) {
- return new Promise(resolve => {
- if (inputState.isPressed(a.button)) {
- resolve();
- return;
- }
- inputState.press(a.button);
- // Append a copy of |a| with pointerUp subtype
- action.inputsToCancel.push(Object.assign({}, a, {subtype: action.PointerUp}));
- switch (inputState.subtype) {
- case action.PointerType.Mouse:
- let mouseEvent = new action.Mouse("mousedown", a.button);
- mouseEvent.update(inputState);
- event.synthesizeMouseAtPoint(inputState.x, inputState.y, mouseEvent, win);
- break;
- case action.PointerType.Pen:
- case action.PointerType.Touch:
- throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
- break;
- default:
- throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
- }
- resolve();
- });
-}
-
-/**
- * Dispatch a pointerUp action equivalent to releasing a pointer-device
- * button.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {action.InputState} inputState
- * Input state for this action's input source.
- * @param {nsIDOMWindow} win
- * Current window.
- *
- * @return {Promise}
- * Promise to dispatch at least a pointerup event.
- */
-function dispatchPointerUp(a, inputState, win) {
- return new Promise(resolve => {
- if (!inputState.isPressed(a.button)) {
- resolve();
- return;
- }
- inputState.release(a.button);
- switch (inputState.subtype) {
- case action.PointerType.Mouse:
- let mouseEvent = new action.Mouse("mouseup", a.button);
- mouseEvent.update(inputState);
- event.synthesizeMouseAtPoint(inputState.x, inputState.y,
- mouseEvent, win);
- break;
- case action.PointerType.Pen:
- case action.PointerType.Touch:
- throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
- default:
- throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
- }
- resolve();
- });
-}
-
-/**
- * Dispatch a pointerMove action equivalent to moving pointer device in a line.
- *
- * If the action duration is 0, the pointer jumps immediately to the target coordinates.
- * Otherwise, events are synthesized to mimic a pointer travelling in a discontinuous,
- * approximately straight line, with the pointer coordinates being updated around 60
- * times per second.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {action.InputState} inputState
- * Input state for this action's input source.
- * @param {element.Store} seenEls
- * Element store.
- * @param {?} container
- * Object with |frame| attribute of type |nsIDOMWindow|.
- *
- * @return {Promise}
- * Promise to dispatch at least one pointermove event, as well as mousemove events
- * as appropriate.
- */
-function dispatchPointerMove(a, inputState, tickDuration, seenEls, container) {
- const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- // interval between pointermove increments in ms, based on common vsync
- const fps60 = 17;
- return new Promise(resolve => {
- const start = Date.now();
- const [startX, startY] = [inputState.x, inputState.y];
- let target = action.computePointerDestination(a, inputState,
- getElementCenter(a.origin, seenEls, container));
- const [targetX, targetY] = [target.x, target.y];
- if (!inViewPort(targetX, targetY, container.frame)) {
- throw new MoveTargetOutOfBoundsError(
- `(${targetX}, ${targetY}) is out of bounds of viewport ` +
- `width (${container.frame.innerWidth}) and height (${container.frame.innerHeight})`);
- }
-
- const duration = typeof a.duration == "undefined" ? tickDuration : a.duration;
- if (duration === 0) {
- // move pointer to destination in one step
- performOnePointerMove(inputState, targetX, targetY, container.frame);
- resolve();
- return;
- }
-
- const distanceX = targetX - startX;
- const distanceY = targetY - startY;
- const ONE_SHOT = Ci.nsITimer.TYPE_ONE_SHOT;
- let intermediatePointerEvents = Task.spawn(function* () {
- // wait |fps60| ms before performing first incremental pointer move
- yield new Promise(resolveTimer =>
- timer.initWithCallback(resolveTimer, fps60, ONE_SHOT)
- );
- let durationRatio = Math.floor(Date.now() - start) / duration;
- const epsilon = fps60 / duration / 10;
- while ((1 - durationRatio) > epsilon) {
- let x = Math.floor(durationRatio * distanceX + startX);
- let y = Math.floor(durationRatio * distanceY + startY);
- performOnePointerMove(inputState, x, y, container.frame);
- // wait |fps60| ms before performing next pointer move
- yield new Promise(resolveTimer =>
- timer.initWithCallback(resolveTimer, fps60, ONE_SHOT));
- durationRatio = Math.floor(Date.now() - start) / duration;
- }
- });
- // perform last pointer move after all incremental moves are resolved and
- // durationRatio is close enough to 1
- intermediatePointerEvents.then(() => {
- performOnePointerMove(inputState, targetX, targetY, container.frame);
- resolve();
- });
-
- });
-}
-
-function performOnePointerMove(inputState, targetX, targetY, win) {
- if (targetX == inputState.x && targetY == inputState.y) {
- return;
- }
- switch (inputState.subtype) {
- case action.PointerType.Mouse:
- let mouseEvent = new action.Mouse("mousemove");
- mouseEvent.update(inputState);
- //TODO both pointermove (if available) and mousemove
- event.synthesizeMouseAtPoint(targetX, targetY, mouseEvent, win);
- break;
- case action.PointerType.Pen:
- case action.PointerType.Touch:
- throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
- default:
- throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
- }
- inputState.x = targetX;
- inputState.y = targetY;
-}
-
-/**
- * Dispatch a pause action equivalent waiting for |a.duration| milliseconds, or a
- * default time interval of |tickDuration|.
- *
- * @param {action.Action} a
- * Action to dispatch.
- * @param {number} tickDuration
- * Duration in milliseconds of this tick.
- *
- * @return {Promise}
- * Promise that is resolved after the specified time interval.
- */
-function dispatchPause(a, tickDuration) {
- const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- let duration = typeof a.duration == "undefined" ? tickDuration : a.duration;
- return new Promise(resolve =>
- timer.initWithCallback(resolve, duration, Ci.nsITimer.TYPE_ONE_SHOT)
- );
-}
-
-// helpers
-/**
- * Force any pending DOM events to fire.
- *
- * @param {?} container
- * Object with |frame| attribute of type |nsIDOMWindow|.
- *
- * @return {Promise}
- * Promise to flush DOM events.
- */
-function flushEvents(container) {
- return new Promise(resolve => container.frame.requestAnimationFrame(resolve));
-}
-
-function capitalize(str) {
- assert.string(str);
- return str.charAt(0).toUpperCase() + str.slice(1);
-}
-
-function inViewPort(x, y, win) {
- assert.number(x, `Expected x to be finite number`);
- assert.number(y, `Expected y to be finite number`);
- // Viewport includes scrollbars if rendered.
- return !(x < 0 || y < 0 || x > win.innerWidth || y > win.innerHeight);
-}
-
-function getElementCenter(elementReference, seenEls, container) {
- if (element.isWebElementReference(elementReference)) {
- let uuid = elementReference[element.Key] || elementReference[element.LegacyKey];
- let el = seenEls.get(uuid, container);
- return element.coordinates(el);
- }
-}
diff --git a/testing/marionette/addon.js b/testing/marionette/addon.js
deleted file mode 100644
index d2ead6fb28..0000000000
--- a/testing/marionette/addon.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/AddonManager.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["addon"];
-
-this.addon = {};
-
-// from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
-addon.Errors = {
- [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
- [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
- [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
- [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
- [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
-};
-
-function lookupError(code) {
- let msg = addon.Errors[code];
- return new UnknownError(msg);
-}
-
-/**
- * Install a Firefox addon.
- *
- * If the addon is restartless, it can be used right away. Otherwise a
- * restart is required.
- *
- * Temporary addons will automatically be uninstalled on shutdown and
- * do not need to be signed, though they must be restartless.
- *
- * @param {string} path
- * Full path to the extension package archive.
- * @param {boolean=} temporary
- * True to install the addon temporarily, false (default) otherwise.
- *
- * @return {Promise: string}
- * Addon ID.
- *
- * @throws {UnknownError}
- * If there is a problem installing the addon.
- */
-addon.install = function (path, temporary = false) {
- return new Promise((resolve, reject) => {
- let file = new FileUtils.File(path);
-
- let listener = {
- onInstallEnded: function (install, addon) {
- resolve(addon.id);
- },
-
- onInstallFailed: function (install) {
- reject(lookupError(install.error));
- },
-
- onInstalled: function (addon) {
- AddonManager.removeAddonListener(listener);
- resolve(addon.id);
- }
- };
-
- if (!temporary) {
- AddonManager.getInstallForFile(file, function (aInstall) {
- if (aInstall.error !== 0) {
- reject(lookupError(aInstall.error));
- }
- aInstall.addListener(listener);
- aInstall.install();
- });
- } else {
- AddonManager.addAddonListener(listener);
- AddonManager.installTemporaryAddon(file);
- }
- });
-};
-
-/**
- * Uninstall a Firefox addon.
- *
- * If the addon is restartless it will be uninstalled right away.
- * Otherwise, Firefox must be restarted for the change to take effect.
- *
- * @param {string} id
- * ID of the addon to uninstall.
- *
- * @return {Promise}
- */
-addon.uninstall = function (id) {
- return new Promise(resolve => {
- AddonManager.getAddonByID(id, function (addon) {
- addon.uninstall();
- resolve();
- });
- });
-};
diff --git a/testing/marionette/assert.js b/testing/marionette/assert.js
deleted file mode 100644
index b2d228d0ef..0000000000
--- a/testing/marionette/assert.js
+++ /dev/null
@@ -1,322 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["assert"];
-
-const isFennec = () => AppConstants.platform == "android";
-const isB2G = () => false;
-const isFirefox = () => Services.appinfo.name == "Firefox";
-
-/** Shorthands for common assertions made in Marionette. */
-this.assert = {};
-
-/**
- * Asserts that Marionette has a session.
- *
- * @param {GeckoDriver} driver
- * Marionette driver instance.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {string}
- * Session ID.
- *
- * @throws {InvalidSessionIDError}
- * If |driver| does not have a session ID.
- */
-assert.session = function (driver, msg = "") {
- assert.that(sessionID => sessionID,
- msg, InvalidSessionIDError)(driver.sessionId);
- return driver.sessionId;
-};
-
-/**
- * Asserts that the current browser is Firefox Desktop.
- *
- * @param {string=} msg
- * Custom error message.
- *
- * @throws {UnsupportedOperationError}
- * If current browser is not Firefox.
- */
-assert.firefox = function (msg = "") {
- msg = msg || "Only supported in Firefox";
- assert.that(isFirefox, msg, UnsupportedOperationError)();
-};
-
-/**
- * Asserts that the current browser is Fennec, or Firefox for Android.
- *
- * @param {string=} msg
- * Custom error message.
- *
- * @throws {UnsupportedOperationError}
- * If current browser is not Fennec.
- */
-assert.fennec = function (msg = "") {
- msg = msg || "Only supported in Fennec";
- assert.that(isFennec, msg, UnsupportedOperationError)();
-};
-
-/**
- * Asserts that the current browser is B2G.
- *
- * @param {string=} msg
- * Custom error message.
- *
- * @throws {UnsupportedOperationError}
- * If the current browser is not B2G.
- */
-assert.b2g = function (msg = "") {
- msg = msg || "Only supported in B2G";
- assert.that(isB2G, msg, UnsupportedOperationError)();
-};
-
-/**
- * Asserts that the current |context| is content.
- *
- * @param {string} context
- * Context to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {string}
- * |context| is returned unaltered.
- *
- * @throws {UnsupportedOperationError}
- * If |context| is not content.
- */
-assert.content = function (context, msg = "") {
- msg = msg || "Only supported in content context";
- assert.that(c => c.toString() == "content", msg, UnsupportedOperationError)(context);
-};
-
-/**
- * Asserts that the current browser is a mobile browser, that is either
- * B2G or Fennec.
- *
- * @param {string=} msg
- * Custom error message.
- *
- * @throws {UnsupportedOperationError}
- * If the current browser is not B2G or Fennec.
- */
-assert.mobile = function (msg = "") {
- msg = msg || "Only supported in Fennec or B2G";
- assert.that(() => isFennec() || isB2G(), msg, UnsupportedOperationError)();
-};
-
-/**
- * Asserts that |obj| is defined.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {?}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not defined.
- */
-assert.defined = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be defined`;
- return assert.that(o => typeof o != "undefined", msg)(obj);
-};
-
-/**
- * Asserts that |obj| is a finite number.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {number}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not a number.
- */
-assert.number = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be finite number`;
- return assert.that(Number.isFinite, msg)(obj);
-};
-
-/**
- * Asserts that |obj| is an integer.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {number}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not an integer.
- */
-assert.integer = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be an integer`;
- return assert.that(Number.isInteger, msg)(obj);
-};
-
-/**
- * Asserts that |obj| is a positive integer.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {number}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not a positive integer.
- */
-assert.positiveInteger = function (obj, msg = "") {
- assert.integer(obj, msg);
- msg = msg || error.pprint`Expected ${obj} to be >= 0`;
- return assert.that(n => n >= 0, msg)(obj);
-};
-
-/**
- * Asserts that |obj| is a boolean.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {boolean}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not a boolean.
- */
-assert.boolean = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be boolean`;
- return assert.that(b => typeof b == "boolean", msg)(obj);
-};
-
-/**
- * Asserts that |obj| is a string.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {string}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not a string.
- */
-assert.string = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be a string`;
- return assert.that(s => typeof s == "string", msg)(obj);
-};
-
-/**
- * Asserts that |obj| is an object.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {Object}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not an object.
- */
-assert.object = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be an object`;
- return assert.that(o =>
- Object.prototype.toString.call(o) == "[object Object]", msg)(obj);
-};
-
-/**
- * Asserts that |prop| is in |obj|.
- *
- * @param {?} prop
- * Own property to test if is in |obj|.
- * @param {?} obj
- * Object.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {?}
- * Value of |obj|'s own property |prop|.
- *
- * @throws {InvalidArgumentError}
- * If |prop| is not in |obj|, or |obj| is not an object.
- */
-assert.in = function (prop, obj, msg = "") {
- assert.object(obj, msg);
- msg = msg || error.pprint`Expected ${prop} in ${obj}`;
- assert.that(p => obj.hasOwnProperty(p), msg)(prop);
- return obj[prop];
-};
-
-/**
- * Asserts that |obj| is an Array.
- *
- * @param {?} obj
- * Value to test.
- * @param {string=} msg
- * Custom error message.
- *
- * @return {Object}
- * |obj| is returned unaltered.
- *
- * @throws {InvalidArgumentError}
- * If |obj| is not an Array.
- */
-assert.array = function (obj, msg = "") {
- msg = msg || error.pprint`Expected ${obj} to be an Array`;
- return assert.that(Array.isArray, msg)(obj);
-};
-
-/**
- * Returns a function that is used to assert the |predicate|.
- *
- * @param {function(?): boolean} predicate
- * Evaluated on calling the return value of this function. If its
- * return value of the inner function is false, |error| is thrown
- * with |message|.
- * @param {string=} message
- * Custom error message.
- * @param {Error=} error
- * Custom error type by its class.
- *
- * @return {function(?): ?}
- * Function that takes and returns the passed in value unaltered, and
- * which may throw |error| with |message| if |predicate| evaluates
- * to false.
- */
-assert.that = function (
- predicate, message = "", error = InvalidArgumentError) {
- return obj => {
- if (!predicate(obj)) {
- throw new error(message);
- }
- return obj;
- };
-};
diff --git a/testing/marionette/atom.js b/testing/marionette/atom.js
deleted file mode 100644
index 369e5c44ce..0000000000
--- a/testing/marionette/atom.js
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2011-2014 Software Freedom Conservancy
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-this.EXPORTED_SYMBOLS = ["atom"];
-
-this.atom = {};
-
-atom.clearElement = function (element, window){return function(){function g(a){throw a;}var h=void 0,i=!0,k=null,l=!1;function n(a){return function(){return this[a]}}function o(a){return function(){return a}}var p,q=this;
-function aa(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
-else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function r(a){return a!==h}function ba(a){var b=aa(a);return"array"==b||"object"==b&&"number"==typeof a.length}function t(a){return"string"==typeof a}function w(a){return"function"==aa(a)}function ca(a){a=aa(a);return"object"==a||"array"==a||"function"==a}var da="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ea=0,fa=Date.now||function(){return+new Date};
-function x(a,b){function c(){}c.prototype=b.prototype;a.$=b.prototype;a.prototype=new c};function ga(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a}function ha(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}function ia(a){if(!ja.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(ka,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(la,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(ma,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(na,"&quot;"));return a}var ka=/&/g,la=/</g,ma=/>/g,na=/\"/g,ja=/[&<>\"]/;
-function oa(a,b){for(var c=0,d=ha(""+a).split("."),e=ha(""+b).split("."),f=Math.max(d.length,e.length),j=0;0==c&&j<f;j++){var m=d[j]||"",s=e[j]||"",O=RegExp("(\\d*)(\\D*)","g"),E=RegExp("(\\d*)(\\D*)","g");do{var u=O.exec(m)||["","",""],v=E.exec(s)||["","",""];if(0==u[0].length&&0==v[0].length)break;c=((0==u[1].length?0:parseInt(u[1],10))<(0==v[1].length?0:parseInt(v[1],10))?-1:(0==u[1].length?0:parseInt(u[1],10))>(0==v[1].length?0:parseInt(v[1],10))?1:0)||((0==u[2].length)<(0==v[2].length)?-1:(0==
-u[2].length)>(0==v[2].length)?1:0)||(u[2]<v[2]?-1:u[2]>v[2]?1:0)}while(0==c)}return c}var pa=2147483648*Math.random()|0,qa={};function ra(a){return qa[a]||(qa[a]=(""+a).replace(/\-([a-z])/g,function (a,c){return c.toUpperCase()}))};var sa,ta;function ua(){return q.navigator?q.navigator.userAgent:k}var va,wa=q.navigator;va=wa&&wa.platform||"";sa=-1!=va.indexOf("Mac");ta=-1!=va.indexOf("Win");var xa=-1!=va.indexOf("Linux"),ya,za="",Aa=/rv\:([^\);]+)(\)|;)/.exec(ua());ya=za=Aa?Aa[1]:"";var Ba={};var Ca=window;function Da(a,b){for(var c in a)b.call(h,a[c],c,a)}function Ea(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b};function y(a,b){this.code=a;this.message=b||"";this.name=Fa[a]||Fa[13];var c=Error(this.message);c.name=this.name;this.stack=c.stack||""}x(y,Error);
-var Fa={7:"NoSuchElementError",8:"NoSuchFrameError",9:"UnknownCommandError",10:"StaleElementReferenceError",11:"ElementNotVisibleError",12:"InvalidElementStateError",13:"UnknownError",15:"ElementNotSelectableError",19:"XPathLookupError",23:"NoSuchWindowError",24:"InvalidCookieDomainError",25:"UnableToSetCookieError",26:"ModalDialogOpenedError",27:"NoModalDialogOpenError",28:"ScriptTimeoutError",32:"InvalidSelectorError",33:"SqlDatabaseError",34:"MoveTargetOutOfBoundsError"};
-y.prototype.toString=function(){return"["+this.name+"] "+this.message};function Ga(a){this.stack=Error().stack||"";a&&(this.message=""+a)}x(Ga,Error);Ga.prototype.name="CustomError";function Ha(a,b){b.unshift(a);Ga.call(this,ga.apply(k,b));b.shift()}x(Ha,Ga);Ha.prototype.name="AssertionError";function Ia(a,b,c){if(!a){var d=Array.prototype.slice.call(arguments,2),e="Assertion failed";if(b)var e=e+(": "+b),f=d;g(new Ha(""+e,f||[]))}}function Ja(a,b){g(new Ha("Failure"+(a?": "+a:""),Array.prototype.slice.call(arguments,1)))};function z(a){return a[a.length-1]}var Ka=Array.prototype;function A(a,b){if(t(a))return!t(b)||1!=b.length?-1:a.indexOf(b,0);for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1}function La(a,b){for(var c=a.length,d=t(a)?a.split(""):a,e=0;e<c;e++)e in d&&b.call(h,d[e],e,a)}function Ma(a,b){for(var c=a.length,d=Array(c),e=t(a)?a.split(""):a,f=0;f<c;f++)f in e&&(d[f]=b.call(h,e[f],f,a));return d}
-function Na(a,b,c){for(var d=a.length,e=t(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return i;return l}function Oa(a,b,c){for(var d=a.length,e=t(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return l;return i}function Pa(a,b){var c;a:{c=a.length;for(var d=t(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(h,d[e],e,a)){c=e;break a}c=-1}return 0>c?k:t(a)?a.charAt(c):a[c]}function Qa(a){return Ka.concat.apply(Ka,arguments)}
-function Ra(a){if("array"==aa(a))return Qa(a);for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b}function Sa(a,b,c){Ia(a.length!=k);return 2>=arguments.length?Ka.slice.call(a,b):Ka.slice.call(a,b,c)};var Ta;Ba["1.9.1"]||(Ba["1.9.1"]=0<=oa(ya,"1.9.1"));function Ua(a,b){var c;c=(c=a.className)&&"function"==typeof c.split?c.split(/\s+/):[];var d=Sa(arguments,1),e;e=c;for(var f=0,j=0;j<d.length;j++)0<=A(e,d[j])||(e.push(d[j]),f++);e=f==d.length;a.className=c.join(" ");return e};function B(a,b){this.x=r(a)?a:0;this.y=r(b)?b:0}B.prototype.toString=function(){return"("+this.x+", "+this.y+")"};function Va(a,b){this.width=a;this.height=b}Va.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};Va.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};Va.prototype.scale=function (a){this.width*=a;this.height*=a;return this};var C=3;function Wa(a){return a?new Xa(D(a)):Ta||(Ta=new Xa)}function Ya(a,b){Da(b,function (b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:d in Za?a.setAttribute(Za[d],b):0==d.lastIndexOf("aria-",0)?a.setAttribute(d,b):a[d]=b})}var Za={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"};
-function F(a){return a?a.parentWindow||a.defaultView:window}function $a(a,b,c){function d(c){c&&b.appendChild(t(c)?a.createTextNode(c):c)}for(var e=2;e<c.length;e++){var f=c[e];ba(f)&&!(ca(f)&&0<f.nodeType)?La(ab(f)?Ra(f):f,d):d(f)}}function bb(a){return a&&a.parentNode?a.parentNode.removeChild(a):k}
-function G(a,b){if(a.contains&&1==b.nodeType)return a==b||a.contains(b);if("undefined"!=typeof a.compareDocumentPosition)return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a}
-function cb(a,b){if(a==b)return 0;if(a.compareDocumentPosition)return a.compareDocumentPosition(b)&2?1:-1;if("sourceIndex"in a||a.parentNode&&"sourceIndex"in a.parentNode){var c=1==a.nodeType,d=1==b.nodeType;if(c&&d)return a.sourceIndex-b.sourceIndex;var e=a.parentNode,f=b.parentNode;return e==f?db(a,b):!c&&G(e,b)?-1*eb(a,b):!d&&G(f,a)?eb(b,a):(c?a.sourceIndex:e.sourceIndex)-(d?b.sourceIndex:f.sourceIndex)}d=D(a);c=d.createRange();c.selectNode(a);c.collapse(i);d=d.createRange();d.selectNode(b);d.collapse(i);
-return c.compareBoundaryPoints(q.Range.START_TO_END,d)}function eb(a,b){var c=a.parentNode;if(c==b)return-1;for(var d=b;d.parentNode!=c;)d=d.parentNode;return db(d,a)}function db(a,b){for(var c=b;c=c.previousSibling;)if(c==a)return-1;return 1}
-function fb(a){var b,c=arguments.length;if(c){if(1==c)return arguments[0]}else return k;var d=[],e=Infinity;for(b=0;b<c;b++){for(var f=[],j=arguments[b];j;)f.unshift(j),j=j.parentNode;d.push(f);e=Math.min(e,f.length)}f=k;for(b=0;b<e;b++){for(var j=d[0][b],m=1;m<c;m++)if(j!=d[m][b])return f;f=j}return f}function D(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function gb(a,b){var c=[];return hb(a,b,c,i)?c[0]:h}
-function hb(a,b,c,d){if(a!=k)for(a=a.firstChild;a;){if(b(a)&&(c.push(a),d)||hb(a,b,c,d))return i;a=a.nextSibling}return l}var ib={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},jb={IMG:" ",BR:"\n"};function kb(a,b,c){if(!(a.nodeName in ib))if(a.nodeType==C)c?b.push((""+a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in jb)b.push(jb[a.nodeName]);else for(a=a.firstChild;a;)kb(a,b,c),a=a.nextSibling}
-function ab(a){if(a&&"number"==typeof a.length){if(ca(a))return"function"==typeof a.item||"string"==typeof a.item;if(w(a))return"function"==typeof a.item}return l}function lb(a,b){for(var a=a.parentNode,c=0;a;){if(b(a))return a;a=a.parentNode;c++}return k}function Xa(a){this.v=a||q.document||document}p=Xa.prototype;p.ea=n("v");p.z=function (a){return t(a)?this.v.getElementById(a):a};
-p.da=function (a,b,c){var d=this.v,e=arguments,f=e[1],j=d.createElement(e[0]);f&&(t(f)?j.className=f:"array"==aa(f)?Ua.apply(k,[j].concat(f)):Ya(j,f));2<e.length&&$a(d,j,e);return j};p.createElement=function (a){return this.v.createElement(a)};p.createTextNode=function (a){return this.v.createTextNode(a)};p.qa=function(){return this.v.parentWindow||this.v.defaultView};
-function mb(a){var b=a.v,a="CSS1Compat"==b.compatMode?b.documentElement:b.body,b=b.parentWindow||b.defaultView;return new B(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}p.appendChild=function (a,b){a.appendChild(b)};p.removeNode=bb;p.contains=G;var H={};H.ya=function(){var a={Oa:"http://www.w3.org/2000/svg"};return function (b){return a[b]||k}}();H.ma=function (a,b,c){var d=D(a);if(!d.implementation.hasFeature("XPath","3.0"))return k;try{var e=d.createNSResolver?d.createNSResolver(d.documentElement):H.ya;return d.evaluate(b,a,e,c,k)}catch(f){"NS_ERROR_ILLEGAL_VALUE"!=f.name&&g(new y(32,"Unable to locate an element with the xpath expression "+b+" because of the following error:\n"+f))}};
-H.ka=function (a,b){(!a||1!=a.nodeType)&&g(new y(32,'The result of the xpath expression "'+b+'" is: '+a+". It should be an element."))};H.Ia=function (a,b){var c=function(){var c=H.ma(b,a,9);return c?c.singleNodeValue||k:b.selectSingleNode?(c=D(b),c.setProperty&&c.setProperty("SelectionLanguage","XPath"),b.selectSingleNode(a)):k}();c===k||H.ka(c,a);return c};
-H.Na=function (a,b){var c=function(){var c=H.ma(b,a,7);if(c){for(var e=c.snapshotLength,f=[],j=0;j<e;++j)f.push(c.snapshotItem(j));return f}return b.selectNodes?(c=D(b),c.setProperty&&c.setProperty("SelectionLanguage","XPath"),b.selectNodes(a)):[]}();La(c,function (b){H.ka(b,a)});return c};var nb,ob="",pb=/Firefox\/([0-9.]+)/.exec(ua());nb=ob=pb?pb[2]||pb[1]:"";var qb=k,rb=function(){var a=q.Components;if(!a)return l;try{if(!a.classes)return l}catch(b){return l}var c=a.classes,a=a.interfaces,d=c["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator),e=c["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo).version;qb=function (a){return 0<=d.Ka(e,""+a)};return i}();var I="StopIteration"in q?q.StopIteration:Error("StopIteration");function J(){}J.prototype.next=function(){g(I)};J.prototype.r=function(){return this};function sb(a){if(a instanceof J)return a;if("function"==typeof a.r)return a.r(l);if(ba(a)){var b=0,c=new J;c.next=function(){for(;;){b>=a.length&&g(I);if(b in a)return a[b++];b++}};return c}g(Error("Not implemented"))};function K(a,b,c,d,e){this.o=!!b;a&&L(this,a,d);this.depth=e!=h?e:this.q||0;this.o&&(this.depth*=-1);this.za=!c}x(K,J);p=K.prototype;p.p=k;p.q=0;p.ha=l;function L(a,b,c,d){if(a.p=b)a.q="number"==typeof c?c:1!=a.p.nodeType?0:a.o?-1:1;"number"==typeof d&&(a.depth=d)}
-p.next=function(){var a;if(this.ha){(!this.p||this.za&&0==this.depth)&&g(I);a=this.p;var b=this.o?-1:1;if(this.q==b){var c=this.o?a.lastChild:a.firstChild;c?L(this,c):L(this,a,-1*b)}else(c=this.o?a.previousSibling:a.nextSibling)?L(this,c):L(this,a.parentNode,-1*b);this.depth+=this.q*(this.o?-1:1)}else this.ha=i;(a=this.p)||g(I);return a};
-p.splice=function (a){var b=this.p,c=this.o?1:-1;this.q==c&&(this.q=-1*c,this.depth+=this.q*(this.o?-1:1));this.o=!this.o;K.prototype.next.call(this);this.o=!this.o;for(var c=ba(arguments[0])?arguments[0]:arguments,d=c.length-1;0<=d;d--)b.parentNode&&b.parentNode.insertBefore(c[d],b.nextSibling);bb(b)};function tb(a,b,c,d){K.call(this,a,b,c,k,d)}x(tb,K);tb.prototype.next=function(){do tb.$.next.call(this);while(-1==this.q);return this.p};function ub(a,b){var c=D(a);return c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(a,k))?c[b]||c.getPropertyValue(b):""}function vb(a,b){return ub(a,b)||(a.currentStyle?a.currentStyle[b]:k)||a.style&&a.style[b]}
-function wb(a){for(var b=D(a),c=vb(a,"position"),d="fixed"==c||"absolute"==c,a=a.parentNode;a&&a!=b;a=a.parentNode)if(c=vb(a,"position"),d=d&&"static"==c&&a!=b.documentElement&&a!=b.body,!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c||"absolute"==c||"relative"==c))return a;return k}
-function xb(a){var b=new B;if(1==a.nodeType)if(a.getBoundingClientRect)a=a.getBoundingClientRect(),b.x=a.left,b.y=a.top;else{var c=mb(Wa(a));var d,e=D(a),f=vb(a,"position"),j=e.getBoxObjectFor&&!a.getBoundingClientRect&&"absolute"==f&&(d=e.getBoxObjectFor(a))&&(0>d.screenX||0>d.screenY),f=new B(0,0),m=(e?9==e.nodeType?e:D(e):document).documentElement;if(a!=m)if(a.getBoundingClientRect)d=a.getBoundingClientRect(),a=mb(Wa(e)),f.x=d.left+a.x,f.y=d.top+a.y;else if(e.getBoxObjectFor&&!j)d=e.getBoxObjectFor(a),
-a=e.getBoxObjectFor(m),f.x=d.screenX-a.screenX,f.y=d.screenY-a.screenY;else{d=a;do f.x+=d.offsetLeft,f.y+=d.offsetTop,d!=a&&(f.x+=d.clientLeft||0,f.y+=d.clientTop||0),d=d.offsetParent;while(d&&d!=a);for(d=a;(d=wb(d))&&d!=e.body&&d!=m;)f.x-=d.scrollLeft,f.y-=d.scrollTop}b.x=f.x-c.x;b.y=f.y-c.y}else c=w(a.pa),d=a,a.targetTouches?d=a.targetTouches[0]:c&&a.pa().targetTouches&&(d=a.pa().targetTouches[0]),b.x=d.clientX,b.y=d.clientY;return b}
-function yb(a){var b=a.offsetWidth,c=a.offsetHeight;return!r(b)&&a.getBoundingClientRect?(a=a.getBoundingClientRect(),new Va(a.right-a.left,a.bottom-a.top)):new Va(b,c)};function M(a,b){return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}var zb={"class":"className",readonly:"readOnly"},Ab=["checked","disabled","draggable","hidden"];function Bb(a,b){var c=zb[b]||b,d=a[c];if(!r(d)&&0<=A(Ab,c))return l;if(c="value"==b)if(c=M(a,"OPTION")){var e;c=b.toLowerCase();if(a.hasAttribute)e=a.hasAttribute(c);else try{e=a.attributes[c].specified}catch(f){e=l}c=!e}c&&(d=[],kb(a,d,l),d=d.join(""));return d}
-var Cb="async,autofocus,autoplay,checked,compact,complete,controls,declare,defaultchecked,defaultselected,defer,disabled,draggable,ended,formnovalidate,hidden,indeterminate,iscontenteditable,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,paused,pubdate,readonly,required,reversed,scoped,seamless,seeking,selected,spellcheck,truespeed,willvalidate".split(","),Db="BUTTON,INPUT,OPTGROUP,OPTION,SELECT,TEXTAREA".split(",");
-function Eb(a){var b=a.tagName.toUpperCase();return!(0<=A(Db,b))?i:Bb(a,"disabled")?l:a.parentNode&&1==a.parentNode.nodeType&&"OPTGROUP"==b||"OPTION"==b?Eb(a.parentNode):i}var Fb="text,search,tel,url,email,password,number".split(",");function Gb(a){return M(a,"TEXTAREA")?i:M(a,"INPUT")?0<=A(Fb,a.type.toLowerCase()):Hb(a)?i:l}
-function Hb(a){function b(a){return"inherit"==a.contentEditable?(a=Ib(a))?b(a):l:"true"==a.contentEditable}return!r(a.contentEditable)?l:r(a.isContentEditable)?a.isContentEditable:b(a)}function Ib(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return M(a)?a:k}function Jb(a,b){b=ra(b);return ub(a,b)||Kb(a,b)}
-function Kb(a,b){var c=a.currentStyle||a.style,d=c[b];!r(d)&&w(c.getPropertyValue)&&(d=c.getPropertyValue(b));return"inherit"!=d?r(d)?d:k:(c=Ib(a))?Kb(c,b):k}function Lb(a){if(w(a.getBBox))try{var b=a.getBBox();if(b)return b}catch(c){}if("none"!=vb(a,"display"))a=yb(a);else{var b=a.style,d=b.display,e=b.visibility,f=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";a=yb(a);b.display=d;b.position=f;b.visibility=e}return a}
-function Mb(a,b){function c(a){if("none"==Jb(a,"display"))return l;a=Ib(a);return!a||c(a)}function d(a){var b=Lb(a);return 0<b.height&&0<b.width?i:Na(a.childNodes,function (a){return a.nodeType==C||M(a)&&d(a)})}function e(a){var b=Ib(a);if(b&&"hidden"==Jb(b,"overflow")){var c=Lb(b),d=xb(b),a=xb(a);return d.x+c.width<a.x||d.y+c.height<a.y?l:e(b)}return i}M(a)||g(Error("Argument to isShown must be of type Element"));if(M(a,"OPTION")||M(a,"OPTGROUP")){var f=lb(a,function (a){return M(a,"SELECT")});return!!f&&
-Mb(f,i)}if(M(a,"MAP")){if(!a.name)return l;f=D(a);f=f.evaluate?H.Ia('/descendant::*[@usemap = "#'+a.name+'"]',f):gb(f,function (b){var c;if(c=M(b))8==b.nodeType?b=k:(c="usemap","style"==c?(b=ha(b.style.cssText).toLowerCase(),b=";"==b.charAt(b.length-1)?b:b+";"):(b=b.getAttributeNode(c),b=!b?k:0<=A(Cb,c)?"true":b.specified?b.value:k)),c=b=="#"+a.name;return c});return!!f&&Mb(f,b)}return M(a,"AREA")?(f=lb(a,function (a){return M(a,"MAP")}),!!f&&Mb(f,b)):M(a,"INPUT")&&"hidden"==a.type.toLowerCase()||M(a,
-"NOSCRIPT")||"hidden"==Jb(a,"visibility")||!c(a)||!b&&0==Nb(a)||!d(a)||!e(a)?l:i}function Nb(a){var b=1,c=Jb(a,"opacity");c&&(b=Number(c));(a=Ib(a))&&(b*=Nb(a));return b};function N(){this.w=Ca.document.documentElement;this.ua=k;var a=D(this.w).activeElement;a&&Ob(this,a)}N.prototype.z=n("w");function Ob(a,b){a.w=b;a.ua=M(b,"OPTION")?lb(b,function (a){return M(a,"SELECT")}):k}
-function Pb(a,b,c,d,e,f){function j(a,c){var d={identifier:a,screenX:c.x,screenY:c.y,clientX:c.x,clientY:c.y,pageX:c.x,pageY:c.y};m.changedTouches.push(d);if(b==Qb||b==Rb)m.touches.push(d),m.targetTouches.push(d)}var m={touches:[],targetTouches:[],changedTouches:[],altKey:l,ctrlKey:l,shiftKey:l,metaKey:l,relatedTarget:k,scale:0,rotation:0};j(c,d);r(e)&&j(e,f);Sb(a.w,b,m)}rb&&rb&&(rb?qb(4):oa(nb,4));rb&&(rb?qb(4):oa(nb,4));function P(a,b,c){this.J=a;this.S=b;this.T=c}P.prototype.create=function (a){a=D(a).createEvent("HTMLEvents");a.initEvent(this.J,this.S,this.T);return a};P.prototype.toString=n("J");function Q(a,b,c){P.call(this,a,b,c)}x(Q,P);
-Q.prototype.create=function (a,b){var c=D(a),d=F(c),c=c.createEvent("MouseEvents"),e=1;this==Tb&&(e=b.wheelDelta/-40);this==Ub&&(e=b.wheelDelta);c.initMouseEvent(this.J,this.S,this.T,d,e,0,0,b.clientX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};function Vb(a,b,c){P.call(this,a,b,c)}x(Vb,P);
-Vb.prototype.create=function (a,b){var c=D(a),d=F(c),e=b.charCode?0:b.keyCode,c=c.createEvent("KeyboardEvent");c.initKeyEvent(this.J,this.S,this.T,d,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,e,b.charCode);this.J==Wb&&b.preventDefault&&c.preventDefault();return c};function Xb(a,b,c){P.call(this,a,b,c)}x(Xb,P);
-Xb.prototype.create=function (a,b){function c(b){var c=Ma(b,function (b){return{identifier:b.identifier,screenX:b.screenX,screenY:b.screenY,clientX:b.clientX,clientY:b.clientY,pageX:b.pageX,pageY:b.pageY,target:a}});c.item=function (a){return c[a]};return c}var d=D(a),e=F(d),f=c(b.changedTouches),j=b.touches==b.changedTouches?f:c(b.touches),m=b.targetTouches==b.changedTouches?f:c(b.targetTouches),d=d.createEvent("MouseEvents");d.initMouseEvent(this.J,this.S,this.T,e,1,0,0,b.clientX,b.clientY,b.ctrlKey,
-b.altKey,b.shiftKey,b.metaKey,0,b.relatedTarget);d.touches=j;d.targetTouches=m;d.changedTouches=f;d.scale=b.scale;d.rotation=b.rotation;return d};
-var Yb=new P("change",i,l),Zb=new Q("click",i,i),$b=new Q("contextmenu",i,i),ac=new Q("dblclick",i,i),bc=new Q("mousedown",i,i),cc=new Q("mousemove",i,l),dc=new Q("mouseout",i,i),ec=new Q("mouseover",i,i),fc=new Q("mouseup",i,i),Tb=new Q("DOMMouseScroll",i,i),Ub=new Q("MozMousePixelScroll",i,i),Wb=new Vb("keypress",i,i),Rb=new Xb("touchmove",i,i),Qb=new Xb("touchstart",i,i);function Sb(a,b,c){b=b.create(a,c);"isTrusted"in b||(b.La=l);a.dispatchEvent(b)};function gc(a){if("function"==typeof a.L)return a.L();if(t(a))return a.split("");if(ba(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Ea(a)};function hc(a,b){this.n={};this.ta={};var c=arguments.length;if(1<c){c%2&&g(Error("Uneven number of arguments"));for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&this.aa(a)}p=hc.prototype;p.ia=0;p.L=function(){var a=[],b;for(b in this.n)":"==b.charAt(0)&&a.push(this.n[b]);return a};function ic(a){var b=[],c;for(c in a.n)if(":"==c.charAt(0)){var d=c.substring(1);b.push(a.ta[c]?Number(d):d)}return b}
-p.set=function (a,b){var c=":"+a;c in this.n||(this.ia++,"number"==typeof a&&(this.ta[c]=i));this.n[c]=b};p.aa=function (a){var b;if(a instanceof hc)b=ic(a),a=a.L();else{b=[];var c=0,d;for(d in a)b[c++]=d;a=Ea(a)}for(c=0;c<b.length;c++)this.set(b[c],a[c])};p.r=function (a){var b=0,c=ic(this),d=this.n,e=this.ia,f=this,j=new J;j.next=function(){for(;;){e!=f.ia&&g(Error("The map has changed since the iterator was created"));b>=c.length&&g(I);var j=c[b++];return a?j:d[":"+j]}};return j};function jc(a){this.n=new hc;a&&this.aa(a)}function kc(a){var b=typeof a;return"object"==b&&a||"function"==b?"o"+(a[da]||(a[da]=++ea)):b.substr(0,1)+a}p=jc.prototype;p.add=function (a){this.n.set(kc(a),a)};p.aa=function (a){for(var a=gc(a),b=a.length,c=0;c<b;c++)this.add(a[c])};p.contains=function (a){return":"+kc(a)in this.n.n};p.L=function(){return this.n.L()};p.r=function(){return this.n.r(l)};function lc(){N.call(this);Gb(this.z())&&Bb(this.z(),"readOnly");this.Ha=new jc}x(lc,N);var mc={};function R(a,b,c){ca(a)&&(a=a.c);a=new nc(a);if(b&&(!(b in mc)||c))mc[b]={key:a,shift:l},c&&(mc[c]={key:a,shift:i})}function nc(a){this.code=a}R(8);R(9);R(13);R(16);R(17);R(18);R(19);R(20);R(27);R(32," ");R(33);R(34);R(35);R(36);R(37);R(38);R(39);R(40);R(44);R(45);R(46);R(48,"0",")");R(49,"1","!");R(50,"2","@");R(51,"3","#");R(52,"4","$");R(53,"5","%");R(54,"6","^");R(55,"7","&");R(56,"8","*");
-R(57,"9","(");R(65,"a","A");R(66,"b","B");R(67,"c","C");R(68,"d","D");R(69,"e","E");R(70,"f","F");R(71,"g","G");R(72,"h","H");R(73,"i","I");R(74,"j","J");R(75,"k","K");R(76,"l","L");R(77,"m","M");R(78,"n","N");R(79,"o","O");R(80,"p","P");R(81,"q","Q");R(82,"r","R");R(83,"s","S");R(84,"t","T");R(85,"u","U");R(86,"v","V");R(87,"w","W");R(88,"x","X");R(89,"y","Y");R(90,"z","Z");R(ta?{c:91,e:91,opera:219}:sa?{c:224,e:91,opera:17}:{c:0,e:91,opera:k});
-R(ta?{c:92,e:92,opera:220}:sa?{c:224,e:93,opera:17}:{c:0,e:92,opera:k});R(ta?{c:93,e:93,opera:0}:sa?{c:0,e:0,opera:16}:{c:93,e:k,opera:0});R({c:96,e:96,opera:48},"0");R({c:97,e:97,opera:49},"1");R({c:98,e:98,opera:50},"2");R({c:99,e:99,opera:51},"3");R({c:100,e:100,opera:52},"4");R({c:101,e:101,opera:53},"5");R({c:102,e:102,opera:54},"6");R({c:103,e:103,opera:55},"7");R({c:104,e:104,opera:56},"8");R({c:105,e:105,opera:57},"9");R({c:106,e:106,opera:xa?56:42},"*");R({c:107,e:107,opera:xa?61:43},"+");
-R({c:109,e:109,opera:xa?109:45},"-");R({c:110,e:110,opera:xa?190:78},".");R({c:111,e:111,opera:xa?191:47},"/");R(144);R(112);R(113);R(114);R(115);R(116);R(117);R(118);R(119);R(120);R(121);R(122);R(123);R({c:107,e:187,opera:61},"=","+");R({c:109,e:189,opera:109},"-","_");R(188,",","<");R(190,".",">");R(191,"/","?");R(192,"`","~");R(219,"[","{");R(220,"\\","|");R(221,"]","}");R({c:59,e:186,opera:59},";",":");R(222,"'",'"');lc.prototype.X=function (a){return this.Ha.contains(a)};function oc(a){return pc(a||arguments.callee.caller,[])}
-function pc(a,b){var c=[];if(0<=A(b,a))c.push("[...circular reference...]");else if(a&&50>b.length){c.push(qc(a)+"(");for(var d=a.arguments,e=0;e<d.length;e++){0<e&&c.push(", ");var f;f=d[e];switch(typeof f){case "object":f=f?"object":"null";break;case "string":break;case "number":f=""+f;break;case "boolean":f=f?"true":"false";break;case "function":f=(f=qc(f))?f:"[fn]";break;default:f=typeof f}40<f.length&&(f=f.substr(0,40)+"...");c.push(f)}b.push(a);c.push(")\n");try{c.push(pc(a.caller,b))}catch(j){c.push("[exception trying to get caller]\n")}}else a?
-c.push("[...long stack...]"):c.push("[end]");return c.join("")}function qc(a){if(rc[a])return rc[a];a=""+a;if(!rc[a]){var b=/function ([^\(]+)/.exec(a);rc[a]=b?b[1]:"[Anonymous]"}return rc[a]}var rc={};function sc(a,b,c,d,e){this.reset(a,b,c,d,e)}sc.prototype.oa=k;sc.prototype.na=k;var tc=0;sc.prototype.reset=function (a,b,c,d,e){"number"==typeof e||tc++;d||fa();this.N=a;this.Fa=b;delete this.oa;delete this.na};sc.prototype.va=function (a){this.N=a};function S(a){this.Ga=a}S.prototype.Y=k;S.prototype.N=k;S.prototype.ba=k;S.prototype.ra=k;function uc(a,b){this.name=a;this.value=b}uc.prototype.toString=n("name");var vc=new uc("WARNING",900),wc=new uc("CONFIG",700);S.prototype.getParent=n("Y");S.prototype.va=function (a){this.N=a};function xc(a){if(a.N)return a.N;if(a.Y)return xc(a.Y);Ja("Root logger has no level set.");return k}
-S.prototype.log=function (a,b,c){if(a.value>=xc(this).value){a=this.Ca(a,b,c);b="log:"+a.Fa;q.console&&(q.console.timeStamp?q.console.timeStamp(b):q.console.markTimeline&&q.console.markTimeline(b));q.msWriteProfilerMark&&q.msWriteProfilerMark(b);for(b=this;b;){var c=b,d=a;if(c.ra)for(var e=0,f=h;f=c.ra[e];e++)f(d);b=b.getParent()}}};
-S.prototype.Ca=function (a,b,c){var d=new sc(a,""+b,this.Ga);if(c){d.oa=c;var e;var f=arguments.callee.caller;try{var j;var m;c:{for(var s=["window","location","href"],O=q,E;E=s.shift();)if(O[E]!=k)O=O[E];else{m=k;break c}m=O}if(t(c))j={message:c,name:"Unknown error",lineNumber:"Not available",fileName:m,stack:"Not available"};else{var u,v,s=l;try{u=c.lineNumber||c.Ma||"Not available"}catch(md){u="Not available",s=i}try{v=c.fileName||c.filename||c.sourceURL||m}catch(nd){v="Not available",s=i}j=s||
-!c.lineNumber||!c.fileName||!c.stack?{message:c.message,name:c.name,lineNumber:u,fileName:v,stack:c.stack||"Not available"}:c}e="Message: "+ia(j.message)+'\nUrl: <a href="view-source:'+j.fileName+'" target="_new">'+j.fileName+"</a>\nLine: "+j.lineNumber+"\n\nBrowser stack:\n"+ia(j.stack+"-> ")+"[end]\n\nJS stack traversal:\n"+ia(oc(f)+"-> ")}catch(kd){e="Exception trying to expose exception! You win, we lose. "+kd}d.na=e}return d};var yc={},zc=k;
-function Ac(a){zc||(zc=new S(""),yc[""]=zc,zc.va(wc));var b;if(!(b=yc[a])){b=new S(a);var c=a.lastIndexOf("."),d=a.substr(c+1),c=Ac(a.substr(0,c));c.ba||(c.ba={});c.ba[d]=b;b.Y=c;yc[a]=b}return b};function Bc(){}x(Bc,function(){});Ac("goog.dom.SavedRange");x(function (a){this.Ja="goog_"+pa++;this.Aa="goog_"+pa++;this.la=Wa(a.ea());a.R(this.la.da("SPAN",{id:this.Ja}),this.la.da("SPAN",{id:this.Aa}))},Bc);function T(){}function Cc(a){if(a.getSelection)return a.getSelection();var a=a.document,b=a.selection;if(b){try{var c=b.createRange();if(c.parentElement){if(c.parentElement().document!=a)return k}else if(!c.length||c.item(0).document!=a)return k}catch(d){return k}return b}return k}function Dc(a){for(var b=[],c=0,d=a.D();c<d;c++)b.push(a.A(c));return b}T.prototype.F=o(l);T.prototype.ea=function(){return D(this.b())};T.prototype.qa=function(){return F(this.ea())};
-T.prototype.containsNode=function (a,b){return this.u(Ec(Fc(a),h),b)};function U(a,b){K.call(this,a,b,i)}x(U,K);function V(){}x(V,T);V.prototype.u=function (a,b){var c=Dc(this),d=Dc(a);return(b?Na:Oa)(d,function (a){return Na(c,function (c){return c.u(a,b)})})};V.prototype.insertNode=function (a,b){if(b){var c=this.b();c.parentNode&&c.parentNode.insertBefore(a,c)}else c=this.g(),c.parentNode&&c.parentNode.insertBefore(a,c.nextSibling);return a};V.prototype.R=function (a,b){this.insertNode(a,i);this.insertNode(b,l)};function Gc(a,b,c,d,e){var f;if(a&&(this.f=a,this.i=b,this.d=c,this.h=d,1==a.nodeType&&"BR"!=a.tagName&&(a=a.childNodes,(b=a[b])?(this.f=b,this.i=0):(a.length&&(this.f=z(a)),f=i)),1==c.nodeType))(this.d=c.childNodes[d])?this.h=0:this.d=c;U.call(this,e?this.d:this.f,e);if(f)try{this.next()}catch(j){j!=I&&g(j)}}x(Gc,U);p=Gc.prototype;p.f=k;p.d=k;p.i=0;p.h=0;p.b=n("f");p.g=n("d");p.M=function(){return this.ha&&this.p==this.d&&(!this.h||1!=this.q)};p.next=function(){this.M()&&g(I);return Gc.$.next.call(this)};"ScriptEngine"in q&&"JScript"==q.ScriptEngine()&&(q.ScriptEngineMajorVersion(),q.ScriptEngineMinorVersion(),q.ScriptEngineBuildVersion());function Hc(){}Hc.prototype.u=function (a,b){var c=b&&!a.isCollapsed(),d=a.a;try{return c?0<=this.l(d,0,1)&&0>=this.l(d,1,0):0<=this.l(d,0,0)&&0>=this.l(d,1,1)}catch(e){g(e)}};Hc.prototype.containsNode=function (a,b){return this.u(Fc(a),b)};Hc.prototype.r=function(){return new Gc(this.b(),this.j(),this.g(),this.k())};function Ic(a){this.a=a}x(Ic,Hc);p=Ic.prototype;p.C=function(){return this.a.commonAncestorContainer};p.b=function(){return this.a.startContainer};p.j=function(){return this.a.startOffset};p.g=function(){return this.a.endContainer};p.k=function(){return this.a.endOffset};p.l=function (a,b,c){return this.a.compareBoundaryPoints(1==c?1==b?q.Range.START_TO_START:q.Range.START_TO_END:1==b?q.Range.END_TO_START:q.Range.END_TO_END,a)};p.isCollapsed=function(){return this.a.collapsed};
-p.select=function (a){this.Z(F(D(this.b())).getSelection(),a)};p.Z=function (a){a.removeAllRanges();a.addRange(this.a)};p.insertNode=function (a,b){var c=this.a.cloneRange();c.collapse(b);c.insertNode(a);c.detach();return a};
-p.R=function (a,b){var c=F(D(this.b()));if(c=(c=Cc(c||window))&&Jc(c))var d=c.b(),e=c.g(),f=c.j(),j=c.k();var m=this.a.cloneRange(),s=this.a.cloneRange();m.collapse(l);s.collapse(i);m.insertNode(b);s.insertNode(a);m.detach();s.detach();if(c){if(d.nodeType==C)for(;f>d.length;){f-=d.length;do d=d.nextSibling;while(d==a||d==b)}if(e.nodeType==C)for(;j>e.length;){j-=e.length;do e=e.nextSibling;while(e==a||e==b)}c=new Kc;c.G=Lc(d,f,e,j);"BR"==d.tagName&&(m=d.parentNode,f=A(m.childNodes,d),d=m);"BR"==e.tagName&&
-(m=e.parentNode,j=A(m.childNodes,e),e=m);c.G?(c.f=e,c.i=j,c.d=d,c.h=f):(c.f=d,c.i=f,c.d=e,c.h=j);c.select()}};p.collapse=function (a){this.a.collapse(a)};function W(a){this.a=a}x(W,Ic);function Fc(a){var b=D(a).createRange();if(a.nodeType==C)b.setStart(a,0),b.setEnd(a,a.length);else if(X(a)){for(var c,d=a;(c=d.firstChild)&&X(c);)d=c;b.setStart(d,0);for(d=a;(c=d.lastChild)&&X(c);)d=c;b.setEnd(d,1==d.nodeType?d.childNodes.length:d.length)}else c=a.parentNode,a=A(c.childNodes,a),b.setStart(c,a),b.setEnd(c,a+1);return new W(b)}
-W.prototype.Z=function (a,b){var c=b?this.g():this.b(),d=b?this.k():this.j(),e=b?this.b():this.g(),f=b?this.j():this.k();a.collapse(c,d);(c!=e||d!=f)&&a.extend(e,f)};function Mc(a){this.a=a}x(Mc,Hc);Ac("goog.dom.browserrange.IeRange");function Nc(a){var b=D(a).body.createTextRange();if(1==a.nodeType)b.moveToElementText(a),X(a)&&!a.childNodes.length&&b.collapse(l);else{for(var c=0,d=a;d=d.previousSibling;){var e=d.nodeType;if(e==C)c+=d.length;else if(1==e){b.moveToElementText(d);break}}d||b.moveToElementText(a.parentNode);b.collapse(!d);c&&b.move("character",c);b.moveEnd("character",a.length)}return b}p=Mc.prototype;p.O=k;p.f=k;p.d=k;p.i=-1;p.h=-1;
-p.s=function(){this.O=this.f=this.d=k;this.i=this.h=-1};
-p.C=function(){if(!this.O){var a=this.a.text,b=this.a.duplicate(),c=a.replace(/ +$/,"");(c=a.length-c.length)&&b.moveEnd("character",-c);c=b.parentElement();b=b.htmlText.replace(/(\r\n|\r|\n)+/g," ").length;if(this.isCollapsed()&&0<b)return this.O=c;for(;b>c.outerHTML.replace(/(\r\n|\r|\n)+/g," ").length;)c=c.parentNode;for(;1==c.childNodes.length&&c.innerText==(c.firstChild.nodeType==C?c.firstChild.nodeValue:c.firstChild.innerText)&&X(c.firstChild);)c=c.firstChild;0==a.length&&(c=Oc(this,c));this.O=
-c}return this.O};function Oc(a,b){for(var c=b.childNodes,d=0,e=c.length;d<e;d++){var f=c[d];if(X(f)){var j=Nc(f),m=j.htmlText!=f.outerHTML;if(a.isCollapsed()&&m?0<=a.l(j,1,1)&&0>=a.l(j,1,0):a.a.inRange(j))return Oc(a,f)}}return b}p.b=function(){this.f||(this.f=Pc(this,1),this.isCollapsed()&&(this.d=this.f));return this.f};p.j=function(){0>this.i&&(this.i=Qc(this,1),this.isCollapsed()&&(this.h=this.i));return this.i};
-p.g=function(){if(this.isCollapsed())return this.b();this.d||(this.d=Pc(this,0));return this.d};p.k=function(){if(this.isCollapsed())return this.j();0>this.h&&(this.h=Qc(this,0),this.isCollapsed()&&(this.i=this.h));return this.h};p.l=function (a,b,c){return this.a.compareEndPoints((1==b?"Start":"End")+"To"+(1==c?"Start":"End"),a)};
-function Pc(a,b,c){c=c||a.C();if(!c||!c.firstChild)return c;for(var d=1==b,e=0,f=c.childNodes.length;e<f;e++){var j=d?e:f-e-1,m=c.childNodes[j],s;try{s=Fc(m)}catch(O){continue}var E=s.a;if(a.isCollapsed())if(X(m)){if(s.u(a))return Pc(a,b,m)}else{if(0==a.l(E,1,1)){a.i=a.h=j;break}}else{if(a.u(s)){if(!X(m)){d?a.i=j:a.h=j+1;break}return Pc(a,b,m)}if(0>a.l(E,1,0)&&0<a.l(E,0,1))return Pc(a,b,m)}}return c}
-function Qc(a,b){var c=1==b,d=c?a.b():a.g();if(1==d.nodeType){for(var d=d.childNodes,e=d.length,f=c?1:-1,j=c?0:e-1;0<=j&&j<e;j+=f){var m=d[j];if(!X(m)&&0==a.a.compareEndPoints((1==b?"Start":"End")+"To"+(1==b?"Start":"End"),Fc(m).a))return c?j:j+1}return-1==j?0:j}e=a.a.duplicate();f=Nc(d);e.setEndPoint(c?"EndToEnd":"StartToStart",f);e=e.text.length;return c?d.length-e:e}p.isCollapsed=function(){return 0==this.a.compareEndPoints("StartToEnd",this.a)};p.select=function(){this.a.select()};
-function Rc(a,b,c){var d;d=d||Wa(a.parentElement());var e;1!=b.nodeType&&(e=i,b=d.da("DIV",k,b));a.collapse(c);d=d||Wa(a.parentElement());var f=c=b.id;c||(c=b.id="goog_"+pa++);a.pasteHTML(b.outerHTML);(b=d.z(c))&&(f||b.removeAttribute("id"));if(e){a=b.firstChild;e=b;if((d=e.parentNode)&&11!=d.nodeType)if(e.removeNode)e.removeNode(l);else{for(;b=e.firstChild;)d.insertBefore(b,e);bb(e)}b=a}return b}p.insertNode=function (a,b){var c=Rc(this.a.duplicate(),a,b);this.s();return c};
-p.R=function (a,b){var c=this.a.duplicate(),d=this.a.duplicate();Rc(c,a,i);Rc(d,b,l);this.s()};p.collapse=function (a){this.a.collapse(a);a?(this.d=this.f,this.h=this.i):(this.f=this.d,this.i=this.h)};function Sc(a){this.a=a}x(Sc,Ic);Sc.prototype.Z=function (a){a.collapse(this.b(),this.j());(this.g()!=this.b()||this.k()!=this.j())&&a.extend(this.g(),this.k());0==a.rangeCount&&a.addRange(this.a)};function Tc(a){this.a=a}x(Tc,Ic);Tc.prototype.l=function (a,b,c){return Ba["528"]||(Ba["528"]=0<=oa(ya,"528"))?Tc.$.l.call(this,a,b,c):this.a.compareBoundaryPoints(1==c?1==b?q.Range.START_TO_START:q.Range.END_TO_START:1==b?q.Range.START_TO_END:q.Range.END_TO_END,a)};Tc.prototype.Z=function (a,b){a.removeAllRanges();b?a.setBaseAndExtent(this.g(),this.k(),this.b(),this.j()):a.setBaseAndExtent(this.b(),this.j(),this.g(),this.k())};function X(a){var b;a:if(1!=a.nodeType)b=l;else{switch(a.tagName){case "APPLET":case "AREA":case "BASE":case "BR":case "COL":case "FRAME":case "HR":case "IMG":case "INPUT":case "IFRAME":case "ISINDEX":case "LINK":case "NOFRAMES":case "NOSCRIPT":case "META":case "OBJECT":case "PARAM":case "SCRIPT":case "STYLE":b=l;break a}b=i}return b||a.nodeType==C};function Kc(){}x(Kc,T);function Ec(a,b){var c=new Kc;c.K=a;c.G=!!b;return c}p=Kc.prototype;p.K=k;p.f=k;p.i=k;p.d=k;p.h=k;p.G=l;p.fa=o("text");p.W=function(){return Y(this).a};p.s=function(){this.f=this.i=this.d=this.h=k};p.D=o(1);p.A=function(){return this};function Y(a){var b;if(!(b=a.K)){b=a.b();var c=a.j(),d=a.g(),e=a.k(),f=D(b).createRange();f.setStart(b,c);f.setEnd(d,e);b=a.K=new W(f)}return b}p.C=function(){return Y(this).C()};p.b=function(){return this.f||(this.f=Y(this).b())};
-p.j=function(){return this.i!=k?this.i:this.i=Y(this).j()};p.g=function(){return this.d||(this.d=Y(this).g())};p.k=function(){return this.h!=k?this.h:this.h=Y(this).k()};p.F=n("G");p.u=function (a,b){var c=a.fa();return"text"==c?Y(this).u(Y(a),b):"control"==c?(c=Uc(a),(b?Na:Oa)(c,function (a){return this.containsNode(a,b)},this)):l};p.isCollapsed=function(){return Y(this).isCollapsed()};p.r=function(){return new Gc(this.b(),this.j(),this.g(),this.k())};p.select=function(){Y(this).select(this.G)};
-p.insertNode=function (a,b){var c=Y(this).insertNode(a,b);this.s();return c};p.R=function (a,b){Y(this).R(a,b);this.s()};p.ga=function(){return new Vc(this)};p.collapse=function (a){a=this.F()?!a:a;this.K&&this.K.collapse(a);a?(this.d=this.f,this.h=this.i):(this.f=this.d,this.i=this.h);this.G=l};function Vc(a){a.F()?a.g():a.b();a.F()?a.k():a.j();a.F()?a.b():a.g();a.F()?a.j():a.k()}x(Vc,Bc);function Wc(){}x(Wc,V);p=Wc.prototype;p.a=k;p.m=k;p.Q=k;p.s=function(){this.Q=this.m=k};p.fa=o("control");p.W=function(){return this.a||document.body.createControlRange()};p.D=function(){return this.a?this.a.length:0};p.A=function (a){a=this.a.item(a);return Ec(Fc(a),h)};p.C=function(){return fb.apply(k,Uc(this))};p.b=function(){return Xc(this)[0]};p.j=o(0);p.g=function(){var a=Xc(this),b=z(a);return Pa(a,function (a){return G(a,b)})};p.k=function(){return this.g().childNodes.length};
-function Uc(a){if(!a.m&&(a.m=[],a.a))for(var b=0;b<a.a.length;b++)a.m.push(a.a.item(b));return a.m}function Xc(a){a.Q||(a.Q=Uc(a).concat(),a.Q.sort(function (a,c){return a.sourceIndex-c.sourceIndex}));return a.Q}p.isCollapsed=function(){return!this.a||!this.a.length};p.r=function(){return new Yc(this)};p.select=function(){this.a&&this.a.select()};p.ga=function(){return new Zc(this)};p.collapse=function(){this.a=k;this.s()};function Zc(a){this.m=Uc(a)}x(Zc,Bc);
-function Yc(a){a&&(this.m=Xc(a),this.f=this.m.shift(),this.d=z(this.m)||this.f);U.call(this,this.f,l)}x(Yc,U);p=Yc.prototype;p.f=k;p.d=k;p.m=k;p.b=n("f");p.g=n("d");p.M=function(){return!this.depth&&!this.m.length};p.next=function(){this.M()&&g(I);if(!this.depth){var a=this.m.shift();L(this,a,1,1);return a}return Yc.$.next.call(this)};function $c(){this.t=[];this.P=[];this.U=this.I=k}x($c,V);p=$c.prototype;p.Ea=Ac("goog.dom.MultiRange");p.s=function(){this.P=[];this.U=this.I=k};p.fa=o("mutli");p.W=function(){1<this.t.length&&this.Ea.log(vc,"getBrowserRangeObject called on MultiRange with more than 1 range",h);return this.t[0]};p.D=function(){return this.t.length};p.A=function (a){this.P[a]||(this.P[a]=Ec(new W(this.t[a]),h));return this.P[a]};
-p.C=function(){if(!this.U){for(var a=[],b=0,c=this.D();b<c;b++)a.push(this.A(b).C());this.U=fb.apply(k,a)}return this.U};function ad(a){a.I||(a.I=Dc(a),a.I.sort(function (a,c){var d=a.b(),e=a.j(),f=c.b(),j=c.j();return d==f&&e==j?0:Lc(d,e,f,j)?1:-1}));return a.I}p.b=function(){return ad(this)[0].b()};p.j=function(){return ad(this)[0].j()};p.g=function(){return z(ad(this)).g()};p.k=function(){return z(ad(this)).k()};p.isCollapsed=function(){return 0==this.t.length||1==this.t.length&&this.A(0).isCollapsed()};
-p.r=function(){return new bd(this)};p.select=function(){var a=Cc(this.qa());a.removeAllRanges();for(var b=0,c=this.D();b<c;b++)a.addRange(this.A(b).W())};p.ga=function(){return new cd(this)};p.collapse=function (a){if(!this.isCollapsed()){var b=a?this.A(0):this.A(this.D()-1);this.s();b.collapse(a);this.P=[b];this.I=[b];this.t=[b.W()]}};function cd(a){Ma(Dc(a),function (a){return a.ga()})}x(cd,Bc);function bd(a){a&&(this.H=Ma(ad(a),function (a){return sb(a)}));U.call(this,a?this.b():k,l)}x(bd,U);p=bd.prototype;
-p.H=k;p.V=0;p.b=function(){return this.H[0].b()};p.g=function(){return z(this.H).g()};p.M=function(){return this.H[this.V].M()};p.next=function(){try{var a=this.H[this.V],b=a.next();L(this,a.p,a.q,a.depth);return b}catch(c){return(c!==I||this.H.length-1==this.V)&&g(c),this.V++,this.next()}};function Jc(a){var b,c=l;if(a.createRange)try{b=a.createRange()}catch(d){return k}else if(a.rangeCount){if(1<a.rangeCount){b=new $c;for(var c=0,e=a.rangeCount;c<e;c++)b.t.push(a.getRangeAt(c));return b}b=a.getRangeAt(0);c=Lc(a.anchorNode,a.anchorOffset,a.focusNode,a.focusOffset)}else return k;b&&b.addElement?(a=new Wc,a.a=b):a=Ec(new W(b),c);return a}
-function Lc(a,b,c,d){if(a==c)return d<b;var e;if(1==a.nodeType&&b)if(e=a.childNodes[b])a=e,b=0;else if(G(a,c))return i;if(1==c.nodeType&&d)if(e=c.childNodes[d])c=e,d=0;else if(G(c,a))return l;return 0<(cb(a,c)||b-d)};function dd(){N.call(this);this.ja=k;this.B=new B(0,0);this.sa=l}x(dd,N);var Z={};Z[Zb]=[0,1,2,k];Z[$b]=[k,k,2,k];Z[fc]=[0,1,2,k];Z[dc]=[0,0,0,0];Z[cc]=[0,0,0,0];Z[ac]=Z[Zb];Z[bc]=Z[fc];Z[ec]=Z[dc];dd.prototype.move=function (a,b){var c=xb(a);this.B.x=b.x+c.x;this.B.y=b.y+c.y;a!=this.z()&&(c=this.z()===Ca.document.documentElement||this.z()===Ca.document.body,c=!this.sa&&c?k:this.z(),ed(this,dc,a),Ob(this,a),ed(this,ec,c));ed(this,cc)};
-function ed(a,b,c){a.sa=i;var d=a.B,e;b in Z?(e=Z[b][a.ja===k?3:a.ja],e===k&&g(new y(13,"Event does not permit the specified mouse button."))):e=0;Mb(a.w,i)&&Eb(a.w)&&(c&&!(ec==b||dc==b)&&g(new y(12,"Event type does not allow related target: "+b)),c={clientX:d.x,clientY:d.y,button:e,altKey:l,ctrlKey:l,shiftKey:l,metaKey:l,wheelDelta:0,relatedTarget:c||k},(a=a.w)&&Sb(a,b,c))};function fd(){N.call(this);this.B=new B(0,0);this.ca=new B(0,0)}x(fd,N);fd.prototype.xa=0;fd.prototype.wa=0;fd.prototype.move=function (a,b,c){this.X()||Ob(this,a);a=xb(a);this.B.x=b.x+a.x;this.B.y=b.y+a.y;r(c)&&(this.ca.x=c.x+a.x,this.ca.y=c.y+a.y);if(this.X()){b=Rb;this.X()||g(new y(13,"Should never fire event when touchscreen is not pressed."));var d,e;this.wa&&(d=this.wa,e=this.ca);Pb(this,b,this.xa,this.B,d,e)}};fd.prototype.X=function(){return!!this.xa};function gd(a,b){this.x=a;this.y=b}x(gd,B);gd.prototype.scale=function (a){this.x*=a;this.y*=a;return this};gd.prototype.add=function (a){this.x+=a.x;this.y+=a.y;return this};function hd(){N.call(this)}x(hd,N);(function (a){a.Ba=function(){return a.Da||(a.Da=new a)}})(hd);function id(a){(!Mb(a,i)||!Eb(a))&&g(new y(12,"Element is not currently interactable and may not be manipulated"));(!Gb(a)||Bb(a,"readOnly"))&&g(new y(12,"Element must be user-editable in order to clear it."));var b=hd.Ba();Ob(b,a);var b=b.ua||b.w,c=D(b).activeElement;if(b!=c){if(c&&w(c.blur))try{c.blur()}catch(d){g(d)}w(b.focus)&&b.focus()}a.value&&(a.value="",Sb(a,Yb));Hb(a)&&(a.innerHTML=" ")}var jd=["_"],$=q;!(jd[0]in $)&&$.execScript&&$.execScript("var "+jd[0]);
-for(var ld;jd.length&&(ld=jd.shift());)!jd.length&&r(id)?$[ld]=id:$=$[ld]?$[ld]:$[ld]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
-
-atom.getElementAttribute = function (element, name, window){return function(){var f=null,g=!1,h=this;
-function i(a){var c=typeof a;if("object"==c)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if("[object Window]"==b)return"object";if("[object Array]"==b||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==b||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==
-c&&"undefined"==typeof a.call)return"object";return c}function j(a,c){function b(){}b.prototype=c.prototype;a.f=c.prototype;a.prototype=new b};function k(a,c){for(var b=1;b<arguments.length;b++)var d=(""+arguments[b]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a}function l(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};var m,n="",o=/rv\:([^\);]+)(\)|;)/.exec(h.navigator?h.navigator.userAgent:f);m=n=o?o[1]:"";var p={};function q(a,c){this.code=a;this.message=c||"";this.name=r[a]||r[13];var b=Error(this.message);b.name=this.name;this.stack=b.stack||""}j(q,Error);
-var r={7:"NoSuchElementError",8:"NoSuchFrameError",9:"UnknownCommandError",10:"StaleElementReferenceError",11:"ElementNotVisibleError",12:"InvalidElementStateError",13:"UnknownError",15:"ElementNotSelectableError",19:"XPathLookupError",23:"NoSuchWindowError",24:"InvalidCookieDomainError",25:"UnableToSetCookieError",26:"ModalDialogOpenedError",27:"NoModalDialogOpenError",28:"ScriptTimeoutError",32:"InvalidSelectorError",33:"SqlDatabaseError",34:"MoveTargetOutOfBoundsError"};
-q.prototype.toString=function(){return"["+this.name+"] "+this.message};function s(a){this.stack=Error().stack||"";a&&(this.message=""+a)}j(s,Error);s.prototype.name="CustomError";function t(a,c){c.unshift(a);s.call(this,k.apply(f,c));c.shift()}j(t,s);t.prototype.name="AssertionError";function u(a,c){if("string"==typeof a)return"string"!=typeof c||1!=c.length?-1:a.indexOf(c,0);for(var b=0;b<a.length;b++)if(b in a&&a[b]===c)return b;return-1};if(!p["1.9.1"]){for(var v=0,w=l(""+m).split("."),x=l("1.9.1").split("."),y=Math.max(w.length,x.length),z=0;0==v&&z<y;z++){var A=w[z]||"",B=x[z]||"",C=RegExp("(\\d*)(\\D*)","g"),D=RegExp("(\\d*)(\\D*)","g");do{var E=C.exec(A)||["","",""],F=D.exec(B)||["","",""];if(0==E[0].length&&0==F[0].length)break;v=((0==E[1].length?0:parseInt(E[1],10))<(0==F[1].length?0:parseInt(F[1],10))?-1:(0==E[1].length?0:parseInt(E[1],10))>(0==F[1].length?0:parseInt(F[1],10))?1:0)||((0==E[2].length)<(0==F[2].length)?-1:(0==
-E[2].length)>(0==F[2].length)?1:0)||(E[2]<F[2]?-1:E[2]>F[2]?1:0)}while(0==v)}p["1.9.1"]=0<=v};var G={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},H={IMG:" ",BR:"\n"};function I(a,c,b){if(!(a.nodeName in G))if(3==a.nodeType)b?c.push((""+a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):c.push(a.nodeValue);else if(a.nodeName in H)c.push(H[a.nodeName]);else for(a=a.firstChild;a;)I(a,c,b),a=a.nextSibling};(function(){var a=h.Components;if(!a)return g;try{if(!a.classes)return g}catch(c){return g}var b=a.classes,a=a.interfaces;b["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);b["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();var J="StopIteration"in h?h.StopIteration:Error("StopIteration");function K(){}K.prototype.next=function(){throw J;};function L(a,c,b,d,e){this.a=!!c;a&&M(this,a,d);this.depth=void 0!=e?e:this.c||0;this.a&&(this.depth*=-1);this.e=!b}j(L,K);L.prototype.b=f;L.prototype.c=0;L.prototype.d=g;function M(a,c,b){if(a.b=c)a.c="number"==typeof b?b:1!=a.b.nodeType?0:a.a?-1:1}
-L.prototype.next=function(){var a;if(this.d){if(!this.b||this.e&&0==this.depth)throw J;a=this.b;var c=this.a?-1:1;if(this.c==c){var b=this.a?a.lastChild:a.firstChild;b?M(this,b):M(this,a,-1*c)}else(b=this.a?a.previousSibling:a.nextSibling)?M(this,b):M(this,a.parentNode,-1*c);this.depth+=this.c*(this.a?-1:1)}else this.d=!0;a=this.b;if(!this.b)throw J;return a};
-L.prototype.splice=function (a){var c=this.b,b=this.a?1:-1;this.c==b&&(this.c=-1*b,this.depth+=this.c*(this.a?-1:1));this.a=!this.a;L.prototype.next.call(this);this.a=!this.a;for(var b=arguments[0],d=i(b),b="array"==d||"object"==d&&"number"==typeof b.length?arguments[0]:arguments,d=b.length-1;0<=d;d--)c.parentNode&&c.parentNode.insertBefore(b[d],c.nextSibling);c&&c.parentNode&&c.parentNode.removeChild(c)};function N(a,c,b,d){L.call(this,a,c,b,f,d)}j(N,L);N.prototype.next=function(){do N.f.next.call(this);while(-1==this.c);return this.b};function O(a,c){return!!a&&1==a.nodeType&&(!c||a.tagName.toUpperCase()==c)}function P(a){return O(a,"OPTION")?!0:O(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):g}var Q={"class":"className",readonly:"readOnly"},R=["checked","disabled","draggable","hidden"];
-function S(a,c){var b=Q[c]||c,d=a[b];if(void 0===d&&0<=u(R,b))return g;if(b="value"==c)if(b=O(a,"OPTION")){var e;b=c.toLowerCase();if(a.hasAttribute)e=a.hasAttribute(b);else try{e=a.attributes[b].specified}catch(Y){e=g}b=!e}b&&(d=[],I(a,d,g),d=d.join(""));return d}var T="async,autofocus,autoplay,checked,compact,complete,controls,declare,defaultchecked,defaultselected,defer,disabled,draggable,ended,formnovalidate,hidden,indeterminate,iscontenteditable,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,paused,pubdate,readonly,required,reversed,scoped,seamless,seeking,selected,spellcheck,truespeed,willvalidate".split(",");
-function U(a,c){if(8==a.nodeType)return f;c=c.toLowerCase();if("style"==c){var b=l(a.style.cssText).toLowerCase();return b=";"==b.charAt(b.length-1)?b:b+";"}b=a.getAttributeNode(c);return!b?f:0<=u(T,c)?"true":b.specified?b.value:f};function V(a,c){var b=f,d=c.toLowerCase();if("style"==c.toLowerCase()){if((b=a.style)&&"string"!=typeof b)b=b.cssText;return b}if("selected"==d||"checked"==d&&P(a)){if(!P(a))throw new q(15,"Element is not selectable");var e="selected",d=a.type&&a.type.toLowerCase();if("checkbox"==d||"radio"==d)e="checked";return S(a,e)?"true":f}b=O(a,"A");if(O(a,"IMG")&&"src"==d||b&&"href"==d)return(b=U(a,d))&&(b=S(a,d)),b;try{e=S(a,c)}catch(Y){}if(!(d=e==f))d=i(e),d="object"==d||"array"==d||"function"==d;b=d?U(a,
-c):e;return b!=f?b.toString():f}var W=["_"],X=h;!(W[0]in X)&&X.execScript&&X.execScript("var "+W[0]);for(var Z;W.length&&(Z=W.shift());)!W.length&&void 0!==V?X[Z]=V:X=X[Z]?X[Z]:X[Z]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
-
-atom.getElementText = function (element, window){return function(){var g=void 0,h=!0,i=null,j=!1,k=this;
-function l(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
-else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function m(a){return"string"==typeof a}function n(a,b){function c(){}c.prototype=b.prototype;a.h=b.prototype;a.prototype=new c};function o(a){var b=a.length-1;return 0<=b&&a.indexOf(" ",b)==b}function aa(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a}function p(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}var q={};function ba(a){return q[a]||(q[a]=(""+a).replace(/\-([a-z])/g,function (a,c){return c.toUpperCase()}))};var s,ca="",u=/rv\:([^\);]+)(\)|;)/.exec(k.navigator?k.navigator.userAgent:i);s=ca=u?u[1]:"";var v={};var da=window;function w(a,b){this.code=a;this.message=b||"";this.name=x[a]||x[13];var c=Error(this.message);c.name=this.name;this.stack=c.stack||""}n(w,Error);
-var x={7:"NoSuchElementError",8:"NoSuchFrameError",9:"UnknownCommandError",10:"StaleElementReferenceError",11:"ElementNotVisibleError",12:"InvalidElementStateError",13:"UnknownError",15:"ElementNotSelectableError",19:"XPathLookupError",23:"NoSuchWindowError",24:"InvalidCookieDomainError",25:"UnableToSetCookieError",26:"ModalDialogOpenedError",27:"NoModalDialogOpenError",28:"ScriptTimeoutError",32:"InvalidSelectorError",33:"SqlDatabaseError",34:"MoveTargetOutOfBoundsError"};
-w.prototype.toString=function(){return"["+this.name+"] "+this.message};function y(a){this.stack=Error().stack||"";a&&(this.message=""+a)}n(y,Error);y.prototype.name="CustomError";function z(a,b){b.unshift(a);y.call(this,aa.apply(i,b));b.shift()}n(z,y);z.prototype.name="AssertionError";function ea(a,b){for(var c=a.length,d=m(a)?a.split(""):a,e=0;e<c;e++)e in d&&b.call(g,d[e],e,a)}function fa(a,b){for(var c=a.length,d=m(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(g,d[e],e,a))return h;return j}function A(a,b){var c;a:if(m(a))c=!m(b)||1!=b.length?-1:a.indexOf(b,0);else{for(c=0;c<a.length;c++)if(c in a&&a[c]===b)break a;c=-1}return 0<=c};var B;
-if(!v["1.9.1"]){for(var C=0,D=p(""+s).split("."),E=p("1.9.1").split("."),ga=Math.max(D.length,E.length),F=0;0==C&&F<ga;F++){var ha=D[F]||"",ia=E[F]||"",ja=RegExp("(\\d*)(\\D*)","g"),ka=RegExp("(\\d*)(\\D*)","g");do{var G=ja.exec(ha)||["","",""],H=ka.exec(ia)||["","",""];if(0==G[0].length&&0==H[0].length)break;C=((0==G[1].length?0:parseInt(G[1],10))<(0==H[1].length?0:parseInt(H[1],10))?-1:(0==G[1].length?0:parseInt(G[1],10))>(0==H[1].length?0:parseInt(H[1],10))?1:0)||((0==G[2].length)<(0==H[2].length)?-1:
-(0==G[2].length)>(0==H[2].length)?1:0)||(G[2]<H[2]?-1:G[2]>H[2]?1:0)}while(0==C)}v["1.9.1"]=0<=C};function I(a,b){this.x=a!==g?a:0;this.y=b!==g?b:0}I.prototype.toString=function(){return"("+this.x+", "+this.y+")"};function J(a,b){this.width=a;this.height=b}J.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};var K=3;function L(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function la(a,b){var c=[];return M(a,b,c,h)?c[0]:g}function M(a,b,c,d){if(a!=i)for(a=a.firstChild;a;){if(b(a)&&(c.push(a),d)||M(a,b,c,d))return h;a=a.nextSibling}return j}function ma(a,b){for(var a=a.parentNode,c=0;a;){if(b(a))return a;a=a.parentNode;c++}return i}function N(a){this.g=a||k.document||document}
-function na(a){var b=a.g,a="CSS1Compat"==b.compatMode?b.documentElement:b.body,b=b.parentWindow||b.defaultView;return new I(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)};var oa=function(){var a={i:"http://www.w3.org/2000/svg"};return function (b){return a[b]||i}}();
-function pa(a,b){var c=function(){var c;a:{var e=L(b);if(e.implementation.hasFeature("XPath","3.0")){try{var f=e.createNSResolver?e.createNSResolver(e.documentElement):oa;c=e.evaluate(a,b,f,9,i);break a}catch(r){if("NS_ERROR_ILLEGAL_VALUE"!=r.name)throw new w(32,"Unable to locate an element with the xpath expression "+a+" because of the following error:\n"+r);}c=g}else c=i}return c?c.singleNodeValue||i:b.selectSingleNode?(c=L(b),c.setProperty&&c.setProperty("SelectionLanguage","XPath"),b.selectSingleNode(a)):
-i}();if(c!==i&&(!c||1!=c.nodeType))throw new w(32,'The result of the xpath expression "'+a+'" is: '+c+". It should be an element.");return c};(function(){var a=k.Components;if(!a)return j;try{if(!a.classes)return j}catch(b){return j}var c=a.classes,a=a.interfaces;c["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);c["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return h})();var P="StopIteration"in k?k.StopIteration:Error("StopIteration");function qa(){}qa.prototype.next=function(){throw P;};function Q(a,b,c,d,e){this.a=!!b;a&&R(this,a,d);this.depth=e!=g?e:this.c||0;this.a&&(this.depth*=-1);this.f=!c}n(Q,qa);Q.prototype.b=i;Q.prototype.c=0;Q.prototype.e=j;function R(a,b,c){if(a.b=b)a.c="number"==typeof c?c:1!=a.b.nodeType?0:a.a?-1:1}
-Q.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&0==this.depth)throw P;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?R(this,c):R(this,a,-1*b)}else(c=this.a?a.previousSibling:a.nextSibling)?R(this,c):R(this,a.parentNode,-1*b);this.depth+=this.c*(this.a?-1:1)}else this.e=h;a=this.b;if(!this.b)throw P;return a};
-Q.prototype.splice=function (a){var b=this.b,c=this.a?1:-1;this.c==c&&(this.c=-1*c,this.depth+=this.c*(this.a?-1:1));this.a=!this.a;Q.prototype.next.call(this);this.a=!this.a;for(var c=arguments[0],d=l(c),c="array"==d||"object"==d&&"number"==typeof c.length?arguments[0]:arguments,d=c.length-1;0<=d;d--)b.parentNode&&b.parentNode.insertBefore(c[d],b.nextSibling);b&&b.parentNode&&b.parentNode.removeChild(b)};function S(a,b,c,d){Q.call(this,a,b,c,i,d)}n(S,Q);S.prototype.next=function(){do S.h.next.call(this);while(-1==this.c);return this.b};function ra(a,b){var c=L(a);return c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(a,i))?c[b]||c.getPropertyValue(b):""}function T(a,b){return ra(a,b)||(a.currentStyle?a.currentStyle[b]:i)||a.style&&a.style[b]}
-function sa(a){for(var b=L(a),c=T(a,"position"),d="fixed"==c||"absolute"==c,a=a.parentNode;a&&a!=b;a=a.parentNode)if(c=T(a,"position"),d=d&&"static"==c&&a!=b.documentElement&&a!=b.body,!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c||"absolute"==c||"relative"==c))return a;return i}
-function ta(a){var b=new I;if(1==a.nodeType)if(a.getBoundingClientRect)a=a.getBoundingClientRect(),b.x=a.left,b.y=a.top;else{var c=na(a?new N(L(a)):B||(B=new N));var d,e=L(a),f=T(a,"position"),r=e.getBoxObjectFor&&!a.getBoundingClientRect&&"absolute"==f&&(d=e.getBoxObjectFor(a))&&(0>d.screenX||0>d.screenY),f=new I(0,0),t=(e?9==e.nodeType?e:L(e):document).documentElement;if(a!=t)if(a.getBoundingClientRect)d=a.getBoundingClientRect(),a=na(e?new N(L(e)):B||(B=new N)),f.x=d.left+a.x,f.y=d.top+a.y;else if(e.getBoxObjectFor&&
-!r)d=e.getBoxObjectFor(a),a=e.getBoxObjectFor(t),f.x=d.screenX-a.screenX,f.y=d.screenY-a.screenY;else{d=a;do f.x+=d.offsetLeft,f.y+=d.offsetTop,d!=a&&(f.x+=d.clientLeft||0,f.y+=d.clientTop||0),d=d.offsetParent;while(d&&d!=a);for(d=a;(d=sa(d))&&d!=e.body&&d!=t;)f.x-=d.scrollLeft,f.y-=d.scrollTop}b.x=f.x-c.x;b.y=f.y-c.y}else c="function"==l(a.d),d=a,a.targetTouches?d=a.targetTouches[0]:c&&a.d().targetTouches&&(d=a.d().targetTouches[0]),b.x=d.clientX,b.y=d.clientY;return b}
-function ua(a){var b=a.offsetWidth,c=a.offsetHeight;return b===g&&a.getBoundingClientRect?(a=a.getBoundingClientRect(),new J(a.right-a.left,a.bottom-a.top)):new J(b,c)};function U(a,b){return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}var va="async,autofocus,autoplay,checked,compact,complete,controls,declare,defaultchecked,defaultselected,defer,disabled,draggable,ended,formnovalidate,hidden,indeterminate,iscontenteditable,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,paused,pubdate,readonly,required,reversed,scoped,seamless,seeking,selected,spellcheck,truespeed,willvalidate".split(",");
-function V(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return U(a)?a:i}function W(a,b){b=ba(b);return ra(a,b)||wa(a,b)}function wa(a,b){var c=a.currentStyle||a.style,d=c[b];d===g&&"function"==l(c.getPropertyValue)&&(d=c.getPropertyValue(b));return"inherit"!=d?d!==g?d:i:(c=V(a))?wa(c,b):i}
-function xa(a){if("function"==l(a.getBBox))try{var b=a.getBBox();if(b)return b}catch(c){}if("none"!=T(a,"display"))a=ua(a);else{var b=a.style,d=b.display,e=b.visibility,f=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";a=ua(a);b.display=d;b.position=f;b.visibility=e}return a}
-function X(a,b){function c(a){if("none"==W(a,"display"))return j;a=V(a);return!a||c(a)}function d(a){var b=xa(a);return 0<b.height&&0<b.width?h:fa(a.childNodes,function (a){return a.nodeType==K||U(a)&&d(a)})}function e(a){var b=V(a);if(b&&"hidden"==W(b,"overflow")){var c=xa(b),d=ta(b),a=ta(a);return d.x+c.width<a.x||d.y+c.height<a.y?j:e(b)}return h}if(!U(a))throw Error("Argument to isShown must be of type Element");if(U(a,"OPTION")||U(a,"OPTGROUP")){var f=ma(a,function (a){return U(a,"SELECT")});return!!f&&
-X(f,h)}if(U(a,"MAP")){if(!a.name)return j;f=L(a);f=f.evaluate?pa('/descendant::*[@usemap = "#'+a.name+'"]',f):la(f,function (b){var c;if(c=U(b))8==b.nodeType?b=i:(c="usemap","style"==c?(b=p(b.style.cssText).toLowerCase(),b=";"==b.charAt(b.length-1)?b:b+";"):(b=b.getAttributeNode(c),b=!b?i:A(va,c)?"true":b.specified?b.value:i)),c=b=="#"+a.name;return c});return!!f&&X(f,b)}return U(a,"AREA")?(f=ma(a,function (a){return U(a,"MAP")}),!!f&&X(f,b)):U(a,"INPUT")&&"hidden"==a.type.toLowerCase()||U(a,"NOSCRIPT")||
-"hidden"==W(a,"visibility")||!c(a)||!b&&0==ya(a)||!d(a)||!e(a)?j:h}function za(a){return a.replace(/^[^\S\xa0]+|[^\S\xa0]+$/g,"")}
-function Aa(a,b){if(U(a,"BR"))b.push("");else{var c=U(a,"TD"),d=W(a,"display"),e=!c&&!A(Ba,d);e&&!/^[\s\xa0]*$/.test(b[b.length-1]||"")&&b.push("");var f=X(a),r=i,t=i;f&&(r=W(a,"white-space"),t=W(a,"text-transform"));ea(a.childNodes,function (a){a.nodeType==K&&f?Ca(a,b,r,t):U(a)&&Aa(a,b)});var O=b[b.length-1]||"";if((c||"table-cell"==d)&&O&&!o(O))b[b.length-1]+=" ";e&&!/^[\s\xa0]*$/.test(O)&&b.push("")}}var Ba="inline,inline-block,inline-table,none,table-cell,table-column,table-column-group".split(",");
-function Ca(a,b,c,d){a=a.nodeValue.replace(/\u200b/g,"");a=a.replace(/(\r\n|\r|\n)/g,"\n");if("normal"==c||"nowrap"==c)a=a.replace(/\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \f\t\v\u2028\u2029]/g,"\u00a0"):a.replace(/[\ \f\t\v\u2028\u2029]+/g," ");"capitalize"==d?a=a.replace(/(^|\s)(\S)/g,function (a,b,c){return b+c.toUpperCase()}):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";o(c)&&0==a.lastIndexOf(" ",0)&&(a=a.substr(1));b.push(c+a)}
-function ya(a){var b=1,c=W(a,"opacity");c&&(b=Number(c));(a=V(a))&&(b*=ya(a));return b};function Da(a){var b;a:{for(b=a;b;){if(b.tagName&&"head"==b.tagName.toLowerCase()){b=h;break a}try{b=b.parentNode}catch(c){break}}b=j}if(b)return b=L(a),"TITLE"==a.tagName.toUpperCase()&&(b?b.parentWindow||b.defaultView:window)==da.top?p(b.title):"";b=[];Aa(a,b);var d=b,a=d.length;b=Array(a);for(var d=m(d)?d.split(""):d,e=0;e<a;e++)e in d&&(b[e]=za.call(g,d[e]));return za(b.join("\n")).replace(/\xa0/g," ")}var Y=["_"],Z=k;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);
-for(var $;Y.length&&($=Y.shift());)!Y.length&&Da!==g?Z[$]=Da:Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
-
-atom.isElementEnabled = function (element, window){return function(){var e=this;function f(a,c){function b(){}b.prototype=c.prototype;a.d=c.prototype;a.prototype=new b};function g(a,c){for(var b=1;b<arguments.length;b++)var d=(""+arguments[b]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a};var h,i="",j=/rv\:([^\);]+)(\)|;)/.exec(e.navigator?e.navigator.userAgent:null);h=i=j?j[1]:"";var k={};function l(a,c){this.code=a;this.message=c||"";this.name=m[a]||m[13];var b=Error(this.message);b.name=this.name;this.stack=b.stack||""}f(l,Error);
-var m={7:"NoSuchElementError",8:"NoSuchFrameError",9:"UnknownCommandError",10:"StaleElementReferenceError",11:"ElementNotVisibleError",12:"InvalidElementStateError",13:"UnknownError",15:"ElementNotSelectableError",19:"XPathLookupError",23:"NoSuchWindowError",24:"InvalidCookieDomainError",25:"UnableToSetCookieError",26:"ModalDialogOpenedError",27:"NoModalDialogOpenError",28:"ScriptTimeoutError",32:"InvalidSelectorError",33:"SqlDatabaseError",34:"MoveTargetOutOfBoundsError"};
-l.prototype.toString=function(){return"["+this.name+"] "+this.message};function n(a){this.stack=Error().stack||"";a&&(this.message=""+a)}f(n,Error);n.prototype.name="CustomError";function o(a,c){c.unshift(a);n.call(this,g.apply(null,c));c.shift()}f(o,n);o.prototype.name="AssertionError";function p(a,c){var b;a:if("string"==typeof a)b="string"!=typeof c||1!=c.length?-1:a.indexOf(c,0);else{for(b=0;b<a.length;b++)if(b in a&&a[b]===c)break a;b=-1}return 0<=b};if(!k["1.9.1"]){for(var q=0,r=(""+h).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),s="1.9.1".replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),t=Math.max(r.length,s.length),u=0;0==q&&u<t;u++){var v=r[u]||"",w=s[u]||"",x=RegExp("(\\d*)(\\D*)","g"),z=RegExp("(\\d*)(\\D*)","g");do{var A=x.exec(v)||["","",""],B=z.exec(w)||["","",""];if(0==A[0].length&&0==B[0].length)break;q=((0==A[1].length?0:parseInt(A[1],10))<(0==B[1].length?0:parseInt(B[1],10))?-1:(0==A[1].length?0:parseInt(A[1],10))>(0==B[1].length?
-0:parseInt(B[1],10))?1:0)||((0==A[2].length)<(0==B[2].length)?-1:(0==A[2].length)>(0==B[2].length)?1:0)||(A[2]<B[2]?-1:A[2]>B[2]?1:0)}while(0==q)}k["1.9.1"]=0<=q};(function(){var a=e.Components;if(!a)return!1;try{if(!a.classes)return!1}catch(c){return!1}var b=a.classes,a=a.interfaces;b["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);b["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();function C(a,c,b,d,y){this.b=!!c;if(a&&(this.a=a))this.c="number"==typeof d?d:1!=this.a.nodeType?0:this.b?-1:1;this.depth=void 0!=y?y:this.c||0;this.b&&(this.depth*=-1)}f(C,function(){});C.prototype.a=null;C.prototype.c=0;f(function (a,c,b,d){C.call(this,a,c,0,null,d)},C);var D={"class":"className",readonly:"readOnly"},E=["checked","disabled","draggable","hidden"],F="BUTTON,INPUT,OPTGROUP,OPTION,SELECT,TEXTAREA".split(",");function G(a){var c=a.tagName.toUpperCase();if(p(F,c)){var b;b=D.disabled||"disabled";var d=a[b];b=void 0===d&&p(E,b)?!1:d;a=b?!1:a.parentNode&&1==a.parentNode.nodeType&&"OPTGROUP"==c||"OPTION"==c?G(a.parentNode):!0}else a=!0;return a};var H=G,I=["_"],J=e;!(I[0]in J)&&J.execScript&&J.execScript("var "+I[0]);for(var K;I.length&&(K=I.shift());)!I.length&&void 0!==H?J[K]=H:J=J[K]?J[K]:J[K]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
-
-atom.isElementSelected = function (element, window){return function(){var f=!1,g=this;function h(a,b){function c(){}c.prototype=b.prototype;a.d=b.prototype;a.prototype=new c};function i(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a};var k,l="",m=/rv\:([^\);]+)(\)|;)/.exec(g.navigator?g.navigator.userAgent:null);k=l=m?m[1]:"";var n={};function o(a,b){this.code=a;this.message=b||"";this.name=p[a]||p[13];var c=Error(this.message);c.name=this.name;this.stack=c.stack||""}h(o,Error);
-var p={7:"NoSuchElementError",8:"NoSuchFrameError",9:"UnknownCommandError",10:"StaleElementReferenceError",11:"ElementNotVisibleError",12:"InvalidElementStateError",13:"UnknownError",15:"ElementNotSelectableError",19:"XPathLookupError",23:"NoSuchWindowError",24:"InvalidCookieDomainError",25:"UnableToSetCookieError",26:"ModalDialogOpenedError",27:"NoModalDialogOpenError",28:"ScriptTimeoutError",32:"InvalidSelectorError",33:"SqlDatabaseError",34:"MoveTargetOutOfBoundsError"};
-o.prototype.toString=function(){return"["+this.name+"] "+this.message};function q(a){this.stack=Error().stack||"";a&&(this.message=""+a)}h(q,Error);q.prototype.name="CustomError";function r(a,b){b.unshift(a);q.call(this,i.apply(null,b));b.shift()}h(r,q);r.prototype.name="AssertionError";if(!n["1.9.1"]){for(var s=0,t=(""+k).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),u="1.9.1".replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),v=Math.max(t.length,u.length),w=0;0==s&&w<v;w++){var x=t[w]||"",y=u[w]||"",z=RegExp("(\\d*)(\\D*)","g"),A=RegExp("(\\d*)(\\D*)","g");do{var B=z.exec(x)||["","",""],C=A.exec(y)||["","",""];if(0==B[0].length&&0==C[0].length)break;s=((0==B[1].length?0:parseInt(B[1],10))<(0==C[1].length?0:parseInt(C[1],10))?-1:(0==B[1].length?0:parseInt(B[1],10))>(0==C[1].length?
-0:parseInt(C[1],10))?1:0)||((0==B[2].length)<(0==C[2].length)?-1:(0==B[2].length)>(0==C[2].length)?1:0)||(B[2]<C[2]?-1:B[2]>C[2]?1:0)}while(0==s)}n["1.9.1"]=0<=s};var D={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},E={IMG:" ",BR:"\n"};function F(a,b,c){if(!(a.nodeName in D))if(3==a.nodeType)c?b.push((""+a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in E)b.push(E[a.nodeName]);else for(a=a.firstChild;a;)F(a,b,c),a=a.nextSibling};(function(){var a=g.Components;if(!a)return f;try{if(!a.classes)return f}catch(b){return f}var c=a.classes,a=a.interfaces;c["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);c["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();function G(a,b,c,d,e){this.b=!!b;if(a&&(this.a=a))this.c="number"==typeof d?d:1!=this.a.nodeType?0:this.b?-1:1;this.depth=void 0!=e?e:this.c||0;this.b&&(this.depth*=-1)}h(G,function(){});G.prototype.a=null;G.prototype.c=0;h(function (a,b,c,d){G.call(this,a,b,0,null,d)},G);function H(a,b){return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}function I(a){return H(a,"OPTION")?!0:H(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):f}var J={"class":"className",readonly:"readOnly"},K=["checked","disabled","draggable","hidden"];function L(a){if(I(a)){if(!I(a))throw new o(15,"Element is not selectable");var b="selected",c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";var c=b,d=J[c]||c,b=a[d],e;if(e=void 0===b){b:if("string"==typeof K)d="string"!=typeof d||1!=d.length?-1:K.indexOf(d,0);else{for(e=0;e<K.length;e++)if(e in K&&K[e]===d){d=e;break b}d=-1}e=0<=d}if(e)a=f;else{if(d="value"==c)if(d=H(a,"OPTION")){var j;c=c.toLowerCase();if(a.hasAttribute)j=a.hasAttribute(c);else try{j=a.attributes[c].specified}catch(P){j=
-f}d=!j}d&&(j=[],F(a,j,f),b=j.join(""));a=b}a=!!a}else a=f;return a}var M=["_"],N=g;!(M[0]in N)&&N.execScript&&N.execScript("var "+M[0]);for(var O;M.length&&(O=M.shift());)!M.length&&void 0!==L?N[O]=L:N=N[O]?N[O]:N[O]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
-
-atom.isElementDisplayed = function (element, window){return function(){function h(a){return function(){return a}}var k=this;
-function m(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
-else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function n(a){return"string"==typeof a};function q(a){var b=0,c=String(r).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split(".");a=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split(".");for(var d=Math.max(c.length,a.length),e=0;0==b&&e<d;e++){var f=c[e]||"",g=a[e]||"",w=RegExp("(\\d*)(\\D*)","g"),p=RegExp("(\\d*)(\\D*)","g");do{var l=w.exec(f)||["","",""],v=p.exec(g)||["","",""];if(0==l[0].length&&0==v[0].length)break;b=((0==l[1].length?0:parseInt(l[1],10))<(0==v[1].length?0:parseInt(v[1],10))?-1:(0==l[1].length?0:parseInt(l[1],10))>(0==v[1].length?
-0:parseInt(v[1],10))?1:0)||((0==l[2].length)<(0==v[2].length)?-1:(0==l[2].length)>(0==v[2].length)?1:0)||(l[2]<v[2]?-1:l[2]>v[2]?1:0)}while(0==b)}return b}function aa(a){return String(a).replace(/\-([a-z])/g,function (a,c){return c.toUpperCase()})};var s=Array.prototype;function t(a,b){for(var c=a.length,d=n(a)?a.split(""):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)}function ba(a,b){if(a.reduce)return a.reduce(b,"");var c="";t(a,function (d,e){c=b.call(void 0,c,d,e,a)});return c}function ca(a,b){for(var c=a.length,d=n(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a))return!0;return!1}
-function da(a,b){var c;a:if(n(a))c=n(b)&&1==b.length?a.indexOf(b,0):-1;else{for(c=0;c<a.length;c++)if(c in a&&a[c]===b)break a;c=-1}return 0<=c}function ea(a,b,c){return 2>=arguments.length?s.slice.call(a,b):s.slice.call(a,b,c)};var u={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",
-darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",
-ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",
-lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",
-moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",
-seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};var fa="background-color border-top-color border-right-color border-bottom-color border-left-color color outline-color".split(" "),ga=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/;function ha(a){if(!x.test(a))throw Error("'"+a+"' is not a valid hex color");4==a.length&&(a=a.replace(ga,"#$1$1$2$2$3$3"));return a.toLowerCase()}var x=/^#(?:[0-9a-f]{3}){1,2}$/i,ia=/^(?:rgba)?\((\d{1,3}),\s?(\d{1,3}),\s?(\d{1,3}),\s?(0|1|0\.\d*)\)$/i;
-function ja(a){var b=a.match(ia);if(b){a=Number(b[1]);var c=Number(b[2]),d=Number(b[3]),b=Number(b[4]);if(0<=a&&255>=a&&0<=c&&255>=c&&0<=d&&255>=d&&0<=b&&1>=b)return[a,c,d,b]}return[]}var ka=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;function la(a){var b=a.match(ka);if(b){a=Number(b[1]);var c=Number(b[2]),b=Number(b[3]);if(0<=a&&255>=a&&0<=c&&255>=c&&0<=b&&255>=b)return[a,c,b]}return[]};function y(a,b){this.code=a;this.state=z[a]||ma;this.message=b||"";var c=this.state.replace(/((?:^|\s+)[a-z])/g,function (a){return a.toUpperCase().replace(/^[\s\xa0]+/g,"")}),d=c.length-5;if(0>d||c.indexOf("Error",d)!=d)c+="Error";this.name=c;c=Error(this.message);c.name=this.name;this.stack=c.stack||""}(function(){var a=Error;function b(){}b.prototype=a.prototype;y.I=a.prototype;y.prototype=new b})();
-var ma="unknown error",z={15:"element not selectable",11:"element not visible",31:"ime engine activation failed",30:"ime not available",24:"invalid cookie domain",29:"invalid element coordinates",12:"invalid element state",32:"invalid selector",51:"invalid selector",52:"invalid selector",17:"javascript error",405:"unsupported operation",34:"move target out of bounds",27:"no such alert",7:"no such element",8:"no such frame",23:"no such window",28:"script timeout",33:"session not created",10:"stale element reference",
-0:"success",21:"timeout",25:"unable to set cookie",26:"unexpected alert open"};z[13]=ma;z[9]="unknown command";y.prototype.toString=function(){return this.name+": "+this.message};var r,na="",oa=/rv\:([^\);]+)(\)|;)/.exec(k.navigator?k.navigator.userAgent:null);r=na=oa?oa[1]:"";var A={};var B;A["1.9.1"]||(A["1.9.1"]=0<=q("1.9.1"));function C(a,b){this.x=void 0!==a?a:0;this.y=void 0!==b?b:0}C.prototype.toString=function(){return"("+this.x+", "+this.y+")"};C.prototype.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};C.prototype.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};C.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};function D(a,b){this.width=a;this.height=b}D.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};D.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};D.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};D.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var pa=3;function E(a,b){if(a.contains&&1==b.nodeType)return a==b||a.contains(b);if("undefined"!=typeof a.compareDocumentPosition)return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a}
-function qa(a,b){if(a==b)return 0;if(a.compareDocumentPosition)return a.compareDocumentPosition(b)&2?1:-1;if("sourceIndex"in a||a.parentNode&&"sourceIndex"in a.parentNode){var c=1==a.nodeType,d=1==b.nodeType;if(c&&d)return a.sourceIndex-b.sourceIndex;var e=a.parentNode,f=b.parentNode;return e==f?ra(a,b):!c&&E(e,b)?-1*sa(a,b):!d&&E(f,a)?sa(b,a):(c?a.sourceIndex:e.sourceIndex)-(d?b.sourceIndex:f.sourceIndex)}d=F(a);c=d.createRange();c.selectNode(a);c.collapse(!0);d=d.createRange();d.selectNode(b);d.collapse(!0);
-return c.compareBoundaryPoints(k.Range.START_TO_END,d)}function sa(a,b){var c=a.parentNode;if(c==b)return-1;for(var d=b;d.parentNode!=c;)d=d.parentNode;return ra(d,a)}function ra(a,b){for(var c=b;c=c.previousSibling;)if(c==a)return-1;return 1}function F(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function ta(a,b){a=a.parentNode;for(var c=0;a;){if(b(a))return a;a=a.parentNode;c++}return null}function G(a){this.p=a||k.document||document}
-function ua(a){var b=a.p;a="CSS1Compat"==b.compatMode?b.documentElement:b.body;b=b.parentWindow||b.defaultView;return new C(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}G.prototype.contains=E;function H(a){var b=null,c=a.nodeType;1==c&&(b=a.textContent,b=void 0==b||null==b?a.innerText:b,b=void 0==b||null==b?"":b);if("string"!=typeof b)if(9==c||1==c){a=9==c?a.documentElement:a.firstChild;for(var c=0,d=[],b="";a;){do 1!=a.nodeType&&(b+=a.nodeValue),d[c++]=a;while(a=a.firstChild);for(;c&&!(a=d[--c].nextSibling););}}else b=a.nodeValue;return""+b}
-function I(a,b,c){if(null===b)return!0;try{if(!a.getAttribute)return!1}catch(d){return!1}return null==c?!!a.getAttribute(b):a.getAttribute(b,2)==c}function J(a,b,c,d,e){return va.call(null,a,b,n(c)?c:null,n(d)?d:null,e||new K)}
-function va(a,b,c,d,e){b.getElementsByName&&d&&"name"==c?(b=b.getElementsByName(d),t(b,function (b){a.matches(b)&&e.add(b)})):b.getElementsByClassName&&d&&"class"==c?(b=b.getElementsByClassName(d),t(b,function (b){b.className==d&&a.matches(b)&&e.add(b)})):b.getElementsByTagName&&(b=b.getElementsByTagName(a.getName()),t(b,function (a){I(a,c,d)&&e.add(a)}));return e}function wa(a,b,c,d,e){for(b=b.firstChild;b;b=b.nextSibling)I(b,c,d)&&a.matches(b)&&e.add(b);return e};function K(){this.d=this.c=null;this.g=0}function xa(a){this.m=a;this.next=this.i=null}K.prototype.unshift=function (a){a=new xa(a);a.next=this.c;this.d?this.c.i=a:this.c=this.d=a;this.c=a;this.g++};K.prototype.add=function (a){a=new xa(a);a.i=this.d;this.c?this.d.next=a:this.c=this.d=a;this.d=a;this.g++};function ya(a){return(a=a.c)?a.m:null}function L(a){return new za(a,!1)}function za(a,b){this.F=a;this.j=(this.n=b)?a.d:a.c;this.r=null}
-za.prototype.next=function(){var a=this.j;if(null==a)return null;var b=this.r=a;this.j=this.n?a.i:a.next;return b.m};function M(a,b,c,d,e){b=b.evaluate(d);c=c.evaluate(d);var f;if(b instanceof K&&c instanceof K){e=L(b);for(d=e.next();d;d=e.next())for(b=L(c),f=b.next();f;f=b.next())if(a(H(d),H(f)))return!0;return!1}if(b instanceof K||c instanceof K){b instanceof K?e=b:(e=c,c=b);e=L(e);b=typeof c;for(d=e.next();d;d=e.next()){switch(b){case "number":d=+H(d);break;case "boolean":d=!!H(d);break;case "string":d=H(d);break;default:throw Error("Illegal primitive type for comparison.");}if(a(d,c))return!0}return!1}return e?
-"boolean"==typeof b||"boolean"==typeof c?a(!!b,!!c):"number"==typeof b||"number"==typeof c?a(+b,+c):a(b,c):a(+b,+c)}function Aa(a,b,c,d){this.s=a;this.H=b;this.o=c;this.q=d}Aa.prototype.toString=function(){return this.s};var Ba={};function N(a,b,c,d){if(a in Ba)throw Error("Binary operator already created: "+a);a=new Aa(a,b,c,d);Ba[a.toString()]=a}N("div",6,1,function (a,b,c){return a.b(c)/b.b(c)});N("mod",6,1,function (a,b,c){return a.b(c)%b.b(c)});N("*",6,1,function (a,b,c){return a.b(c)*b.b(c)});
-N("+",5,1,function (a,b,c){return a.b(c)+b.b(c)});N("-",5,1,function (a,b,c){return a.b(c)-b.b(c)});N("<",4,2,function (a,b,c){return M(function (a,b){return a<b},a,b,c)});N(">",4,2,function (a,b,c){return M(function (a,b){return a>b},a,b,c)});N("<=",4,2,function (a,b,c){return M(function (a,b){return a<=b},a,b,c)});N(">=",4,2,function (a,b,c){return M(function (a,b){return a>=b},a,b,c)});N("=",3,2,function (a,b,c){return M(function (a,b){return a==b},a,b,c,!0)});
-N("!=",3,2,function (a,b,c){return M(function (a,b){return a!=b},a,b,c,!0)});N("and",2,2,function (a,b,c){return a.f(c)&&b.f(c)});N("or",1,2,function (a,b,c){return a.f(c)||b.f(c)});function Ca(a,b,c,d,e,f,g,w,p){this.h=a;this.o=b;this.D=c;this.C=d;this.B=e;this.q=f;this.A=g;this.w=void 0!==w?w:g;this.G=!!p}Ca.prototype.toString=function(){return this.h};var Da={};function O(a,b,c,d,e,f,g,w){if(a in Da)throw Error("Function already created: "+a+".");Da[a]=new Ca(a,b,c,d,!1,e,f,g,w)}O("boolean",2,!1,!1,function (a,b){return b.f(a)},1);O("ceiling",1,!1,!1,function (a,b){return Math.ceil(b.b(a))},1);
-O("concat",3,!1,!1,function (a,b){var c=ea(arguments,1);return ba(c,function (b,c){return b+c.a(a)})},2,null);O("contains",2,!1,!1,function (a,b,c){b=b.a(a);a=c.a(a);return-1!=b.indexOf(a)},2);O("count",1,!1,!1,function (a,b){return b.evaluate(a).g},1,1,!0);O("false",2,!1,!1,h(!1),0);O("floor",1,!1,!1,function (a,b){return Math.floor(b.b(a))},1);
-O("id",4,!1,!1,function (a,b){var c=a.e(),d=9==c.nodeType?c:c.ownerDocument,c=b.a(a).split(/\s+/),e=[];t(c,function (a){(a=d.getElementById(a))&&!da(e,a)&&e.push(a)});e.sort(qa);var f=new K;t(e,function (a){f.add(a)});return f},1);O("lang",2,!1,!1,h(!1),1);O("last",1,!0,!1,function (a){if(1!=arguments.length)throw Error("Function last expects ()");return a.u()},0);O("local-name",3,!1,!0,function (a,b){var c=b?ya(b.evaluate(a)):a.e();return c?c.nodeName.toLowerCase():""},0,1,!0);
-O("name",3,!1,!0,function (a,b){var c=b?ya(b.evaluate(a)):a.e();return c?c.nodeName.toLowerCase():""},0,1,!0);O("namespace-uri",3,!0,!1,h(""),0,1,!0);O("normalize-space",3,!1,!0,function (a,b){return(b?b.a(a):H(a.e())).replace(/[\s\xa0]+/g," ").replace(/^\s+|\s+$/g,"")},0,1);O("not",2,!1,!1,function (a,b){return!b.f(a)},1);O("number",1,!1,!0,function (a,b){return b?b.b(a):+H(a.e())},0,1);O("position",1,!0,!1,function (a){return a.v()},0);O("round",1,!1,!1,function (a,b){return Math.round(b.b(a))},1);
-O("starts-with",2,!1,!1,function (a,b,c){b=b.a(a);a=c.a(a);return 0==b.lastIndexOf(a,0)},2);O("string",3,!1,!0,function (a,b){return b?b.a(a):H(a.e())},0,1);O("string-length",1,!1,!0,function (a,b){return(b?b.a(a):H(a.e())).length},0,1);
-O("substring",3,!1,!1,function (a,b,c,d){c=c.b(a);if(isNaN(c)||Infinity==c||-Infinity==c)return"";d=d?d.b(a):Infinity;if(isNaN(d)||-Infinity===d)return"";c=Math.round(c)-1;var e=Math.max(c,0);a=b.a(a);if(Infinity==d)return a.substring(e);b=Math.round(d);return a.substring(e,c+b)},2,3);O("substring-after",3,!1,!1,function (a,b,c){b=b.a(a);a=c.a(a);c=b.indexOf(a);return-1==c?"":b.substring(c+a.length)},2);
-O("substring-before",3,!1,!1,function (a,b,c){b=b.a(a);a=c.a(a);a=b.indexOf(a);return-1==a?"":b.substring(0,a)},2);O("sum",1,!1,!1,function (a,b){for(var c=L(b.evaluate(a)),d=0,e=c.next();e;e=c.next())d+=+H(e);return d},1,1,!0);O("translate",3,!1,!1,function (a,b,c,d){b=b.a(a);c=c.a(a);var e=d.a(a);a=[];for(d=0;d<c.length;d++){var f=c.charAt(d);f in a||(a[f]=e.charAt(d))}c="";for(d=0;d<b.length;d++)f=b.charAt(d),c+=f in a?a[f]:f;return c},3);O("true",2,!1,!1,h(!0),0);function Ea(a,b,c,d){this.h=a;this.t=b;this.n=c;this.J=d}Ea.prototype.toString=function(){return this.h};var Fa={};function P(a,b,c,d){if(a in Fa)throw Error("Axis already created: "+a);Fa[a]=new Ea(a,b,c,!!d)}P("ancestor",function (a,b){for(var c=new K,d=b;d=d.parentNode;)a.matches(d)&&c.unshift(d);return c},!0);P("ancestor-or-self",function (a,b){var c=new K,d=b;do a.matches(d)&&c.unshift(d);while(d=d.parentNode);return c},!0);
-P("attribute",function (a,b){var c=new K,d=a.getName(),e=b.attributes;if(e)if("*"==d)for(var d=0,f;f=e[d];d++)c.add(f);else(f=e.getNamedItem(d))&&c.add(f);return c},!1);P("child",function (a,b,c,d,e){return wa.call(null,a,b,n(c)?c:null,n(d)?d:null,e||new K)},!1,!0);P("descendant",J,!1,!0);P("descendant-or-self",function (a,b,c,d){var e=new K;I(b,c,d)&&a.matches(b)&&e.add(b);return J(a,b,c,d,e)},!1,!0);
-P("following",function (a,b,c,d){var e=new K;do for(var f=b;f=f.nextSibling;)I(f,c,d)&&a.matches(f)&&e.add(f),e=J(a,f,c,d,e);while(b=b.parentNode);return e},!1,!0);P("following-sibling",function (a,b){for(var c=new K,d=b;d=d.nextSibling;)a.matches(d)&&c.add(d);return c},!1);P("namespace",function(){return new K},!1);P("parent",function (a,b){var c=new K;if(9==b.nodeType)return c;if(2==b.nodeType)return c.add(b.ownerElement),c;var d=b.parentNode;a.matches(d)&&c.add(d);return c},!1);
-P("preceding",function (a,b,c,d){var e=new K,f=[];do f.unshift(b);while(b=b.parentNode);for(var g=1,w=f.length;g<w;g++){var p=[];for(b=f[g];b=b.previousSibling;)p.unshift(b);for(var l=0,v=p.length;l<v;l++)b=p[l],I(b,c,d)&&a.matches(b)&&e.add(b),e=J(a,b,c,d,e)}return e},!0,!0);P("preceding-sibling",function (a,b){for(var c=new K,d=b;d=d.previousSibling;)a.matches(d)&&c.unshift(d);return c},!0);P("self",function (a,b){var c=new K;a.matches(b)&&c.add(b);return c},!1);var Ga=function(){var a={K:"http://www.w3.org/2000/svg"};return function (b){return a[b]||null}}();
-function Ha(a,b){var c=function(){var c;a:{var e=F(b);try{var f=e.createNSResolver?e.createNSResolver(e.documentElement):Ga;c=e.evaluate(a,b,f,9,null);break a}catch(g){if("NS_ERROR_ILLEGAL_VALUE"!=g.name)throw new y(32,"Unable to locate an element with the xpath expression "+a+" because of the following error:\n"+g);}c=void 0}return c?c.singleNodeValue||null:b.selectSingleNode?(c=F(b),c.setProperty&&c.setProperty("SelectionLanguage","XPath"),b.selectSingleNode(a)):null}();if(null!==c&&(!c||1!=c.nodeType))throw new y(32,
-'The result of the xpath expression "'+a+'" is: '+c+". It should be an element.");return c};(function(){var a=k.Components;if(!a)return!1;try{if(!a.classes)return!1}catch(b){return!1}var c=a.classes,a=a.interfaces;c["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator);c["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo);return!0})();function Q(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d}Q.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"};Q.prototype.contains=function (a){return a instanceof Q?this.left<=a.left&&this.left+this.width>=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.top+a.height:a.x>=this.left&&a.x<=this.left+this.width&&a.y>=this.top&&a.y<=this.top+this.height};
-Q.prototype.ceil=function(){this.left=Math.ceil(this.left);this.top=Math.ceil(this.top);this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};Q.prototype.floor=function(){this.left=Math.floor(this.left);this.top=Math.floor(this.top);this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};
-Q.prototype.round=function(){this.left=Math.round(this.left);this.top=Math.round(this.top);this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function Ia(a,b){var c=F(a);return c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(a,null))?c[b]||c.getPropertyValue(b)||"":""}function R(a,b){return Ia(a,b)||(a.currentStyle?a.currentStyle[b]:null)||a.style&&a.style[b]}function Ja(a){var b;try{b=a.getBoundingClientRect()}catch(c){return{left:0,top:0,right:0,bottom:0}}return b}
-function Ka(a){var b=F(a),c=R(a,"position"),d="fixed"==c||"absolute"==c;for(a=a.parentNode;a&&a!=b;a=a.parentNode)if(c=R(a,"position"),d=d&&"static"==c&&a!=b.documentElement&&a!=b.body,!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c||"absolute"==c||"relative"==c))return a;return null}
-function La(a){if(1==a.nodeType){var b;if(a.getBoundingClientRect)b=Ja(a),b=new C(b.left,b.top);else{b=ua(a?new G(F(a)):B||(B=new G));var c,d=F(a),e=R(a,"position"),f=d.getBoxObjectFor&&!a.getBoundingClientRect&&"absolute"==e&&(c=d.getBoxObjectFor(a))&&(0>c.screenX||0>c.screenY),e=new C(0,0),g=(d?F(d):document).documentElement;if(a!=g)if(a.getBoundingClientRect)c=Ja(a),d=ua(d?new G(F(d)):B||(B=new G)),e.x=c.left+d.x,e.y=c.top+d.y;else if(d.getBoxObjectFor&&!f)c=d.getBoxObjectFor(a),d=d.getBoxObjectFor(g),
-e.x=c.screenX-d.screenX,e.y=c.screenY-d.screenY;else{c=a;do e.x+=c.offsetLeft,e.y+=c.offsetTop,c!=a&&(e.x+=c.clientLeft||0,e.y+=c.clientTop||0),c=c.offsetParent;while(c&&c!=a);for(c=a;(c=Ka(c))&&c!=d.body&&c!=g;)e.x-=c.scrollLeft,e.y-=c.scrollTop}b=new C(e.x-b.x,e.y-b.y)}A[12]||(A[12]=0<=q(12))?a=b:((c=R(a,"-moz-transform"))||(c=R(a,"transform")),a=c?(a=c.match(Ma))?new C(parseFloat(a[1]),parseFloat(a[2])):new C(0,0):new C(0,0),a=new C(b.x+a.x,b.y+a.y));return a}b="function"==m(a.k);c=a;a.targetTouches?
-c=a.targetTouches[0]:b&&a.k().targetTouches&&(c=a.k().targetTouches[0]);return new C(c.clientX,c.clientY)}var Ma=/matrix\([0-9\.\-]+, [0-9\.\-]+, [0-9\.\-]+, [0-9\.\-]+, ([0-9\.\-]+)p?x?, ([0-9\.\-]+)p?x?\)/;function S(a,b){return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}function T(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return S(a)?a:null}
-function U(a,b){var c=aa(b);if("float"==c||"cssFloat"==c||"styleFloat"==c)c="cssFloat";c=Ia(a,c)||Na(a,c);if(null===c)c=null;else if(da(fa,b)&&(x.test("#"==c.charAt(0)?c:"#"+c)||la(c).length||u&&u[c.toLowerCase()]||ja(c).length)){var d=ja(c);if(!d.length){a:if(d=la(c),!d.length){d=(d=u[c.toLowerCase()])?d:"#"==c.charAt(0)?c:"#"+c;if(x.test(d)&&(d=ha(d),d=ha(d),d=[parseInt(d.substr(1,2),16),parseInt(d.substr(3,2),16),parseInt(d.substr(5,2),16)],d.length))break a;d=[]}3==d.length&&d.push(1)}c=4!=d.length?
-c:"rgba("+d.join(", ")+")"}return c}function Na(a,b){var c=a.currentStyle||a.style,d=c[b];void 0===d&&"function"==m(c.getPropertyValue)&&(d=c.getPropertyValue(b));return"inherit"!=d?void 0!==d?d:null:(c=T(a))?Na(c,b):null}
-function V(a,b){function c(a){if("none"==U(a,"display"))return!1;a=T(a);return!a||c(a)}function d(a){if(a.hasAttribute){if(a.hasAttribute("hidden"))return!1}else return!0;a=T(a);return!a||d(a)}function e(a){var b=W(a);return 0<b.height&&0<b.width?!0:S(a,"PATH")&&(0<b.height||0<b.width)?(a=U(a,"stroke-width"),!!a&&0<parseInt(a,10)):"hidden"!=U(a,"overflow")&&ca(a.childNodes,function (a){return a.nodeType==pa||S(a)&&e(a)})}function f(a){var b=U(a,"-o-transform")||U(a,"-webkit-transform")||U(a,"-ms-transform")||
-U(a,"-moz-transform")||U(a,"transform");if(b&&"none"!==b)return b=La(a),a=W(a),0<=b.x+a.width&&0<=b.y+a.height?!0:!1;a=T(a);return!a||f(a)}if(!S(a))throw Error("Argument to isShown must be of type Element");if(S(a,"OPTION")||S(a,"OPTGROUP")){var g=ta(a,function (a){return S(a,"SELECT")});return!!g&&V(g,!0)}return(g=Oa(a))?!!g.l&&0<g.rect.width&&0<g.rect.height&&V(g.l,b):S(a,"INPUT")&&"hidden"==a.type.toLowerCase()||S(a,"NOSCRIPT")||"hidden"==U(a,"visibility")||!c(a)||!b&&0==Pa(a)||!d(a)||!e(a)||Qa(a)==
-X?!1:f(a)}var X="hidden";
-function Qa(a){function b(a){var b=a;if("visible"==w)if(a==f)b=g;else if(a==g)return{x:"visible",y:"visible"};b={x:U(b,"overflow-x"),y:U(b,"overflow-y")};a==f&&(b.x="hidden"==b.x?"hidden":"auto",b.y="hidden"==b.y?"hidden":"auto");return b}function c(a){var b=U(a,"position");if("fixed"==b)return f;for(a=T(a);a&&a!=f&&(0==U(a,"display").lastIndexOf("inline",0)||"absolute"==b&&"static"==U(a,"position"));)a=T(a);return a}var d=W(a),e=F(a),f=e.documentElement,g=e.body||f,w=U(f,"overflow");for(a=c(a);a;a=
-c(a)){var p=W(a),e=b(a),l=d.left>=p.left+p.width,p=d.top>=p.top+p.height;if(l&&"hidden"==e.x||p&&"hidden"==e.y)return X;if(l&&"visible"!=e.x||p&&"visible"!=e.y)return Qa(a)==X?X:"scroll"}return"none"}
-function W(a){var b=Oa(a);if(b)return b.rect;if("function"==m(a.getBBox))try{var c=a.getBBox();return new Q(c.x,c.y,c.width,c.height)}catch(d){if("NS_ERROR_FAILURE"===d.name||-1!=d.message.indexOf("Component returned failure code: 0x80004005"))return new Q(0,0,0,0);throw d;}else{if(S(a,"HTML"))return a=((F(a)?F(a).parentWindow||F(a).defaultView:window)||window).document,a="CSS1Compat"==a.compatMode?a.documentElement:a.body,a=new D(a.clientWidth,a.clientHeight),new Q(0,0,a.width,a.height);b=La(a);
-return new Q(b.x,b.y,a.offsetWidth,a.offsetHeight)}}
-function Oa(a){var b=S(a,"MAP");if(!b&&!S(a,"AREA"))return null;var c=b?a:S(a.parentNode,"MAP")?a.parentNode:null,d=null,e=null;if(c&&c.name&&(d=Ha('/descendant::*[@usemap = "#'+c.name+'"]',F(c)))&&(e=W(d),!b&&"default"!=a.shape.toLowerCase())){var f=Ra(a);a=Math.min(Math.max(f.left,0),e.width);b=Math.min(Math.max(f.top,0),e.height);c=Math.min(f.width,e.width-a);f=Math.min(f.height,e.height-b);e=new Q(a+e.left,b+e.top,c,f)}return{l:d,rect:e||new Q(0,0,0,0)}}
-function Ra(a){var b=a.shape.toLowerCase();a=a.coords.split(",");if("rect"==b&&4==a.length){var b=a[0],c=a[1];return new Q(b,c,a[2]-b,a[3]-c)}if("circle"==b&&3==a.length)return b=a[2],new Q(a[0]-b,a[1]-b,2*b,2*b);if("poly"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new Q(b,c,d-b,e-c)}return new Q(0,0,0,0)}
-function Pa(a){var b=1,c=U(a,"opacity");c&&(b=Number(c));(a=T(a))&&(b*=Pa(a));return b};var Sa=V,Y=["_"],Z=k;Y[0]in Z||!Z.execScript||Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)Y.length||void 0===Sa?Z=Z[$]?Z[$]:Z[$]={}:Z[$]=Sa;; return this._.apply(null,arguments);}.apply({navigator:typeof window!=undefined?window.navigator:null,document:typeof window!=undefined?window.document:null}, arguments);}
diff --git a/testing/marionette/browser.js b/testing/marionette/browser.js
deleted file mode 100644
index c6f9a2338f..0000000000
--- a/testing/marionette/browser.js
+++ /dev/null
@@ -1,436 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/frame.js");
-
-this.EXPORTED_SYMBOLS = ["browser"];
-
-this.browser = {};
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-
-/**
- * Get the <xul:browser> for the specified tab.
- *
- * @param {<xul:tab>} tab
- * The tab whose browser needs to be returned.
- *
- * @return {<xul:browser>}
- * The linked browser for the tab or null if no browser can be found.
- */
-browser.getBrowserForTab = function (tab) {
- if ("browser" in tab) {
- // Fennec
- return tab.browser;
-
- } else if ("linkedBrowser" in tab) {
- // Firefox
- return tab.linkedBrowser;
-
- } else {
- return null;
- }
-};
-
-/**
- * Return the tab browser for the specified chrome window.
- *
- * @param {nsIDOMWindow} win
- * The window whose tabbrowser needs to be accessed.
- *
- * @return {<xul:tabbrowser>}
- * Tab browser or null if it's not a browser window.
- */
-browser.getTabBrowser = function (win) {
- if ("BrowserApp" in win) {
- // Fennec
- return win.BrowserApp;
-
- } else if ("gBrowser" in win) {
- // Firefox
- return win.gBrowser;
-
- } else {
- return null;
- }
-};
-
-/**
- * Creates a browsing context wrapper.
- *
- * Browsing contexts handle interactions with the browser, according to
- * the current environment (desktop, B2G, Fennec, &c).
- *
- * @param {nsIDOMWindow} win
- * The window whose browser needs to be accessed.
- * @param {GeckoDriver} driver
- * Reference to the driver the browser is attached to.
- */
-browser.Context = class {
-
- /**
- * @param {<xul:browser>} win
- * Frame that is expected to contain the view of the web document.
- * @param {GeckoDriver} driver
- * Reference to driver instance.
- */
- constructor(win, driver) {
- this.window = win;
- this.driver = driver;
-
- // In Firefox this is <xul:tabbrowser> (not <xul:browser>!)
- // and BrowserApp in Fennec
- this.tabBrowser = browser.getTabBrowser(win);
-
- this.knownFrames = [];
-
- // Used in B2G to identify the homescreen content page
- this.mainContentId = null;
-
- // Used to set curFrameId upon new session
- this.newSession = true;
-
- this.seenEls = new element.Store();
-
- // A reference to the tab corresponding to the current window handle, if any.
- // Specifically, this.tab refers to the last tab that Marionette switched
- // to in this browser window. Note that this may not equal the currently
- // selected tab. For example, if Marionette switches to tab A, and then
- // clicks on a button that opens a new tab B in the same browser window,
- // this.tab will still point to tab A, despite tab B being the currently
- // selected tab.
- this.tab = null;
- this.pendingCommands = [];
-
- // We should have one frame.Manager per browser.Context so that we
- // can handle modals in each <xul:browser>.
- this.frameManager = new frame.Manager(driver);
- this.frameRegsPending = 0;
-
- // register all message listeners
- this.frameManager.addMessageManagerListeners(driver.mm);
- this.getIdForBrowser = driver.getIdForBrowser.bind(driver);
- this.updateIdForBrowser = driver.updateIdForBrowser.bind(driver);
- this._curFrameId = null;
- this._browserWasRemote = null;
- this._hasRemotenessChange = false;
- }
-
- /**
- * The current frame ID is managed per browser element on desktop in
- * case the ID needs to be refreshed. The currently selected window is
- * identified by a tab.
- */
- get curFrameId() {
- let rv = null;
- if (this.driver.appName == "B2G") {
- rv = this._curFrameId;
- } else if (this.tab) {
- rv = this.getIdForBrowser(browser.getBrowserForTab(this.tab));
- }
- return rv;
- }
-
- set curFrameId(id) {
- if (this.driver.appName != "Firefox") {
- this._curFrameId = id;
- }
- }
-
- /**
- * Retrieves the current tabmodal UI object. According to the browser
- * associated with the currently selected tab.
- */
- getTabModalUI() {
- let br = browser.getBrowserForTab(this.tab);
- if (!br.hasAttribute("tabmodalPromptShowing")) {
- return null;
- }
-
- // The modal is a direct sibling of the browser element.
- // See tabbrowser.xml's getTabModalPromptBox.
- let modals = br.parentNode.getElementsByTagNameNS(
- XUL_NS, "tabmodalprompt");
- return modals[0].ui;
- }
-
- /**
- * Close the current window.
- *
- * @return {Promise}
- * A promise which is resolved when the current window has been closed.
- */
- closeWindow() {
- return new Promise(resolve => {
- this.window.addEventListener("unload", ev => {
- resolve();
- }, {once: true});
- this.window.close();
- });
- }
-
- /** Called when we start a session with this browser. */
- startSession(newSession, win, callback) {
- callback(win, newSession);
- }
-
- /**
- * Close the current tab.
- *
- * @return {Promise}
- * A promise which is resolved when the current tab has been closed.
- *
- * @throws UnsupportedOperationError
- * If tab handling for the current application isn't supported.
- */
- closeTab() {
- // If the current window is not a browser then close it directly. Do the
- // same if only one remaining tab is open, or no tab selected at all.
- if (!this.tabBrowser || this.tabBrowser.tabs.length === 1 || !this.tab) {
- return this.closeWindow();
- }
-
- return new Promise((resolve, reject) => {
- if (this.tabBrowser.closeTab) {
- // Fennec
- this.tabBrowser.deck.addEventListener("TabClose", ev => {
- resolve();
- }, {once: true});
- this.tabBrowser.closeTab(this.tab);
-
- } else if (this.tabBrowser.removeTab) {
- // Firefox
- this.tab.addEventListener("TabClose", ev => {
- resolve();
- }, {once: true});
- this.tabBrowser.removeTab(this.tab);
-
- } else {
- reject(new UnsupportedOperationError(
- `closeTab() not supported in ${this.driver.appName}`));
- }
- });
- }
-
- /**
- * Opens a tab with given URI.
- *
- * @param {string} uri
- * URI to open.
- */
- addTab(uri) {
- return this.tabBrowser.addTab(uri, true);
- }
-
- /**
- * Set the current tab and update remoteness tracking if a tabbrowser is available.
- *
- * @param {number=} index
- * Tab index to switch to. If the parameter is undefined,
- * the currently selected tab will be used.
- * @param {nsIDOMWindow=} win
- * Switch to this window before selecting the tab.
- * @param {boolean=} focus
- * A boolean value which determins whether to focus
- * the window. Defaults to true.
- *
- * @throws UnsupportedOperationError
- * If tab handling for the current application isn't supported.
- */
- switchToTab(index, win, focus = true) {
- if (win) {
- this.window = win;
- this.tabBrowser = browser.getTabBrowser(win);
- }
-
- if (!this.tabBrowser) {
- return;
- }
-
- if (typeof index == "undefined") {
- this.tab = this.tabBrowser.selectedTab;
- } else {
- this.tab = this.tabBrowser.tabs[index];
-
- if (focus) {
- if (this.tabBrowser.selectTab) {
- // Fennec
- this.tabBrowser.selectTab(this.tab);
-
- } else if ("selectedTab" in this.tabBrowser) {
- // Firefox
- this.tabBrowser.selectedTab = this.tab;
-
- } else {
- throw new UnsupportedOperationError("switchToTab() not supported");
- }
- }
- }
-
- if (this.driver.appName == "Firefox") {
- this._browserWasRemote = browser.getBrowserForTab(this.tab).isRemoteBrowser;
- this._hasRemotenessChange = false;
- }
- }
-
- /**
- * Registers a new frame, and sets its current frame id to this frame
- * if it is not already assigned, and if a) we already have a session
- * or b) we're starting a new session and it is the right start frame.
- *
- * @param {string} uid
- * Frame uid for use by Marionette.
- * @param the XUL <browser> that was the target of the originating message.
- */
- register(uid, target) {
- let remotenessChange = this.hasRemotenessChange();
- if (this.curFrameId === null || remotenessChange) {
- if (this.tabBrowser) {
- // If we're setting up a new session on Firefox, we only process the
- // registration for this frame if it belongs to the current tab.
- if (!this.tab) {
- this.switchToTab();
- }
-
- if (target == browser.getBrowserForTab(this.tab)) {
- this.updateIdForBrowser(browser.getBrowserForTab(this.tab), uid);
- this.mainContentId = uid;
- }
- } else {
- this._curFrameId = uid;
- this.mainContentId = uid;
- }
- }
-
- // used to delete sessions
- this.knownFrames.push(uid);
- return remotenessChange;
- }
-
- /**
- * When navigating between pages results in changing a browser's
- * process, we need to take measures not to lose contact with a listener
- * script. This function does the necessary bookkeeping.
- */
- hasRemotenessChange() {
- // None of these checks are relevant on b2g or if we don't have a tab yet,
- // and may not apply on Fennec.
- if (this.driver.appName != "Firefox" ||
- this.tab === null ||
- browser.getBrowserForTab(this.tab) === null) {
- return false;
- }
-
- if (this._hasRemotenessChange) {
- return true;
- }
-
- let currentIsRemote = browser.getBrowserForTab(this.tab).isRemoteBrowser;
- this._hasRemotenessChange = this._browserWasRemote !== currentIsRemote;
- this._browserWasRemote = currentIsRemote;
- return this._hasRemotenessChange;
- }
-
- /**
- * Flushes any pending commands queued when a remoteness change is being
- * processed and mark this remotenessUpdate as complete.
- */
- flushPendingCommands() {
- if (!this._hasRemotenessChange) {
- return;
- }
-
- this._hasRemotenessChange = false;
- this.pendingCommands.forEach(cb => cb());
- this.pendingCommands = [];
- }
-
- /**
- * This function intercepts commands interacting with content and queues
- * or executes them as needed.
- *
- * No commands interacting with content are safe to process until
- * the new listener script is loaded and registers itself.
- * This occurs when a command whose effect is asynchronous (such
- * as goBack) results in a remoteness change and new commands
- * are subsequently posted to the server.
- */
- executeWhenReady(cb) {
- if (this.hasRemotenessChange()) {
- this.pendingCommands.push(cb);
- } else {
- cb();
- }
- }
-
- /**
- * Returns the position of the OS window.
- */
- get position() {
- return {
- x: this.window.screenX,
- y: this.window.screenY,
- };
- }
-
-};
-
-/**
- * The window storage is used to save outer window IDs mapped to weak
- * references of Window objects.
- *
- * Usage:
- *
- * let wins = new browser.Windows();
- * wins.set(browser.outerWindowID, window);
- *
- * ...
- *
- * let win = wins.get(browser.outerWindowID);
- *
- */
-browser.Windows = class extends Map {
-
- /**
- * Save a weak reference to the Window object.
- *
- * @param {string} id
- * Outer window ID.
- * @param {Window} win
- * Window object to save.
- *
- * @return {browser.Windows}
- * Instance of self.
- */
- set(id, win) {
- let wref = Cu.getWeakReference(win);
- super.set(id, wref);
- return this;
- }
-
- /**
- * Get the window object stored by provided |id|.
- *
- * @param {string} id
- * Outer window ID.
- *
- * @return {Window}
- * Saved window object, or |undefined| if no window is stored by
- * provided |id|.
- */
- get(id) {
- let wref = super.get(id);
- if (wref) {
- return wref.get();
- }
- }
-
-};
diff --git a/testing/marionette/capture.js b/testing/marionette/capture.js
deleted file mode 100644
index 274d205675..0000000000
--- a/testing/marionette/capture.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-Cu.importGlobalProperties(["crypto"]);
-
-this.EXPORTED_SYMBOLS = ["capture"];
-
-const CONTEXT_2D = "2d";
-const BG_COLOUR = "rgb(255,255,255)";
-const PNG_MIME = "image/png";
-const XHTML_NS = "http://www.w3.org/1999/xhtml";
-
-/** Provides primitives to capture screenshots. */
-this.capture = {};
-
-capture.Format = {
- Base64: 0,
- Hash: 1,
-};
-
-/**
- * Take a screenshot of a single element.
- *
- * @param {Node} node
- * The node to take a screenshot of.
- * @param {Array.<Node>=} highlights
- * Optional array of nodes, around which a border will be marked to
- * highlight them in the screenshot.
- *
- * @return {HTMLCanvasElement}
- * The canvas element where the element has been painted on.
- */
-capture.element = function (node, highlights = []) {
- let win = node.ownerDocument.defaultView;
- let rect = node.getBoundingClientRect();
-
- return capture.canvas(
- win,
- rect.left,
- rect.top,
- rect.width,
- rect.height,
- highlights);
-};
-
-/**
- * Take a screenshot of the window's viewport by taking into account
- * the current offsets.
- *
- * @param {DOMWindow} win
- * The DOM window providing the document element to capture,
- * and the offsets for the viewport.
- * @param {Array.<Node>=} highlights
- * Optional array of nodes, around which a border will be marked to
- * highlight them in the screenshot.
- *
- * @return {HTMLCanvasElement}
- * The canvas element where the viewport has been painted on.
- */
-capture.viewport = function (win, highlights = []) {
- let rootNode = win.document.documentElement;
-
- return capture.canvas(
- win,
- win.pageXOffset,
- win.pageYOffset,
- rootNode.clientWidth,
- rootNode.clientHeight,
- highlights);
-};
-
-/**
- * Low-level interface to draw a rectangle off the framebuffer.
- *
- * @param {DOMWindow} win
- * The DOM window used for the framebuffer, and providing the interfaces
- * for creating an HTMLCanvasElement.
- * @param {number} left
- * The left, X axis offset of the rectangle.
- * @param {number} top
- * The top, Y axis offset of the rectangle.
- * @param {number} width
- * The width dimension of the rectangle to paint.
- * @param {number} height
- * The height dimension of the rectangle to paint.
- * @param {Array.<Node>=} highlights
- * Optional array of nodes, around which a border will be marked to
- * highlight them in the screenshot.
- *
- * @return {HTMLCanvasElement}
- * The canvas on which the selection from the window's framebuffer
- * has been painted on.
- */
-capture.canvas = function (win, left, top, width, height, highlights = []) {
- let scale = win.devicePixelRatio;
-
- let canvas = win.document.createElementNS(XHTML_NS, "canvas");
- canvas.width = width * scale;
- canvas.height = height * scale;
-
- let ctx = canvas.getContext(CONTEXT_2D);
- let flags = ctx.DRAWWINDOW_DRAW_CARET;
- // Disabled in bug 1243415 for webplatform-test failures due to out of view elements.
- // Needs https://github.com/w3c/web-platform-tests/issues/4383 fixed.
- // ctx.DRAWWINDOW_DRAW_VIEW;
- // Bug 1009762 - Crash in [@ mozilla::gl::ReadPixelsIntoDataSurface]
- // ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
-
- ctx.scale(scale, scale);
- ctx.drawWindow(win, left, top, width, height, BG_COLOUR, flags);
- ctx = capture.highlight_(ctx, highlights, top, left);
-
- return canvas;
-};
-
-capture.highlight_ = function (context, highlights, top = 0, left = 0) {
- if (!highlights) {
- return;
- }
-
- context.lineWidth = "2";
- context.strokeStyle = "red";
- context.save();
-
- for (let el of highlights) {
- let rect = el.getBoundingClientRect();
- let oy = -top;
- let ox = -left;
-
- context.strokeRect(
- rect.left + ox,
- rect.top + oy,
- rect.width,
- rect.height);
- }
-
- return context;
-};
-
-/**
- * Encode the contents of an HTMLCanvasElement to a Base64 encoded string.
- *
- * @param {HTMLCanvasElement} canvas
- * The canvas to encode.
- *
- * @return {string}
- * A Base64 encoded string.
- */
-capture.toBase64 = function (canvas) {
- let u = canvas.toDataURL(PNG_MIME);
- return u.substring(u.indexOf(",") + 1);
-};
-
-/**
-* Hash the contents of an HTMLCanvasElement to a SHA-256 hex digest.
-*
-* @param {HTMLCanvasElement} canvas
-* The canvas to encode.
-*
-* @return {string}
-* A hex digest of the SHA-256 hash of the base64 encoded string.
-*/
-capture.toHash = function (canvas) {
- let u = capture.toBase64(canvas);
- let buffer = new TextEncoder("utf-8").encode(u);
- return crypto.subtle.digest("SHA-256", buffer).then(hash => hex(hash));
-};
-
-/**
-* Convert buffer into to hex.
-*
-* @param {ArrayBuffer} buffer
-* The buffer containing the data to convert to hex.
-*
-* @return {string}
-* A hex digest of the input buffer.
-*/
-function hex(buffer) {
- let hexCodes = [];
- let view = new DataView(buffer);
- for (let i = 0; i < view.byteLength; i += 4) {
- let value = view.getUint32(i);
- let stringValue = value.toString(16);
- let padding = '00000000';
- let paddedValue = (padding + stringValue).slice(-padding.length);
- hexCodes.push(paddedValue);
- }
- return hexCodes.join("");
-}; \ No newline at end of file
diff --git a/testing/marionette/cert.js b/testing/marionette/cert.js
deleted file mode 100644
index e54129c576..0000000000
--- a/testing/marionette/cert.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-this.EXPORTED_SYMBOLS = ["cert"];
-
-const registrar =
- Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-const sss = Cc["@mozilla.org/ssservice;1"]
- .getService(Ci.nsISiteSecurityService);
-
-const CONTRACT_ID = "@mozilla.org/security/certoverride;1";
-const CERT_PINNING_ENFORCEMENT_PREF =
- "security.cert_pinning.enforcement_level";
-const HSTS_PRELOAD_LIST_PREF =
- "network.stricttransportsecurity.preloadlist";
-
-/** TLS certificate service override management for Marionette. */
-this.cert = {
- Error: {
- Untrusted: 1,
- Mismatch: 2,
- Time: 4,
- },
-
- currentOverride: null,
-};
-
-/**
- * Installs a TLS certificate service override.
- *
- * The provided |service| must implement the |register| and |unregister|
- * functions that causes a new |nsICertOverrideService| interface
- * implementation to be registered with the |nsIComponentRegistrar|.
- *
- * After |service| is registered and made the |cert.currentOverride|,
- * |nsICertOverrideService| is reinitialised to cause all Gecko components
- * to pick up the new service.
- *
- * If an override is already installed, i.e. when |cert.currentOverride|
- * is not null, this functions acts as a NOOP.
- *
- * @param {cert.Override} service
- * Service generator that registers and unregisters the XPCOM service.
- *
- * @throws {Components.Exception}
- * If unable to register or initialise |service|.
- */
-cert.installOverride = function (service) {
- if (this.currentOverride) {
- return;
- }
-
- service.register();
- cert.currentOverride = service;
-};
-
-/**
- * Uninstall a TLS certificate service override.
- *
- * After the service has been unregistered, |cert.currentOverride|
- * is reset to null.
- *
- * If there no current override installed, i.e. if |cert.currentOverride|
- * is null, this function acts as a NOOP.
- */
-cert.uninstallOverride = function() {
- if (!cert.currentOverride) {
- return;
- }
- cert.currentOverride.unregister();
- this.currentOverride = null;
-};
-
-/**
- * Certificate override service that acts in an all-inclusive manner
- * on TLS certificates.
- *
- * When an invalid certificate is encountered, it is overriden
- * with the |matching| bit level, which is typically a combination of
- * |cert.Error.Untrusted|, |cert.Error.Mismatch|, and |cert.Error.Time|.
- *
- * @type cert.Override
- *
- * @throws {Components.Exception}
- * If there are any problems registering the service.
- */
-cert.InsecureSweepingOverride = function() {
- const CID = Components.ID("{4b67cce0-a51c-11e6-9598-0800200c9a66}");
- const DESC = "All-encompassing cert service that matches on a bitflag";
-
- // This needs to be an old-style class with a function constructor
- // and prototype assignment because... XPCOM. Any attempt at
- // modernisation will be met with cryptic error messages which will
- // make your life miserable.
- let service = function() {};
- service.prototype = {
- hasMatchingOverride: function (
- aHostName, aPort, aCert, aOverrideBits, aIsTemporary) {
- aIsTemporary.value = false;
- aOverrideBits.value =
- cert.Error.Untrusted | cert.Error.Mismatch | cert.Error.Time;
-
- return true;
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICertOverrideService]),
- };
- let factory = XPCOMUtils.generateSingletonFactory(service);
-
- return {
- register: function() {
- // make it possible to register certificate overrides for domains
- // that use HSTS or HPKP
- Preferences.set(HSTS_PRELOAD_LIST_PREF, false);
- Preferences.set(CERT_PINNING_ENFORCEMENT_PREF, 0);
-
- registrar.registerFactory(CID, DESC, CONTRACT_ID, factory);
- },
-
- unregister: function() {
- registrar.unregisterFactory(CID, factory);
-
- Preferences.reset(HSTS_PRELOAD_LIST_PREF);
- Preferences.reset(CERT_PINNING_ENFORCEMENT_PREF);
-
- // clear collected HSTS and HPKP state
- // through the site security service
- sss.clearAll();
- },
- };
-};
diff --git a/testing/marionette/chrome/test.xul b/testing/marionette/chrome/test.xul
deleted file mode 100644
index 2baa28e5ff..0000000000
--- a/testing/marionette/chrome/test.xul
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<!DOCTYPE window [
-]>
-<window id="winTest" title="Title Test" windowtype="Test Type"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <dialog id="dia"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <vbox id="things">
- <checkbox id="testBox" label="box" />
- <textbox id="textInput" size="6" value="test" label="input" />
- <textbox id="textInput2" size="6" value="test" label="input" />
- <textbox id="textInput3" class="asdf" size="6" value="test" label="input" />
- </vbox>
-
- <iframe id="iframe" name="iframename" src="chrome://marionette/content/test2.xul"/>
- <iframe id="iframe" name="iframename" src="chrome://marionette/content/test_nested_iframe.xul"/>
- <hbox id="testXulBox"/>
- <browser id='aBrowser' src="chrome://marionette/content/test2.xul"/>
- </dialog>
-</window>
diff --git a/testing/marionette/chrome/test2.xul b/testing/marionette/chrome/test2.xul
deleted file mode 100644
index d450e03058..0000000000
--- a/testing/marionette/chrome/test2.xul
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<!DOCTYPE window [
-]>
-
-<dialog id="dia"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <vbox id="things">
- <checkbox id="testBox" label="box" />
- <textbox id="textInput" size="6" value="test" label="input" />
- <textbox id="textInput2" size="6" value="test" label="input" />
- <textbox id="textInput3" class="asdf" size="6" value="test" label="input" />
- </vbox>
-
-</dialog>
diff --git a/testing/marionette/chrome/test_anonymous_content.xul b/testing/marionette/chrome/test_anonymous_content.xul
deleted file mode 100644
index 49f9eff292..0000000000
--- a/testing/marionette/chrome/test_anonymous_content.xul
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<!DOCTYPE dialog [
-]>
-
-<dialog id="testDialogAnonymousNode"
- buttons="accept, cancel"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <bindings id="testBindings" xmlns="http://www.mozilla.org/xbl"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <binding id="framebox">
- <content orient="vertical" mousethrough="never">
- <xul:browser anonid="content" id="browser" flex="1"
- context="contentAreaContextMenu"
- src="test.xul"
- type="content"/>
- </content>
- </binding>
-
- <binding id="iframebox">
- <content>
- <xul:box>
- <xul:iframe anonid="iframe" src="chrome://marionette/content/test.xul"></xul:iframe>
- </xul:box>
- </content>
- </binding>
- </bindings>
-
- <hbox id="testAnonymousContentBox"/>
- <hbox id="container" style="-moz-binding: url('#testBindings');"/>
- <hbox id="container2" style="-moz-binding: url('#iframebox');"/>
-
-</dialog>
diff --git a/testing/marionette/chrome/test_dialog.dtd b/testing/marionette/chrome/test_dialog.dtd
deleted file mode 100644
index 414cb0ee81..0000000000
--- a/testing/marionette/chrome/test_dialog.dtd
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- 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/. -->
-
-<!ENTITY testDialog.title "Test Dialog">
-
-<!ENTITY settings.label "Settings">
diff --git a/testing/marionette/chrome/test_dialog.properties b/testing/marionette/chrome/test_dialog.properties
deleted file mode 100644
index ade7b6bde3..0000000000
--- a/testing/marionette/chrome/test_dialog.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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/.
-
-testDialog.title=Test Dialog
-
-settings.label=Settings
diff --git a/testing/marionette/chrome/test_dialog.xul b/testing/marionette/chrome/test_dialog.xul
deleted file mode 100644
index 0d4816b97e..0000000000
--- a/testing/marionette/chrome/test_dialog.xul
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<!DOCTYPE testdialog [
-<!ENTITY % dialogDTD SYSTEM "chrome://marionette/content/test_dialog.dtd" >
-%dialogDTD;
-]>
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-
-<dialog id="testDialog"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- title="&testDialog.title;"
- buttons="accept,cancel">
-
- <vbox flex="1" style="min-width: 300px; min-height: 500px;">
- <label>&settings.label;</label>
- <separator class="thin"/>
- <richlistbox id="test-list" flex="1">
- <richlistitem id="item-choose" orient="horizontal" selected="true">
- <label id="choose-label" value="First Entry" flex="1"/>
- <button id="choose-button" oncommand="" label="Choose..."/>
- </richlistitem>
- </richlistbox>
- <separator class="thin"/>
- <checkbox id="check-box" label="Test Mode 2" />
- <hbox align="center">
- <label id="text-box-label" control="text-box">Name:</label>
- <textbox id="text-box" flex="1" />
- </hbox>
- </vbox>
-
-</dialog>
diff --git a/testing/marionette/chrome/test_nested_iframe.xul b/testing/marionette/chrome/test_nested_iframe.xul
deleted file mode 100644
index 0bec83cbe6..0000000000
--- a/testing/marionette/chrome/test_nested_iframe.xul
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<!DOCTYPE window [
-]>
-
- <iframe id="iframe" name="iframename" src="test2.xul"/>
diff --git a/testing/marionette/client/.flake8 b/testing/marionette/client/.flake8
deleted file mode 100644
index 5f607bc639..0000000000
--- a/testing/marionette/client/.flake8
+++ /dev/null
@@ -1,3 +0,0 @@
-[flake8]
-max-line-length = 99
-exclude = __init__.py,disti/*,build/*,
diff --git a/testing/marionette/client/MANIFEST.in b/testing/marionette/client/MANIFEST.in
deleted file mode 100644
index cf628b039c..0000000000
--- a/testing/marionette/client/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-exclude MANIFEST.in
-include requirements.txt
diff --git a/testing/marionette/client/docs/Makefile b/testing/marionette/client/docs/Makefile
deleted file mode 100644
index f3d89d6d47..0000000000
--- a/testing/marionette/client/docs/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/MarionettePythonClient.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/MarionettePythonClient.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/MarionettePythonClient"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/MarionettePythonClient"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/testing/marionette/client/docs/advanced/actions.rst b/testing/marionette/client/docs/advanced/actions.rst
deleted file mode 100644
index 294855a6f7..0000000000
--- a/testing/marionette/client/docs/advanced/actions.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-Actions
-=======
-
-.. py:currentmodule:: marionette
-
-Action Sequences
-----------------
-
-:class:`Actions` are designed as a way to simulate user input as closely as possible
-on a touch device like a smart phone. A common operation is to tap the screen
-and drag your finger to another part of the screen and lift it off.
-
-This can be simulated using an Action::
-
- from marionette import Actions
-
- start_element = marionette.find_element('id', 'start')
- end_element = marionette.find_element('id', 'end')
-
- action = Actions(marionette)
- action.press(start_element).wait(1).move(end_element).release()
- action.perform()
-
-This will simulate pressing an element, waiting for one second, moving the
-finger over to another element and then lifting the finger off the screen. The
-wait is optional in this case, but can be useful for simulating delays typical
-to a users behaviour.
-
-Multi-Action Sequences
-----------------------
-
-Sometimes it may be necessary to simulate multiple actions at the same time.
-For example a user may be dragging one finger while tapping another. This is
-where :class:`MultiActions` come in. MultiActions are simply a way of combining
-two or more actions together and performing them all at the same time::
-
- action1 = Actions(marionette)
- action1.press(start_element).move(end_element).release()
-
- action2 = Actions(marionette)
- action2.press(another_element).wait(1).release()
-
- multi = MultiActions(marionette)
- multi.add(action1)
- multi.add(action2)
- multi.perform()
diff --git a/testing/marionette/client/docs/advanced/debug.rst b/testing/marionette/client/docs/advanced/debug.rst
deleted file mode 100644
index e72d2549bd..0000000000
--- a/testing/marionette/client/docs/advanced/debug.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-Debugging
-=========
-
-.. py:currentmodule:: marionette
-
-Sometimes when working with Marionette you'll run into unexpected behaviour and
-need to do some debugging. This page outlines some of the Marionette methods
-that can be useful to you.
-
-Please note that the best tools for debugging are the `ones that ship with
-Gecko`_. This page doesn't describe how to use those with Marionette. Also see
-a related topic about `using the debugger with Marionette`_ on MDN.
-
-.. _ones that ship with Gecko: https://developer.mozilla.org/en-US/docs/Tools
-.. _using the debugger with Marionette: https://developer.mozilla.org/en-US/docs/Marionette/Debugging
-
-
-Storing Logs on the Server
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-By calling `~Marionette.log` it is possible to store a message on the server.
-Logs can later be retrieved using `~Marionette.get_logs`. For example::
-
- try:
- marionette.log("Sending a click event") # logged at INFO level
- elem.click()
- except:
- marionette.log("Something went wrong!", "ERROR")
-
- print(marionette.get_logs())
-
-Disclaimer: Example for illustrative purposes only, don't actually hide
-tracebacks like that!
-
-
-Seeing What's on the Page
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes it's difficult to tell what is actually on the page that is being
-manipulated. Either because it happens too fast, the window isn't big enough or
-you are manipulating a remote server! There are two methods that can help you
-out. The first is `~Marionette.screenshot`::
-
- marionette.screenshot() # takes screenshot of entire frame
- elem = marionette.find_element(By.ID, 'some-div')
- marionette.screenshot(elem) # takes a screenshot of only the given element
-
-Sometimes you just want to see the DOM layout. You can do this with the
-`~Marionette.page_source` property. Note that the page source depends on the
-context you are in::
-
- print(marionette.page_source)
- marionette.set_context('chrome')
- print(marionette.page_source)
diff --git a/testing/marionette/client/docs/advanced/findelement.rst b/testing/marionette/client/docs/advanced/findelement.rst
deleted file mode 100644
index abcbc8e89a..0000000000
--- a/testing/marionette/client/docs/advanced/findelement.rst
+++ /dev/null
@@ -1,126 +0,0 @@
-Finding Elements
-================
-.. py:currentmodule:: marionette
-
-One of the most common and yet often most difficult tasks in Marionette is
-finding a DOM element on a webpage or in the chrome UI. Marionette provides
-several different search strategies to use when finding elements. All search
-strategies work with both :func:`~Marionette.find_element` and
-:func:`~Marionette.find_elements`, though some strategies are not implemented
-in chrome scope.
-
-In the event that more than one element is matched by the query,
-:func:`~Marionette.find_element` will only return the first element found. In
-the event that no elements are matched by the query,
-:func:`~Marionette.find_element` will raise `NoSuchElementException` while
-:func:`~Marionette.find_elements` will return an empty list.
-
-Search Strategies
------------------
-
-Search strategies are defined in the :class:`By` class::
-
- from marionette import By
- print(By.ID)
-
-The strategies are:
-
-* `id` - The easiest way to find an element is to refer to its id directly::
-
- container = client.find_element(By.ID, 'container')
-
-* `class name` - To find elements belonging to a certain class, use `class name`::
-
- buttons = client.find_elements(By.CLASS_NAME, 'button')
-
-* `css selector` - It's also possible to find elements using a `css selector`_::
-
- container_buttons = client.find_elements(By.CSS_SELECTOR, '#container .buttons')
-
-* `name` - Find elements by their name attribute (not implemented in chrome
- scope)::
-
- form = client.find_element(By.NAME, 'signup')
-
-* `tag name` - To find all the elements with a given tag, use `tag name`::
-
- paragraphs = client.find_elements(By.TAG_NAME, 'p')
-
-* `link text` - A convenience strategy for finding link elements by their
- innerHTML (not implemented in chrome scope)::
-
- link = client.find_element(By.LINK_TEXT, 'Click me!')
-
-* `partial link text` - Same as `link text` except substrings of the innerHTML
- are matched (not implemented in chrome scope)::
-
- link = client.find_element(By.PARTIAL_LINK_TEXT, 'Clic')
-
-* `xpath` - Find elements using an xpath_ query::
-
- elem = client.find_element(By.XPATH, './/*[@id="foobar"')
-
-.. _css selector: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors
-.. _xpath: https://developer.mozilla.org/en-US/docs/Web/XPath
-
-
-
-Chaining Searches
------------------
-
-In addition to the methods on the Marionette object, HTMLElement objects also
-provide :func:`~HTMLElement.find_element` and :func:`~HTMLElement.find_elements`
-methods. The difference is that only child nodes of the element will be searched.
-Consider the following html snippet::
-
- <div id="content">
- <span id="main"></span>
- </div>
- <div id="footer"></div>
-
-Doing the following will work::
-
- client.find_element(By.ID, 'container').find_element(By.ID, 'main')
-
-But this will raise a `NoSuchElementException`::
-
- client.find_element(By.ID, 'container').find_element(By.ID, 'footer')
-
-
-Finding Anonymous Nodes
------------------------
-
-When working in chrome scope, for example manipulating the Firefox user
-interface, you may run into something called an anonymous node.
-
-Firefox uses a markup language called XUL_ for its interface. XUL is similar
-to HTML in that it has a DOM and tags that render controls on the display. One
-ability of XUL is to create re-useable widgets that are made up out of several
-smaller XUL elements. These widgets can be bound to the DOM using something
-called the `XML binding language (XBL)`_.
-
-The end result is that the DOM sees the widget as a single entity. It doesn't
-know anything about how that widget is made up. All of the smaller XUL elements
-that make up the widget are called `anonymous content`_. It is not possible to
-query such elements using traditional DOM methods like `getElementById`.
-
-Marionette provides two special strategies used for finding anonymous content.
-Unlike normal elements, anonymous nodes can only be seen by their parent. So
-it's necessary to first find the parent element and then search for the
-anonymous children from there.
-
-* `anon` - Finds all anonymous children of the element, there is no search term
- so `None` must be passed in::
-
- anon_children = client.find_element('id', 'parent').find_elements('anon', None)
-
-* `anon attribute` - Find an anonymous child based on an attribute. An
- unofficial convention is for anonymous nodes to have an
- `anonid` attribute::
-
- anon_child = client.find_element('id', 'parent').find_element('anon attribute', {'anonid': 'container'})
-
-
-.. _XUL: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL
-.. _XML binding language (XBL): https://developer.mozilla.org/en-US/docs/XBL
-.. _anonymous content: https://developer.mozilla.org/en-US/docs/XBL/XBL_1.0_Reference/Anonymous_Content
diff --git a/testing/marionette/client/docs/advanced/landing.rst b/testing/marionette/client/docs/advanced/landing.rst
deleted file mode 100644
index 0a44de63d7..0000000000
--- a/testing/marionette/client/docs/advanced/landing.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Advanced Topics
-===============
-
-Here are a collection of articles explaining some of the more complicated
-aspects of Marionette.
-
-.. toctree::
- :maxdepth: 1
-
- findelement
- stale
- actions
- debug
diff --git a/testing/marionette/client/docs/advanced/stale.rst b/testing/marionette/client/docs/advanced/stale.rst
deleted file mode 100644
index 0af5768653..0000000000
--- a/testing/marionette/client/docs/advanced/stale.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-Dealing with Stale Elements
-===========================
-.. py:currentmodule:: marionette
-
-Marionette does not keep a live representation of the DOM saved. All it can do
-is send commands to the Marionette server which queries the DOM on the client's
-behalf. References to elements are also not passed from server to client. A
-unique id is generated for each element that gets referenced and a mapping of
-id to element object is stored on the server. When commands such as
-:func:`~HTMLElement.click()` are run, the client sends the element's id along
-with the command. The server looks up the proper DOM element in its reference
-table and executes the command on it.
-
-In practice this means that the DOM can change state and Marionette will never
-know until it sends another query. For example, look at the following HTML::
-
- <head>
- <script type=text/javascript>
- function addDiv() {
- var div = document.createElement("div");
- document.getElementById("container").appendChild(div);
- }
- </script>
- </head>
-
- <body>
- <div id="container">
- </div>
- <input id="button" type=button onclick="addDiv();">
- </body>
-
-Care needs to be taken as the DOM is being modified after the page has loaded.
-The following code has a race condition::
-
- button = client.find_element('id', 'button')
- button.click()
- assert len(client.find_elements('css selector', '#container div')) > 0
-
-
-Explicit Waiting and Expected Conditions
-----------------------------------------
-
-To avoid the above scenario, manual synchronisation is needed. Waits are used
-to pause program execution until a given condition is true. This is a useful
-technique to employ when documents load new content or change after
-``Document.readyState``'s value changes to "complete".
-
-The :class:`Wait` helper class provided by Marionette avoids some of the
-caveats of ``time.sleep(n)``. It will return immediately once the provided
-condition evaluates to true.
-
-To avoid the race condition in the above example, one could do::
-
- button = client.find_element('id', 'button')
- button.click()
-
- def find_divs():
- return client.find_elements('css selector', '#container div')
-
- divs = Wait(client).until(find_divs)
- assert len(divs) > 0
-
-This avoids the race condition. Because finding elements is a common condition
-to wait for, it is built in to Marionette. Instead of the above, you could
-write::
-
- button = client.find_element('id', 'button')
- button.click()
- assert len(Wait(client).until(expected.elements_present('css selector', '#container div'))) > 0
-
-For a full list of built-in conditions, see :mod:`~marionette.expected`.
diff --git a/testing/marionette/client/docs/basics.rst b/testing/marionette/client/docs/basics.rst
deleted file mode 100644
index 0de72c6256..0000000000
--- a/testing/marionette/client/docs/basics.rst
+++ /dev/null
@@ -1,185 +0,0 @@
-.. py:currentmodule:: marionette_driver.marionette
-
-Marionette Python Client
-========================
-
-The Marionette Python client library allows you to remotely control a
-Gecko-based browser or device which is running a Marionette_
-server. This includes Firefox Desktop and Firefox for Android.
-
-The Marionette server is built directly into Gecko and can be started by
-passing in a command line option to Gecko, or by using a Marionette-enabled
-build. The server listens for connections from various clients. Clients can
-then control Gecko by sending commands to the server.
-
-This is the official Python client for Marionette. There also exists a
-`NodeJS client`_ maintained by the Firefox OS automation team.
-
-.. _Marionette: https://developer.mozilla.org/en-US/docs/Marionette
-.. _NodeJS client: https://github.com/mozilla-b2g/gaia/tree/master/tests/jsmarionette
-
-Getting the Client
-------------------
-
-The Python client is officially supported. To install it, first make sure you
-have `pip installed`_ then run:
-
-.. parsed-literal::
- pip install marionette_driver
-
-It's highly recommended to use virtualenv_ when installing Marionette to avoid
-package conflicts and other general nastiness.
-
-You should now be ready to start using Marionette. The best way to learn is to
-play around with it. Start a `Marionette-enabled instance of Firefox`_, fire up
-a python shell and follow along with the
-:doc:`interactive tutorial <interactive>`!
-
-.. _pip installed: https://pip.pypa.io/en/latest/installing.html
-.. _virtualenv: http://virtualenv.readthedocs.org/en/latest/
-.. _Marionette-enabled instance of Firefox: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Builds
-
-Using the Client for Testing
-----------------------------
-
-Please visit the `Marionette Tests`_ section on MDN for information regarding
-testing with Marionette.
-
-.. _Marionette Tests: https://developer.mozilla.org/en/Marionette/Tests
-
-Session Management
-------------------
-A session is a single instance of a Marionette client connected to a Marionette
-server. Before you can start executing commands, you need to start a session
-with :func:`start_session() <Marionette.start_session>`:
-
-.. parsed-literal::
- from marionette_driver.marionette import Marionette
-
- client = Marionette('localhost', port=2828)
- client.start_session()
-
-This returns a session id and an object listing the capabilities of the
-Marionette server. For example, a server running on Firefox Desktop will
-have some features which a server running from Firefox Android won't.
-It's also possible to access the capabilities using the
-:attr:`~Marionette.session_capabilities` attribute. After finishing with a
-session, you can delete it with :func:`~Marionette.delete_session()`. Note that
-this will also happen automatically when the Marionette object is garbage
-collected.
-
-Context Management
-------------------
-Commands can only be executed in a single window, frame and scope at a time. In
-order to run commands elsewhere, it's necessary to explicitly switch to the
-appropriate context.
-
-Use :func:`~Marionette.switch_to_window` to execute commands in the context of a
-new window:
-
-.. parsed-literal::
- original_window = client.current_window_handle
- for handle in client.window_handles:
- if handle != original_window:
- client.switch_to_window(handle)
- print("Switched to window with '{}' loaded.".format(client.get_url()))
- client.switch_to_window(original_window)
-
-Similarly, use :func:`~Marionette.switch_to_frame` to execute commands in the
-context of a new frame (e.g an <iframe> element):
-
-.. parsed-literal::
- iframe = client.find_element(By.TAG_NAME, 'iframe')
- client.switch_to_frame(iframe)
- assert iframe == client.get_active_frame()
-
-Finally Marionette can switch between `chrome` and `content` scope. Chrome is a
-privileged scope where you can access things like the Firefox UI itself.
-Content scope is where things like webpages live. You can switch between
-`chrome` and `content` using the :func:`~Marionette.set_context` and :func:`~Marionette.using_context` functions:
-
-.. parsed-literal::
- client.set_context(client.CONTEXT_CONTENT)
- # content scope
- with client.using_context(client.CONTEXT_CHROME):
- #chrome scope
- ... do stuff ...
- # content scope restored
-
-
-Navigation
-----------
-
-Use :func:`~Marionette.navigate` to open a new website. It's also possible to
-move through the back/forward cache using :func:`~Marionette.go_forward` and
-:func:`~Marionette.go_back` respectively. To retrieve the currently
-open website, use :func:`~Marionette.get_url`:
-
-.. parsed-literal::
- url = 'http://mozilla.org'
- client.navigate(url)
- client.go_back()
- client.go_forward()
- assert client.get_url() == url
-
-
-DOM Elements
-------------
-
-In order to inspect or manipulate actual DOM elements, they must first be found
-using the :func:`~Marionette.find_element` or :func:`~Marionette.find_elements`
-methods:
-
-.. parsed-literal::
- from marionette import HTMLElement
- element = client.find_element(By.ID, 'my-id')
- assert type(element) == HTMLElement
- elements = client.find_elements(By.TAG_NAME, 'a')
- assert type(elements) == list
-
-For a full list of valid search strategies, see :doc:`advanced/findelement`.
-
-Now that an element has been found, it's possible to manipulate it:
-
-.. parsed-literal::
- element.click()
- element.send_keys('hello!')
- print(element.get_attribute('style'))
-
-For the full list of possible commands, see the :class:`HTMLElement`
-reference.
-
-Be warned that a reference to an element object can become stale if it was
-modified or removed from the document. See :doc:`advanced/stale` for tips
-on working around this limitation.
-
-Script Execution
-----------------
-
-Sometimes Marionette's provided APIs just aren't enough and it is necessary to
-run arbitrary javascript. This is accomplished with the
-:func:`~Marionette.execute_script` and :func:`~Marionette.execute_async_script`
-functions. They accomplish what their names suggest, the former executes some
-synchronous JavaScript, while the latter provides a callback mechanism for
-running asynchronous JavaScript:
-
-.. parsed-literal::
- result = client.execute_script("return arguments[0] + arguments[1];",
- script_args=[2, 3])
- assert result == 5
-
-The async method works the same way, except it won't return until a special
-`marionetteScriptFinished()` function is called:
-
-.. parsed-literal::
- result = client.execute_async_script("""
- setTimeout(function() {
- marionetteScriptFinished("all done");
- }, arguments[0]);
- """, script_args=[1000])
- assert result == "all done"
-
-Beware that running asynchronous scripts can potentially hang the program
-indefinitely if they are not written properly. It is generally a good idea to
-set a script timeout using :func:`~Marionette.timeout.script` and handling
-`ScriptTimeoutException`.
diff --git a/testing/marionette/client/docs/conf.py b/testing/marionette/client/docs/conf.py
deleted file mode 100644
index c3a74eef61..0000000000
--- a/testing/marionette/client/docs/conf.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Marionette Python Client documentation build configuration file, created by
-# sphinx-quickstart on Tue Aug 6 13:54:46 2013.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import os
-import sys
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-here = os.path.dirname(os.path.abspath(__file__))
-parent = os.path.dirname(here)
-sys.path.insert(0, parent)
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'Marionette Python Client'
-copyright = u'2013, Mozilla Automation and Tools and individual contributors'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-# version = '0'
-# The full version, including alpha/beta/rc tags.
-# release = '0'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-
-html_theme = 'default'
-
-on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
-
-if not on_rtd:
- try:
- import sphinx_rtd_theme
- html_theme = 'sphinx_rtd_theme'
- html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
- except ImportError:
- pass
-
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-# html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-# html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'MarionettePythonClientdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- # 'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- # 'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- # 'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'MarionettePythonClient.tex', u'Marionette Python Client Documentation',
- u'Mozilla Automation and Tools team', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'marionettepythonclient', u'Marionette Python Client Documentation',
- [u'Mozilla Automation and Tools team'], 1)
-]
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'MarionettePythonClient', 'Marionette Python Client Documentation',
- 'Mozilla Automation and Tools team', 'MarionettePythonClient',
- 'One line description of project.', 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
diff --git a/testing/marionette/client/docs/index.rst b/testing/marionette/client/docs/index.rst
deleted file mode 100644
index b1f266726c..0000000000
--- a/testing/marionette/client/docs/index.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-.. include:: basics.rst
-
-Indices and tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
-.. toctree::
- :hidden:
-
- Getting Started <basics>
- Interactive Tutorial <interactive>
- advanced/landing
- reference
diff --git a/testing/marionette/client/docs/interactive.rst b/testing/marionette/client/docs/interactive.rst
deleted file mode 100644
index e6d7556134..0000000000
--- a/testing/marionette/client/docs/interactive.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-Using the Client Interactively
-==============================
-
-Once you installed the client and have Marionette running, you can fire
-up your favourite interactive python environment and start playing with
-Marionette. Let's use a typical python shell:
-
-.. parsed-literal::
-
- python
-
-First, import Marionette:
-
-.. parsed-literal::
- from marionette import Marionette
-
-Now create the client for this session. Assuming you're using the default
-port on a Marionette instance running locally:
-
-.. parsed-literal::
-
- client = Marionette(host='localhost', port=2828)
- client.start_session()
-
-This will return some id representing your session id. Now that you've
-established a connection, let's start doing interesting things:
-
-.. parsed-literal::
-
- client.execute_script("alert('o hai there!');")
-
-You should now see this alert pop up! How exciting! Okay, let's do
-something practical. Close the dialog and try this:
-
-.. parsed-literal::
-
- client.navigate("http://www.mozilla.org")
-
-Now you're at mozilla.org! You can even verify it using the following:
-
-.. parsed-literal::
- client.get_url()
-
-You can even find an element and click on it. Let's say you want to get
-the first link:
-
-.. parsed-literal::
- from marionette import By
- first_link = client.find_element(By.TAG_NAME, "a")
-
-first_link now holds a reference to the first link on the page. You can click it:
-
-.. parsed-literal::
- first_link.click()
-
diff --git a/testing/marionette/client/docs/make.bat b/testing/marionette/client/docs/make.bat
deleted file mode 100644
index fb02fc1a8c..0000000000
--- a/testing/marionette/client/docs/make.bat
+++ /dev/null
@@ -1,190 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\MarionettePythonClient.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\MarionettePythonClient.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/testing/marionette/client/docs/reference.rst b/testing/marionette/client/docs/reference.rst
deleted file mode 100644
index 7d2fc5b00f..0000000000
--- a/testing/marionette/client/docs/reference.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-=============
-API Reference
-=============
-
-Marionette
-----------
-.. autoclass:: marionette_driver.marionette.Marionette
- :members:
-
-HTMLElement
------------
-.. autoclass:: marionette_driver.marionette.HTMLElement
- :members:
-
-DateTimeValue
--------------
-.. autoclass:: marionette_driver.DateTimeValue
- :members:
-
-Actions
--------
-.. autoclass:: marionette_driver.marionette.Actions
- :members:
-
-MultiActions
-------------
-.. autoclass:: marionette_driver.marionette.MultiActions
- :members:
-
-Wait
-----
-.. autoclass:: marionette_driver.Wait
- :members:
- :special-members:
-.. autoattribute marionette_driver.wait.DEFAULT_TIMEOUT
-.. autoattribute marionette_driver.wait.DEFAULT_INTERVAL
-
-Built-in Conditions
-^^^^^^^^^^^^^^^^^^^
-.. automodule:: marionette_driver.expected
- :members:
-
-Addons
-------
-.. autoclass:: marionette_driver.addons.Addons
- :members:
-
-Localization
-------------
-.. autoclass:: marionette_driver.localization.L10n
- :members:
diff --git a/testing/marionette/client/marionette_driver/__init__.py b/testing/marionette/client/marionette_driver/__init__.py
deleted file mode 100644
index d947d9c27c..0000000000
--- a/testing/marionette/client/marionette_driver/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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/.
-
-__version__ = '2.2.0'
-
-from marionette_driver import (
- addons,
- by,
- date_time_value,
- decorators,
- errors,
- expected,
- geckoinstance,
- gestures,
- keys,
- localization,
- marionette,
- selection,
- wait,
-)
-from marionette_driver.by import By
-from marionette_driver.date_time_value import DateTimeValue
-from marionette_driver.gestures import smooth_scroll, pinch
-from marionette_driver.marionette import Actions
-from marionette_driver.wait import Wait
diff --git a/testing/marionette/client/marionette_driver/addons.py b/testing/marionette/client/marionette_driver/addons.py
deleted file mode 100644
index 0a8baef4fc..0000000000
--- a/testing/marionette/client/marionette_driver/addons.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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 . import errors
-
-__all__ = ["Addons", "AddonInstallException"]
-
-
-class AddonInstallException(errors.MarionetteException):
- pass
-
-
-class Addons(object):
- """An API for installing and inspecting addons during Gecko
- runtime. This is a partially implemented wrapper around Gecko's
- `AddonManager API`_.
-
- For example::
-
- from marionette_driver.addons import Addons
- addons = Addons(marionette)
- addons.install("/path/to/extension.xpi")
-
- .. _AddonManager API: https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager
-
- """
- def __init__(self, marionette):
- self._mn = marionette
-
- def install(self, path, temp=False):
- """Install a Firefox addon.
-
- If the addon is restartless, it can be used right away. Otherwise
- a restart using :func:`~marionette_driver.marionette.Marionette.restart`
- will be needed.
-
- :param path: A file path to the extension to be installed.
- :param temp: Install a temporary addon. Temporary addons will
- automatically be uninstalled on shutdown and do not need
- to be signed, though they must be restartless.
-
- :returns: The addon ID string of the newly installed addon.
-
- :raises: :exc:`AddonInstallException`
-
- """
- body = {"path": path, "temporary": temp}
- try:
- return self._mn._send_message("addon:install", body, key="value")
- except errors.UnknownException as e:
- raise AddonInstallException(e)
-
- def uninstall(self, addon_id):
- """Uninstall a Firefox addon.
-
- If the addon is restartless, it will be uninstalled right away.
- Otherwise a restart using :func:`~marionette_driver.marionette.Marionette.restart`
- will be needed.
-
- If the call to uninstall is resulting in a `ScriptTimeoutException`,
- an invalid ID is likely being passed in. Unfortunately due to
- AddonManager's implementation, it's hard to retrieve this error from
- Python.
-
- :param addon_id: The addon ID string to uninstall.
-
- """
- body = {"id": addon_id}
- self._mn._send_message("addon:uninstall", body)
diff --git a/testing/marionette/client/marionette_driver/by.py b/testing/marionette/client/marionette_driver/by.py
deleted file mode 100644
index 8232be1453..0000000000
--- a/testing/marionette/client/marionette_driver/by.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2008-2009 WebDriver committers
-# Copyright 2008-2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class By(object):
- ID = "id"
- XPATH = "xpath"
- LINK_TEXT = "link text"
- PARTIAL_LINK_TEXT = "partial link text"
- NAME = "name"
- TAG_NAME = "tag name"
- CLASS_NAME = "class name"
- CSS_SELECTOR = "css selector"
- ANON_ATTRIBUTE = "anon attribute"
- ANON = "anon"
diff --git a/testing/marionette/client/marionette_driver/date_time_value.py b/testing/marionette/client/marionette_driver/date_time_value.py
deleted file mode 100644
index 35c541dc02..0000000000
--- a/testing/marionette/client/marionette_driver/date_time_value.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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 DateTimeValue(object):
- """
- Interface for setting the value of HTML5 "date" and "time" input elements.
-
- Simple usage example:
-
- ::
-
- element = marionette.find_element(By.ID, "date-test")
- dt_value = DateTimeValue(element)
- dt_value.date = datetime(1998, 6, 2)
-
- """
-
- def __init__(self, element):
- self.element = element
-
- @property
- def date(self):
- """
- Retrieve the element's string value
- """
- return self.element.get_attribute('value')
-
- # As per the W3C "date" element specification
- # (http://dev.w3.org/html5/markup/input.date.html), this value is formatted
- # according to RFC 3339: http://tools.ietf.org/html/rfc3339#section-5.6
- @date.setter
- def date(self, date_value):
- self.element.send_keys(date_value.strftime('%Y-%m-%d'))
-
- @property
- def time(self):
- """
- Retrieve the element's string value
- """
- return self.element.get_attribute('value')
-
- # As per the W3C "time" element specification
- # (http://dev.w3.org/html5/markup/input.time.html), this value is formatted
- # according to RFC 3339: http://tools.ietf.org/html/rfc3339#section-5.6
- @time.setter
- def time(self, time_value):
- self.element.send_keys(time_value.strftime('%H:%M:%S'))
diff --git a/testing/marionette/client/marionette_driver/decorators.py b/testing/marionette/client/marionette_driver/decorators.py
deleted file mode 100644
index f651524719..0000000000
--- a/testing/marionette/client/marionette_driver/decorators.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# 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 functools import wraps
-import socket
-
-
-def _find_marionette_in_args(*args, **kwargs):
- try:
- m = [a for a in args + tuple(kwargs.values()) if hasattr(a, 'session')][0]
- except IndexError:
- print("Can only apply decorator to function using a marionette object")
- raise
- return m
-
-
-def do_process_check(func):
- """Decorator which checks the process status after the function has run."""
- @wraps(func)
- def _(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except (socket.error, socket.timeout):
- # In case of socket failures which will also include crashes of the
- # application, make sure to handle those correctly.
- m = _find_marionette_in_args(*args, **kwargs)
- m._handle_socket_failure()
-
- return _
-
-
-def uses_marionette(func):
- """Decorator which creates a marionette session and deletes it
- afterwards if one doesn't already exist.
- """
- @wraps(func)
- def _(*args, **kwargs):
- m = _find_marionette_in_args(*args, **kwargs)
- delete_session = False
- if not m.session:
- delete_session = True
- m.start_session()
-
- m.set_context(m.CONTEXT_CHROME)
- ret = func(*args, **kwargs)
-
- if delete_session:
- m.delete_session()
-
- return ret
- return _
-
-
-def using_context(context):
- """Decorator which allows a function to execute in certain scope
- using marionette.using_context functionality and returns to old
- scope once the function exits.
- :param context: Either 'chrome' or 'content'.
- """
- def wrap(func):
- @wraps(func)
- def inner(*args, **kwargs):
- m = _find_marionette_in_args(*args, **kwargs)
- with m.using_context(context):
- return func(*args, **kwargs)
-
- return inner
- return wrap
diff --git a/testing/marionette/client/marionette_driver/errors.py b/testing/marionette/client/marionette_driver/errors.py
deleted file mode 100644
index 8fb1d564e4..0000000000
--- a/testing/marionette/client/marionette_driver/errors.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# 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 traceback
-
-
-class MarionetteException(Exception):
-
- """Raised when a generic non-recoverable exception has occured."""
-
- status = "webdriver error"
-
- def __init__(self, message=None, cause=None, stacktrace=None):
- """Construct new MarionetteException instance.
-
- :param message: An optional exception message.
-
- :param cause: An optional tuple of three values giving
- information about the root exception cause. Expected
- tuple values are (type, value, traceback).
-
- :param stacktrace: Optional string containing a stacktrace
- (typically from a failed JavaScript execution) that will
- be displayed in the exception's string representation.
-
- """
- self.cause = cause
- self.stacktrace = stacktrace
-
- super(MarionetteException, self).__init__(message)
-
- def __str__(self):
- msg = str(self.message)
- tb = None
-
- if self.cause:
- if type(self.cause) is tuple:
- msg += ", caused by {0!r}".format(self.cause[0])
- tb = self.cause[2]
- else:
- msg += ", caused by {}".format(self.cause)
- if self.stacktrace:
- st = "".join(["\t{}\n".format(x)
- for x in self.stacktrace.splitlines()])
- msg += "\nstacktrace:\n{}".format(st)
-
- if tb:
- msg += ': ' + "".join(traceback.format_tb(tb))
-
- return msg
-
-
-class ElementNotSelectableException(MarionetteException):
- status = "element not selectable"
-
-
-class ElementClickInterceptedException(MarionetteException):
- status = "element click intercepted"
-
-
-class InsecureCertificateException(MarionetteException):
- status = "insecure certificate"
-
-
-class InvalidArgumentException(MarionetteException):
- status = "invalid argument"
-
-
-class InvalidSessionIdException(MarionetteException):
- status = "invalid session id"
-
-
-class TimeoutException(MarionetteException):
- status = "timeout"
-
-
-class JavascriptException(MarionetteException):
- status = "javascript error"
-
-
-class NoSuchElementException(MarionetteException):
- status = "no such element"
-
-
-class NoSuchWindowException(MarionetteException):
- status = "no such window"
-
-
-class StaleElementException(MarionetteException):
- status = "stale element reference"
-
-
-class ScriptTimeoutException(MarionetteException):
- status = "script timeout"
-
-
-class ElementNotVisibleException(MarionetteException):
- """Deprecated. Will be removed with the release of Firefox 54."""
-
- status = "element not visible"
-
- def __init__(self,
- message="Element is not currently visible and may not be manipulated",
- stacktrace=None, cause=None):
- super(ElementNotVisibleException, self).__init__(
- message, cause=cause, stacktrace=stacktrace)
-
-
-class ElementNotAccessibleException(MarionetteException):
- status = "element not accessible"
-
-
-class ElementNotInteractableException(MarionetteException):
- status = "element not interactable"
-
-
-class NoSuchFrameException(MarionetteException):
- status = "no such frame"
-
-
-class InvalidElementStateException(MarionetteException):
- status = "invalid element state"
-
-
-class NoAlertPresentException(MarionetteException):
- status = "no such alert"
-
-
-class InvalidCookieDomainException(MarionetteException):
- status = "invalid cookie domain"
-
-
-class UnableToSetCookieException(MarionetteException):
- status = "unable to set cookie"
-
-
-class InvalidElementCoordinates(MarionetteException):
- status = "invalid element coordinates"
-
-
-class InvalidSelectorException(MarionetteException):
- status = "invalid selector"
-
-
-class MoveTargetOutOfBoundsException(MarionetteException):
- status = "move target out of bounds"
-
-
-class SessionNotCreatedException(MarionetteException):
- status = "session not created"
-
-
-class UnexpectedAlertOpen(MarionetteException):
- status = "unexpected alert open"
-
-
-class UnknownCommandException(MarionetteException):
- status = "unknown command"
-
-
-class UnknownException(MarionetteException):
- status = "unknown error"
-
-
-class UnsupportedOperationException(MarionetteException):
- status = "unsupported operation"
-
-
-es_ = [e for e in locals().values() if type(e) == type and issubclass(e, MarionetteException)]
-by_string = {e.status: e for e in es_}
-
-
-def lookup(identifier):
- """Finds error exception class by associated Selenium JSON wire
- protocol number code, or W3C WebDriver protocol string.
-
- """
- return by_string.get(identifier, MarionetteException)
diff --git a/testing/marionette/client/marionette_driver/expected.py b/testing/marionette/client/marionette_driver/expected.py
deleted file mode 100644
index d8c47e708f..0000000000
--- a/testing/marionette/client/marionette_driver/expected.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# 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 errors
-import types
-
-from marionette import HTMLElement
-
-"""This file provides a set of expected conditions for common use
-cases when writing Marionette tests.
-
-The conditions rely on explicit waits that retries conditions a number
-of times until they are either successfully met, or they time out.
-
-"""
-
-
-class element_present(object):
- """Checks that a web element is present in the DOM of the current
- context. This does not necessarily mean that the element is
- visible.
-
- You can select which element to be checked for presence by
- supplying a locator::
-
- el = Wait(marionette).until(expected.element_present(By.ID, "foo"))
-
- Or by using a function/lambda returning an element::
-
- el = Wait(marionette).\
- until(expected.element_present(lambda m: m.find_element(By.ID, "foo")))
-
- :param args: locator or function returning web element
- :returns: the web element once it is located, or False
-
- """
-
- def __init__(self, *args):
- if len(args) == 1 and isinstance(args[0], types.FunctionType):
- self.locator = args[0]
- else:
- self.locator = lambda m: m.find_element(*args)
-
- def __call__(self, marionette):
- return _find(marionette, self.locator)
-
-
-class element_not_present(element_present):
- """Checks that a web element is not present in the DOM of the current
- context.
-
- You can select which element to be checked for lack of presence by
- supplying a locator::
-
- r = Wait(marionette).until(expected.element_not_present(By.ID, "foo"))
-
- Or by using a function/lambda returning an element::
-
- r = Wait(marionette).\
- until(expected.element_present(lambda m: m.find_element(By.ID, "foo")))
-
- :param args: locator or function returning web element
- :returns: True if element is not present, or False if it is present
-
- """
-
- def __init__(self, *args):
- super(element_not_present, self).__init__(*args)
-
- def __call__(self, marionette):
- return not super(element_not_present, self).__call__(marionette)
-
-
-class element_stale(object):
- """Check that the given element is no longer attached to DOM of the
- current context.
-
- This can be useful for waiting until an element is no longer
- present.
-
- Sample usage::
-
- el = marionette.find_element(By.ID, "foo")
- # ...
- Wait(marionette).until(expected.element_stale(el))
-
- :param element: the element to wait for
- :returns: False if the element is still attached to the DOM, True
- otherwise
-
- """
-
- def __init__(self, element):
- self.el = element
-
- def __call__(self, marionette):
- try:
- # Calling any method forces a staleness check
- self.el.is_enabled()
- return False
- except errors.StaleElementException:
- return True
-
-
-class elements_present(object):
- """Checks that web elements are present in the DOM of the current
- context. This does not necessarily mean that the elements are
- visible.
-
- You can select which elements to be checked for presence by
- supplying a locator::
-
- els = Wait(marionette).until(expected.elements_present(By.TAG_NAME, "a"))
-
- Or by using a function/lambda returning a list of elements::
-
- els = Wait(marionette).\
- until(expected.elements_present(lambda m: m.find_elements(By.TAG_NAME, "a")))
-
- :param args: locator or function returning a list of web elements
- :returns: list of web elements once they are located, or False
-
- """
-
- def __init__(self, *args):
- if len(args) == 1 and isinstance(args[0], types.FunctionType):
- self.locator = args[0]
- else:
- self.locator = lambda m: m.find_elements(*args)
-
- def __call__(self, marionette):
- return _find(marionette, self.locator)
-
-
-class elements_not_present(elements_present):
- """Checks that web elements are not present in the DOM of the
- current context.
-
- You can select which elements to be checked for not being present
- by supplying a locator::
-
- r = Wait(marionette).until(expected.elements_not_present(By.TAG_NAME, "a"))
-
- Or by using a function/lambda returning a list of elements::
-
- r = Wait(marionette).\
- until(expected.elements_not_present(lambda m: m.find_elements(By.TAG_NAME, "a")))
-
- :param args: locator or function returning a list of web elements
- :returns: True if elements are missing, False if one or more are
- present
-
- """
-
- def __init__(self, *args):
- super(elements_not_present, self).__init__(*args)
-
- def __call__(self, marionette):
- return not super(elements_not_present, self).__call__(marionette)
-
-
-class element_displayed(object):
- """An expectation for checking that an element is visible.
-
- Visibility means that the element is not only displayed, but also
- has a height and width that is greater than 0 pixels.
-
- Stale elements, meaning elements that have been detached from the
- DOM of the current context are treated as not being displayed,
- meaning this expectation is not analogous to the behaviour of
- calling `is_displayed()` on an `HTMLElement`.
-
- You can select which element to be checked for visibility by
- supplying a locator::
-
- displayed = Wait(marionette).until(expected.element_displayed(By.ID, "foo"))
-
- Or by supplying an element::
-
- el = marionette.find_element(By.ID, "foo")
- displayed = Wait(marionette).until(expected.element_displayed(el))
-
- :param args: locator or web element
- :returns: True if element is displayed, False if hidden
-
- """
-
- def __init__(self, *args):
- self.el = None
- if len(args) == 1 and isinstance(args[0], HTMLElement):
- self.el = args[0]
- else:
- self.locator = lambda m: m.find_element(*args)
-
- def __call__(self, marionette):
- if self.el is None:
- self.el = _find(marionette, self.locator)
- if not self.el:
- return False
- try:
- return self.el.is_displayed()
- except errors.StaleElementException:
- return False
-
-
-class element_not_displayed(element_displayed):
- """An expectation for checking that an element is not visible.
-
- Visibility means that the element is not only displayed, but also
- has a height and width that is greater than 0 pixels.
-
- Stale elements, meaning elements that have been detached fom the
- DOM of the current context are treated as not being displayed,
- meaning this expectation is not analogous to the behaviour of
- calling `is_displayed()` on an `HTMLElement`.
-
- You can select which element to be checked for visibility by
- supplying a locator::
-
- hidden = Wait(marionette).until(expected.element_not_displayed(By.ID, "foo"))
-
- Or by supplying an element::
-
- el = marionette.find_element(By.ID, "foo")
- hidden = Wait(marionette).until(expected.element_not_displayed(el))
-
- :param args: locator or web element
- :returns: True if element is hidden, False if displayed
-
- """
-
- def __init__(self, *args):
- super(element_not_displayed, self).__init__(*args)
-
- def __call__(self, marionette):
- return not super(element_not_displayed, self).__call__(marionette)
-
-
-class element_selected(object):
- """An expectation for checking that the given element is selected.
-
- :param element: the element to be selected
- :returns: True if element is selected, False otherwise
-
- """
-
- def __init__(self, element):
- self.el = element
-
- def __call__(self, marionette):
- return self.el.is_selected()
-
-
-class element_not_selected(element_selected):
- """An expectation for checking that the given element is not
- selected.
-
- :param element: the element to not be selected
- :returns: True if element is not selected, False if selected
-
- """
-
- def __init__(self, element):
- super(element_not_selected, self).__init__(element)
-
- def __call__(self, marionette):
- return not super(element_not_selected, self).__call__(marionette)
-
-
-class element_enabled(object):
- """An expectation for checking that the given element is enabled.
-
- :param element: the element to check if enabled
- :returns: True if element is enabled, False otherwise
-
- """
-
- def __init__(self, element):
- self.el = element
-
- def __call__(self, marionette):
- return self.el.is_enabled()
-
-
-class element_not_enabled(element_enabled):
- """An expectation for checking that the given element is disabled.
-
- :param element: the element to check if disabled
- :returns: True if element is disabled, False if enabled
-
- """
-
- def __init__(self, element):
- super(element_not_enabled, self).__init__(element)
-
- def __call__(self, marionette):
- return not super(element_not_enabled, self).__call__(marionette)
-
-
-def _find(marionette, func):
- el = None
-
- try:
- el = func(marionette)
- except errors.NoSuchElementException:
- pass
-
- if el is None:
- return False
- return el
diff --git a/testing/marionette/client/marionette_driver/geckoinstance.py b/testing/marionette/client/marionette_driver/geckoinstance.py
deleted file mode 100644
index c59cc2acea..0000000000
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ /dev/null
@@ -1,464 +0,0 @@
-# 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
-import sys
-import tempfile
-import time
-
-from copy import deepcopy
-
-import mozversion
-
-from mozprofile import Profile
-from mozrunner import Runner, FennecEmulatorRunner
-
-
-class GeckoInstance(object):
- required_prefs = {
- # Increase the APZ content response timeout in tests to 1 minute.
- # This is to accommodate the fact that test environments tends to be slower
- # than production environments (with the b2g emulator being the slowest of them
- # all), resulting in the production timeout value sometimes being exceeded
- # and causing false-positive test failures. See bug 1176798, bug 1177018,
- # bug 1210465.
- "apz.content_response_timeout": 60000,
-
- # Do not send Firefox health reports to the production server
- "datareporting.healthreport.documentServerURI": "http://%(server)s/dummy/healthreport/",
- "datareporting.healthreport.about.reportUrl": "http://%(server)s/dummy/abouthealthreport/",
-
- # Do not show datareporting policy notifications which can interfer with tests
- "datareporting.policy.dataSubmissionPolicyBypassNotification": True,
-
- # Until Bug 1238095 is fixed, we have to enable CPOWs in order
- # for Marionette tests to work properly.
- "dom.ipc.cpows.forbid-unsafe-from-browser": False,
- "dom.ipc.reportProcessHangs": False,
-
- # No slow script dialogs
- "dom.max_chrome_script_run_time": 0,
- "dom.max_script_run_time": 0,
-
- # Only load extensions from the application and user profile
- # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
- "extensions.autoDisableScopes": 0,
- "extensions.enabledScopes": 5,
- # don't block add-ons for e10s
- "extensions.e10sBlocksEnabling": False,
- # Disable metadata caching for installed add-ons by default
- "extensions.getAddons.cache.enabled": False,
- # Disable intalling any distribution add-ons
- "extensions.installDistroAddons": False,
- "extensions.showMismatchUI": False,
- # Turn off extension updates so they don't bother tests
- "extensions.update.enabled": False,
- "extensions.update.notifyUser": False,
- # Make sure opening about:addons won"t hit the network
- "extensions.webservice.discoverURL": "http://%(server)s/dummy/discoveryURL",
-
- # Allow the application to have focus even it runs in the background
- "focusmanager.testmode": True,
-
- # Disable useragent updates
- "general.useragent.updates.enabled": False,
-
- # Always use network provider for geolocation tests
- # so we bypass the OSX dialog raised by the corelocation provider
- "geo.provider.testing": True,
- # Do not scan Wifi
- "geo.wifi.scan": False,
-
- # No hang monitor
- "hangmonitor.timeout": 0,
-
- "javascript.options.showInConsole": True,
- "marionette.defaultPrefs.enabled": True,
- "media.volume_scale": "0.01",
-
- # Do not prompt for temporary redirects
- "network.http.prompt-temp-redirect": False,
- # Disable speculative connections so they aren"t reported as leaking when they"re
- # hanging around
- "network.http.speculative-parallel-limit": 0,
- # Do not automatically switch between offline and online
- "network.manage-offline-status": False,
- # Make sure SNTP requests don't hit the network
- "network.sntp.pools": "%(server)s",
-
- # Tests don't wait for the notification button security delay
- "security.notification_enable_delay": 0,
-
- # Ensure blocklist updates don't hit the network
- "services.settings.server": "http://%(server)s/dummy/blocklist/",
-
- # Disable password capture, so that tests that include forms aren"t
- # influenced by the presence of the persistent doorhanger notification
- "signon.rememberSignons": False,
-
- # Prevent starting into safe mode after application crashes
- "toolkit.startup.max_resumed_crashes": -1,
-
- # We want to collect telemetry, but we don't want to send in the results
- "toolkit.telemetry.server": "https://%(server)s/dummy/telemetry/",
- }
-
- def __init__(self, host=None, port=None, bin=None, profile=None, addons=None,
- app_args=None, symbols_path=None, gecko_log=None, prefs=None,
- workspace=None, verbose=0):
- self.runner_class = Runner
- self.app_args = app_args or []
- self.runner = None
- self.symbols_path = symbols_path
- self.binary = bin
-
- self.marionette_host = host
- self.marionette_port = port
- # Alternative to default temporary directory
- self.workspace = workspace
- self.addons = addons
- # Check if it is a Profile object or a path to profile
- self.profile = None
- if isinstance(profile, Profile):
- self.profile = profile
- else:
- self.profile_path = profile
- self.prefs = prefs
- self.required_prefs = deepcopy(self.required_prefs)
- if prefs:
- self.required_prefs.update(prefs)
-
- self._gecko_log_option = gecko_log
- self._gecko_log = None
- self.verbose = verbose
-
- @property
- def gecko_log(self):
- if self._gecko_log:
- return self._gecko_log
-
- path = self._gecko_log_option
- if path != "-":
- if path is None:
- path = "gecko.log"
- elif os.path.isdir(path):
- fname = "gecko-{}.log".format(time.time())
- path = os.path.join(path, fname)
-
- path = os.path.realpath(path)
- if os.access(path, os.F_OK):
- os.remove(path)
-
- self._gecko_log = path
- return self._gecko_log
-
- def _update_profile(self):
- profile_args = {"preferences": deepcopy(self.required_prefs)}
- profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port
- if self.prefs:
- profile_args["preferences"].update(self.prefs)
- if self.verbose:
- level = "TRACE" if self.verbose >= 2 else "DEBUG"
- profile_args["preferences"]["marionette.logging"] = level
- if "-jsdebugger" in self.app_args:
- profile_args["preferences"].update({
- "devtools.browsertoolbox.panel": "jsdebugger",
- "devtools.debugger.remote-enabled": True,
- "devtools.chrome.enabled": True,
- "devtools.debugger.prompt-connection": False,
- "marionette.debugging.clicktostart": True,
- })
- if self.addons:
- profile_args["addons"] = self.addons
-
- if hasattr(self, "profile_path") and self.profile is None:
- if not self.profile_path:
- if self.workspace:
- profile_args["profile"] = tempfile.mkdtemp(
- suffix=".mozrunner-{:.0f}".format(time.time()),
- dir=self.workspace)
- self.profile = Profile(**profile_args)
- else:
- profile_args["path_from"] = self.profile_path
- profile_name = "{}-{:.0f}".format(
- os.path.basename(self.profile_path),
- time.time()
- )
- if self.workspace:
- profile_args["path_to"] = os.path.join(self.workspace,
- profile_name)
- self.profile = Profile.clone(**profile_args)
-
- @classmethod
- def create(cls, app=None, *args, **kwargs):
- try:
- if not app and kwargs["bin"] is not None:
- app_id = mozversion.get_version(binary=kwargs["bin"])["application_id"]
- app = app_ids[app_id]
-
- instance_class = apps[app]
- except (IOError, KeyError):
- exc, val, tb = sys.exc_info()
- msg = 'Application "{0}" unknown (should be one of {1})'
- raise NotImplementedError, msg.format(app, apps.keys()), tb
-
- return instance_class(*args, **kwargs)
-
- def start(self):
- self._update_profile()
- self.runner = self.runner_class(**self._get_runner_args())
- self.runner.start()
-
- def _get_runner_args(self):
- process_args = {
- "processOutputLine": [NullOutput()],
- }
-
- if self.gecko_log == "-":
- process_args["stream"] = sys.stdout
- else:
- process_args["logfile"] = self.gecko_log
-
- env = os.environ.copy()
-
- # environment variables needed for crashreporting
- # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
- env.update({"MOZ_CRASHREPORTER_NO_REPORT": "1",
- "MOZ_CRASHREPORTER_SHUTDOWN": "1",
- })
-
- return {
- "binary": self.binary,
- "profile": self.profile,
- "cmdargs": ["-no-remote", "-marionette"] + self.app_args,
- "env": env,
- "symbols_path": self.symbols_path,
- "process_args": process_args
- }
-
- def close(self, restart=False):
- if not restart:
- self.profile = None
-
- if self.runner:
- self.runner.stop()
- self.runner.cleanup()
-
- def restart(self, prefs=None, clean=True):
- self.close(restart=True)
-
- if clean and self.profile:
- self.profile.cleanup()
- self.profile = None
-
- if prefs:
- self.prefs = prefs
- else:
- self.prefs = None
- self.start()
-
-
-class FennecInstance(GeckoInstance):
- fennec_prefs = {
- # Enable output of dump()
- "browser.dom.window.dump.enabled": True,
-
- # Disable Android snippets
- "browser.snippets.enabled": False,
- "browser.snippets.syncPromo.enabled": False,
- "browser.snippets.firstrunHomepage.enabled": False,
-
- # Disable safebrowsing components
- "browser.safebrowsing.downloads.enabled": False,
-
- # Do not restore the last open set of tabs if the browser has crashed
- "browser.sessionstore.resume_from_crash": False,
-
- # Disable e10s by default
- "browser.tabs.remote.autostart.1": False,
- "browser.tabs.remote.autostart.2": False,
- "browser.tabs.remote.autostart": False,
-
- # Do not allow background tabs to be zombified, otherwise for tests that
- # open additional tabs, the test harness tab itself might get unloaded
- "browser.tabs.disableBackgroundZombification": True,
- }
-
- def __init__(self, emulator_binary=None, avd_home=None, avd=None,
- adb_path=None, serial=None, connect_to_running_emulator=False,
- package_name=None, *args, **kwargs):
- super(FennecInstance, self).__init__(*args, **kwargs)
- self.required_prefs.update(FennecInstance.fennec_prefs)
-
- self.runner_class = FennecEmulatorRunner
- # runner args
- self._package_name = package_name
- self.emulator_binary = emulator_binary
- self.avd_home = avd_home
- self.adb_path = adb_path
- self.avd = avd
- self.serial = serial
- self.connect_to_running_emulator = connect_to_running_emulator
-
- @property
- def package_name(self):
- """
- Name of app to run on emulator.
-
- Note that FennecInstance does not use self.binary
- """
- if self._package_name is None:
- self._package_name = "org.mozilla.fennec"
- user = os.getenv("USER")
- if user:
- self._package_name += "_" + user
- return self._package_name
-
- def start(self):
- self._update_profile()
- self.runner = self.runner_class(**self._get_runner_args())
- try:
- if self.connect_to_running_emulator:
- self.runner.device.connect()
- self.runner.start()
- except Exception as e:
- exc, val, tb = sys.exc_info()
- message = "Error possibly due to runner or device args: {}"
- raise exc, message.format(e.message), tb
- # gecko_log comes from logcat when running with device/emulator
- logcat_args = {
- "filterspec": "Gecko",
- "serial": self.runner.device.dm._deviceSerial
- }
- if self.gecko_log == "-":
- logcat_args["stream"] = sys.stdout
- else:
- logcat_args["logfile"] = self.gecko_log
- self.runner.device.start_logcat(**logcat_args)
-
- # forward marionette port (localhost:2828)
- self.runner.device.dm.forward(
- local="tcp:{}".format(self.marionette_port),
- remote="tcp:{}".format(self.marionette_port))
-
- def _get_runner_args(self):
- process_args = {
- "processOutputLine": [NullOutput()],
- }
-
- runner_args = {
- "app": self.package_name,
- "avd_home": self.avd_home,
- "adb_path": self.adb_path,
- "binary": self.emulator_binary,
- "profile": self.profile,
- "cmdargs": ["-marionette"] + self.app_args,
- "symbols_path": self.symbols_path,
- "process_args": process_args,
- "logdir": self.workspace or os.getcwd(),
- "serial": self.serial,
- }
- if self.avd:
- runner_args["avd"] = self.avd
-
- return runner_args
-
- def close(self, restart=False):
- super(FennecInstance, self).close(restart)
- if self.runner and self.runner.device.connected:
- self.runner.device.dm.remove_forward(
- "tcp:{}".format(self.marionette_port))
-
-
-class DesktopInstance(GeckoInstance):
- desktop_prefs = {
- # Disable application updates
- "app.update.enabled": False,
-
- # Enable output of dump()
- "browser.dom.window.dump.enabled": True,
-
- # Indicate that the download panel has been shown once so that whichever
- # download test runs first doesn"t show the popup inconsistently
- "browser.download.panel.shown": True,
-
- # Do not show the EULA notification which can interfer with tests
- "browser.EULA.override": True,
-
- # Turn off about:newtab and make use of about:blank instead for new opened tabs
- "browser.newtabpage.enabled": False,
- # Assume the about:newtab page"s intro panels have been shown to not depend on
- # which test runs first and happens to open about:newtab
- "browser.newtabpage.introShown": True,
-
- # Background thumbnails in particular cause grief, and disabling thumbnails
- # in general can"t hurt - we re-enable them when tests need them
- "browser.pagethumbnails.capturing_disabled": True,
-
- # Avoid performing Reader Mode intros during tests
- "browser.reader.detectedFirstArticle": True,
-
- # Disable safebrowsing components
- "browser.safebrowsing.blockedURIs.enabled": False,
- "browser.safebrowsing.downloads.enabled": False,
- "browser.safebrowsing.forbiddenURIs.enabled": False,
- "browser.safebrowsing.malware.enabled": False,
- "browser.safebrowsing.phishing.enabled": False,
-
- # Disable updates to search engines
- "browser.search.update": False,
-
- # Do not restore the last open set of tabs if the browser has crashed
- "browser.sessionstore.resume_from_crash": False,
-
- # Don't check for the default web browser during startup
- "browser.shell.checkDefaultBrowser": False,
-
- # Disable e10s by default
- "browser.tabs.remote.autostart.1": False,
- "browser.tabs.remote.autostart.2": False,
- "browser.tabs.remote.autostart": False,
-
- # Needed for branded builds to prevent opening a second tab on startup
- "browser.startup.homepage_override.mstone": "ignore",
- # Start with a blank page by default
- "browser.startup.page": 0,
-
- # Disable tab animation
- "browser.tabs.animate": False,
-
- # Do not warn on exit when multiple tabs are open
- "browser.tabs.warnOnClose": False,
- # Do not warn when closing all other open tabs
- "browser.tabs.warnOnCloseOtherTabs": False,
- # Do not warn when multiple tabs will be opened
- "browser.tabs.warnOnOpen": False,
-
- # Disable the UI tour
- "browser.uitour.enabled": False,
-
- # Disable first-run welcome page
- "startup.homepage_welcome_url": "about:blank",
- "startup.homepage_welcome_url.additional": "",
- }
-
- def __init__(self, *args, **kwargs):
- super(DesktopInstance, self).__init__(*args, **kwargs)
- self.required_prefs.update(DesktopInstance.desktop_prefs)
-
-
-class NullOutput(object):
- def __call__(self, line):
- pass
-
-
-apps = {
- 'fennec': FennecInstance,
- 'fxdesktop': DesktopInstance,
-}
-
-app_ids = {
- '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'fennec',
- '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'fxdesktop',
-}
diff --git a/testing/marionette/client/marionette_driver/gestures.py b/testing/marionette/client/marionette_driver/gestures.py
deleted file mode 100644
index 55b27ec83b..0000000000
--- a/testing/marionette/client/marionette_driver/gestures.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# 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 MultiActions, Actions
-
-
-def smooth_scroll(marionette_session, start_element, axis, direction,
- length, increments=None, wait_period=None, scroll_back=None):
- """
- :param axis: y or x
- :param direction: 0 for positive, and -1 for negative
- :param length: total length of scroll scroll
- :param increments: Amount to be moved per scrolling
- :param wait_period: Seconds to wait between scrolling
- :param scroll_back: Scroll back to original view?
- """
- if axis not in ["x", "y"]:
- raise Exception("Axis must be either 'x' or 'y'")
- if direction not in [-1, 0]:
- raise Exception("Direction must either be -1 negative or 0 positive")
- increments = increments or 100
- wait_period = wait_period or 0.05
- scroll_back = scroll_back or False
- current = 0
- if axis is "x":
- if direction is -1:
- offset = [-increments, 0]
- else:
- offset = [increments, 0]
- else:
- if direction is -1:
- offset = [0, -increments]
- else:
- offset = [0, increments]
- action = Actions(marionette_session)
- action.press(start_element)
- while (current < length):
- current += increments
- action.move_by_offset(*offset).wait(wait_period)
- if scroll_back:
- offset = [-value for value in offset]
- while (current > 0):
- current -= increments
- action.move_by_offset(*offset).wait(wait_period)
- action.release()
- action.perform()
-
-
-def pinch(marionette_session, element, x1, y1, x2, y2, x3, y3, x4, y4, duration=200):
- """
- :param element: target
- :param x1, y1: 1st finger starting position relative to the target
- :param x3, y3: 1st finger ending position relative to the target
- :param x2, y2: 2nd finger starting position relative to the target
- :param x4, y4: 2nd finger ending position relative to the target
- :param duration: Amount of time in milliseconds to complete the pinch.
- """
- time = 0
- time_increment = 10
- if time_increment >= duration:
- time_increment = duration
- move_x1 = time_increment*1.0/duration * (x3 - x1)
- move_y1 = time_increment*1.0/duration * (y3 - y1)
- move_x2 = time_increment*1.0/duration * (x4 - x2)
- move_y2 = time_increment*1.0/duration * (y4 - y2)
- multiAction = MultiActions(marionette_session)
- action1 = Actions(marionette_session)
- action2 = Actions(marionette_session)
- action1.press(element, x1, y1)
- action2.press(element, x2, y2)
- while (time < duration):
- time += time_increment
- action1.move_by_offset(move_x1, move_y1).wait(time_increment/1000)
- action2.move_by_offset(move_x2, move_y2).wait(time_increment/1000)
- action1.release()
- action2.release()
- multiAction.add(action1).add(action2).perform()
-
-
-def long_press_without_contextmenu(marionette_session, element, time_in_seconds, x=None, y=None):
- """
- :param element: The element to press.
- :param time_in_seconds: Time in seconds to wait before releasing the press.
- #x: Optional, x-coordinate to tap, relative to the top-left corner of the element.
- #y: Optional, y-coordinate to tap, relative to the top-leftcorner of the element.
- """
- action = Actions(marionette_session)
- action.press(element, x, y)
- action.move_by_offset(0, 0)
- action.wait(time_in_seconds)
- action.release()
- action.perform()
diff --git a/testing/marionette/client/marionette_driver/keys.py b/testing/marionette/client/marionette_driver/keys.py
deleted file mode 100644
index 2a998c0892..0000000000
--- a/testing/marionette/client/marionette_driver/keys.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# copyright 2008-2009 WebDriver committers
-# Copyright 2008-2009 Google Inc.
-#
-# Licensed under the Apache License Version 2.0 = uthe "License")
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http //www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class Keys(object):
-
- NULL = u'\ue000'
- CANCEL = u'\ue001' # ^break
- HELP = u'\ue002'
- BACK_SPACE = u'\ue003'
- TAB = u'\ue004'
- CLEAR = u'\ue005'
- RETURN = u'\ue006'
- ENTER = u'\ue007'
- SHIFT = u'\ue008'
- LEFT_SHIFT = u'\ue008' # alias
- CONTROL = u'\ue009'
- LEFT_CONTROL = u'\ue009' # alias
- ALT = u'\ue00a'
- LEFT_ALT = u'\ue00a' # alias
- PAUSE = u'\ue00b'
- ESCAPE = u'\ue00c'
- SPACE = u'\ue00d'
- PAGE_UP = u'\ue00e'
- PAGE_DOWN = u'\ue00f'
- END = u'\ue010'
- HOME = u'\ue011'
- LEFT = u'\ue012'
- ARROW_LEFT = u'\ue012' # alias
- UP = u'\ue013'
- ARROW_UP = u'\ue013' # alias
- RIGHT = u'\ue014'
- ARROW_RIGHT = u'\ue014' # alias
- DOWN = u'\ue015'
- ARROW_DOWN = u'\ue015' # alias
- INSERT = u'\ue016'
- DELETE = u'\ue017'
- SEMICOLON = u'\ue018'
- EQUALS = u'\ue019'
-
- NUMPAD0 = u'\ue01a' # numbe pad keys
- NUMPAD1 = u'\ue01b'
- NUMPAD2 = u'\ue01c'
- NUMPAD3 = u'\ue01d'
- NUMPAD4 = u'\ue01e'
- NUMPAD5 = u'\ue01f'
- NUMPAD6 = u'\ue020'
- NUMPAD7 = u'\ue021'
- NUMPAD8 = u'\ue022'
- NUMPAD9 = u'\ue023'
- MULTIPLY = u'\ue024'
- ADD = u'\ue025'
- SEPARATOR = u'\ue026'
- SUBTRACT = u'\ue027'
- DECIMAL = u'\ue028'
- DIVIDE = u'\ue029'
-
- F1 = u'\ue031' # function keys
- F2 = u'\ue032'
- F3 = u'\ue033'
- F4 = u'\ue034'
- F5 = u'\ue035'
- F6 = u'\ue036'
- F7 = u'\ue037'
- F8 = u'\ue038'
- F9 = u'\ue039'
- F10 = u'\ue03a'
- F11 = u'\ue03b'
- F12 = u'\ue03c'
-
- META = u'\ue03d'
- COMMAND = u'\ue03d'
diff --git a/testing/marionette/client/marionette_driver/localization.py b/testing/marionette/client/marionette_driver/localization.py
deleted file mode 100644
index 7b0d91b445..0000000000
--- a/testing/marionette/client/marionette_driver/localization.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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 L10n(object):
- """An API which allows Marionette to handle localized content.
-
- The `localization`_ of UI elements in Gecko based applications is done via
- entities and properties. For static values entities are used, which are located
- in .dtd files. Whereby for dynamically updated content the values come from
- .property files. Both types of elements can be identifed via a unique id,
- and the translated content retrieved.
-
- For example::
-
- from marionette_driver.localization import L10n
- l10n = L10n(marionette)
-
- l10n.localize_entity(["chrome://global/locale/about.dtd"], "about.version")
- l10n.localize_property(["chrome://global/locale/findbar.properties"], "FastFind"))
-
- .. _localization: https://mzl.la/2eUMjyF
- """
-
- def __init__(self, marionette):
- self._marionette = marionette
-
- def localize_entity(self, dtd_urls, entity_id):
- """Retrieve the localized string for the specified entity id.
-
- :param dtd_urls: List of .dtd URLs which will be used to search for the entity.
- :param entity_id: ID of the entity to retrieve the localized string for.
-
- :returns: The localized string for the requested entity.
- :raises: :exc:`NoSuchElementException`
- """
- body = {"urls": dtd_urls, "id": entity_id}
- return self._marionette._send_message("localization:l10n:localizeEntity",
- body, key="value")
-
- def localize_property(self, properties_urls, property_id):
- """Retrieve the localized string for the specified property id.
-
- :param properties_urls: List of .properties URLs which will be used to
- search for the property.
- :param property_id: ID of the property to retrieve the localized string for.
-
- :returns: The localized string for the requested property.
- :raises: :exc:`NoSuchElementException`
- """
- body = {"urls": properties_urls, "id": property_id}
- return self._marionette._send_message("localization:l10n:localizeProperty",
- body, key="value")
diff --git a/testing/marionette/client/marionette_driver/marionette.py b/testing/marionette/client/marionette_driver/marionette.py
deleted file mode 100644
index 7450d1fbb1..0000000000
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ /dev/null
@@ -1,2153 +0,0 @@
-# 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 base64
-import datetime
-import json
-import os
-import socket
-import sys
-import time
-import traceback
-import warnings
-
-from contextlib import contextmanager
-
-import errors
-import transport
-
-from .decorators import do_process_check
-from .geckoinstance import GeckoInstance
-from .keys import Keys
-from .timeout import Timeouts
-
-WEBELEMENT_KEY = "ELEMENT"
-W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
-
-
-class HTMLElement(object):
- """Represents a DOM Element."""
-
- def __init__(self, marionette, id):
- self.marionette = marionette
- assert(id is not None)
- self.id = id
-
- def __str__(self):
- return self.id
-
- def __eq__(self, other_element):
- return self.id == other_element.id
-
- def find_element(self, method, target):
- """Returns an ``HTMLElement`` instance that matches the specified
- method and target, relative to the current element.
-
- For more details on this function, see the `find_element` method
- in the Marionette class.
- """
- return self.marionette.find_element(method, target, self.id)
-
- def find_elements(self, method, target):
- """Returns a list of all ``HTMLElement`` instances that match the
- specified method and target in the current context.
-
- For more details on this function, see the find_elements method
- in the Marionette class.
- """
- return self.marionette.find_elements(method, target, self.id)
-
- def get_attribute(self, name):
- """Returns the requested attribute, or None if no attribute
- is set.
- """
- body = {"id": self.id, "name": name}
- return self.marionette._send_message("getElementAttribute", body, key="value")
-
- def get_property(self, name):
- """Returns the requested property, or None if the property is
- not set.
- """
- try:
- body = {"id": self.id, "name": name}
- return self.marionette._send_message("getElementProperty", body, key="value")
- except errors.UnknownCommandException:
- # Keep backward compatibility for code which uses get_attribute() to
- # also retrieve element properties.
- # Remove when Firefox 55 is stable.
- return self.get_attribute(name)
-
- def click(self):
- self.marionette._send_message("clickElement", {"id": self.id})
-
- def tap(self, x=None, y=None):
- """Simulates a set of tap events on the element.
-
- :param x: X coordinate of tap event. If not given, default to
- the centre of the element.
- :param y: Y coordinate of tap event. If not given, default to
- the centre of the element.
- """
- body = {"id": self.id, "x": x, "y": y}
- self.marionette._send_message("singleTap", body)
-
- @property
- def text(self):
- """Returns the visible text of the element, and its child elements."""
- body = {"id": self.id}
- return self.marionette._send_message("getElementText", body, key="value")
-
- def send_keys(self, *string):
- """Sends the string via synthesized keypresses to the element."""
- keys = Marionette.convert_keys(*string)
- body = {"id": self.id, "value": keys}
- self.marionette._send_message("sendKeysToElement", body)
-
- def clear(self):
- """Clears the input of the element."""
- self.marionette._send_message("clearElement", {"id": self.id})
-
- def is_selected(self):
- """Returns True if the element is selected."""
- body = {"id": self.id}
- return self.marionette._send_message("isElementSelected", body, key="value")
-
- def is_enabled(self):
- """This command will return False if all the following criteria
- are met otherwise return True:
-
- * A form control is disabled.
- * A ``HTMLElement`` has a disabled boolean attribute.
- """
- body = {"id": self.id}
- return self.marionette._send_message("isElementEnabled", body, key="value")
-
- def is_displayed(self):
- """Returns True if the element is displayed, False otherwise."""
- body = {"id": self.id}
- return self.marionette._send_message("isElementDisplayed", body, key="value")
-
- @property
- def size(self):
- """A dictionary with the size of the element."""
- warnings.warn("The size property has been deprecated and will be removed in a future version. \
- Please use HTMLElement#rect", DeprecationWarning)
- rect = self.rect
- return {"width": rect["width"], "height": rect["height"]}
-
- @property
- def tag_name(self):
- """The tag name of the element."""
- body = {"id": self.id}
- return self.marionette._send_message("getElementTagName", body, key="value")
-
- @property
- def location(self):
- """Get an element's location on the page.
-
- The returned point will contain the x and y coordinates of the
- top left-hand corner of the given element. The point (0,0)
- refers to the upper-left corner of the document.
-
- :returns: a dictionary containing x and y as entries
- """
- warnings.warn("The location property has been deprecated and will be removed in a future version. \
- Please use HTMLElement#rect", DeprecationWarning)
- rect = self.rect
- return {"x": rect["x"], "y": rect["y"]}
-
- @property
- def rect(self):
- """Gets the element's bounding rectangle.
-
- This will return a dictionary with the following:
-
- * x and y represent the top left coordinates of the ``HTMLElement``
- relative to top left corner of the document.
- * height and the width will contain the height and the width
- of the DOMRect of the ``HTMLElement``.
- """
- body = {"id": self.id}
- return self.marionette._send_message(
- "getElementRect", body, key="value" if self.marionette.protocol == 1 else None)
-
- def value_of_css_property(self, property_name):
- """Gets the value of the specified CSS property name.
-
- :param property_name: Property name to get the value of.
- """
- body = {"id": self.id, "propertyName": property_name}
- return self.marionette._send_message(
- "getElementValueOfCssProperty", body, key="value")
-
-
-class MouseButton(object):
- """Enum-like class for mouse button constants."""
- LEFT = 0
- MIDDLE = 1
- RIGHT = 2
-
-
-class Actions(object):
- '''
- An Action object represents a set of actions that are executed in a particular order.
-
- All action methods (press, etc.) return the Actions object itself, to make
- it easy to create a chain of events.
-
- Example usage:
-
- ::
-
- # get html file
- testAction = marionette.absolute_url("testFool.html")
- # navigate to the file
- marionette.navigate(testAction)
- # find element1 and element2
- element1 = marionette.find_element(By.ID, "element1")
- element2 = marionette.find_element(By.ID, "element2")
- # create action object
- action = Actions(marionette)
- # add actions (press, wait, move, release) into the object
- action.press(element1).wait(5). move(element2).release()
- # fire all the added events
- action.perform()
- '''
-
- def __init__(self, marionette):
- self.action_chain = []
- self.marionette = marionette
- self.current_id = None
-
- def press(self, element, x=None, y=None):
- '''
- Sends a 'touchstart' event to this element.
-
- If no coordinates are given, it will be targeted at the center of the
- element. If given, it will be targeted at the (x,y) coordinates
- relative to the top-left corner of the element.
-
- :param element: The element to press on.
- :param x: Optional, x-coordinate to tap, relative to the top-left
- corner of the element.
- :param y: Optional, y-coordinate to tap, relative to the top-left
- corner of the element.
- '''
- element = element.id
- self.action_chain.append(['press', element, x, y])
- return self
-
- def release(self):
- '''
- Sends a 'touchend' event to this element.
-
- May only be called if press() has already be called on this element.
-
- If press and release are chained without a move action between them,
- then it will be processed as a 'tap' event, and will dispatch the
- expected mouse events ('mousemove' (if necessary), 'mousedown',
- 'mouseup', 'mouseclick') after the touch events. If there is a wait
- period between press and release that will trigger a contextmenu,
- then the 'contextmenu' menu event will be fired instead of the
- touch/mouse events.
- '''
- self.action_chain.append(['release'])
- return self
-
- def move(self, element):
- '''
- Sends a 'touchmove' event at the center of the target element.
-
- :param element: Element to move towards.
-
- May only be called if press() has already be called.
- '''
- element = element.id
- self.action_chain.append(['move', element])
- return self
-
- def move_by_offset(self, x, y):
- '''
- Sends 'touchmove' event to the given x, y coordinates relative to the
- top-left of the currently touched element.
-
- May only be called if press() has already be called.
-
- :param x: Specifies x-coordinate of move event, relative to the
- top-left corner of the element.
- :param y: Specifies y-coordinate of move event, relative to the
- top-left corner of the element.
- '''
- self.action_chain.append(['moveByOffset', x, y])
- return self
-
- def wait(self, time=None):
- '''
- Waits for specified time period.
-
- :param time: Time in seconds to wait. If time is None then this has no effect
- for a single action chain. If used inside a multi-action chain,
- then time being None indicates that we should wait for all other
- currently executing actions that are part of the chain to complete.
- '''
- self.action_chain.append(['wait', time])
- return self
-
- def cancel(self):
- '''
- Sends 'touchcancel' event to the target of the original 'touchstart' event.
-
- May only be called if press() has already be called.
- '''
- self.action_chain.append(['cancel'])
- return self
-
- def tap(self, element, x=None, y=None):
- '''
- Performs a quick tap on the target element.
-
- :param element: The element to tap.
- :param x: Optional, x-coordinate of tap, relative to the top-left
- corner of the element. If not specified, default to center of
- element.
- :param y: Optional, y-coordinate of tap, relative to the top-left
- corner of the element. If not specified, default to center of
- element.
-
- This is equivalent to calling:
-
- ::
-
- action.press(element, x, y).release()
- '''
- element = element.id
- self.action_chain.append(['press', element, x, y])
- self.action_chain.append(['release'])
- return self
-
- def double_tap(self, element, x=None, y=None):
- '''
- Performs a double tap on the target element.
-
- :param element: The element to double tap.
- :param x: Optional, x-coordinate of double tap, relative to the
- top-left corner of the element.
- :param y: Optional, y-coordinate of double tap, relative to the
- top-left corner of the element.
- '''
- element = element.id
- self.action_chain.append(['press', element, x, y])
- self.action_chain.append(['release'])
- self.action_chain.append(['press', element, x, y])
- self.action_chain.append(['release'])
- return self
-
- def click(self, element, button=MouseButton.LEFT, count=1):
- '''
- Performs a click with additional parameters to allow for double clicking,
- right click, middle click, etc.
-
- :param element: The element to click.
- :param button: The mouse button to click (indexed from 0, left to right).
- :param count: Optional, the count of clicks to synthesize (for double
- click events).
- '''
- el = element.id
- self.action_chain.append(['click', el, button, count])
- return self
-
- def context_click(self, element):
- '''
- Performs a context click on the specified element.
-
- :param element: The element to context click.
- '''
- return self.click(element, button=MouseButton.RIGHT)
-
- def middle_click(self, element):
- '''
- Performs a middle click on the specified element.
-
- :param element: The element to middle click.
- '''
- return self.click(element, button=MouseButton.MIDDLE)
-
- def double_click(self, element):
- '''
- Performs a double click on the specified element.
-
- :param element: The element to double click.
- '''
- return self.click(element, count=2)
-
- def flick(self, element, x1, y1, x2, y2, duration=200):
- '''
- Performs a flick gesture on the target element.
-
- :param element: The element to perform the flick gesture on.
- :param x1: Starting x-coordinate of flick, relative to the top left
- corner of the element.
- :param y1: Starting y-coordinate of flick, relative to the top left
- corner of the element.
- :param x2: Ending x-coordinate of flick, relative to the top left
- corner of the element.
- :param y2: Ending y-coordinate of flick, relative to the top left
- corner of the element.
- :param duration: Time needed for the flick gesture for complete (in
- milliseconds).
- '''
- element = element.id
- elapsed = 0
- time_increment = 10
- if time_increment >= duration:
- time_increment = duration
- move_x = time_increment*1.0/duration * (x2 - x1)
- move_y = time_increment*1.0/duration * (y2 - y1)
- self.action_chain.append(['press', element, x1, y1])
- while elapsed < duration:
- elapsed += time_increment
- self.action_chain.append(['moveByOffset', move_x, move_y])
- self.action_chain.append(['wait', time_increment/1000])
- self.action_chain.append(['release'])
- return self
-
- def long_press(self, element, time_in_seconds, x=None, y=None):
- '''
- Performs a long press gesture on the target element.
-
- :param element: The element to press.
- :param time_in_seconds: Time in seconds to wait before releasing the press.
- :param x: Optional, x-coordinate to tap, relative to the top-left
- corner of the element.
- :param y: Optional, y-coordinate to tap, relative to the top-left
- corner of the element.
-
- This is equivalent to calling:
-
- ::
-
- action.press(element, x, y).wait(time_in_seconds).release()
-
- '''
- element = element.id
- self.action_chain.append(['press', element, x, y])
- self.action_chain.append(['wait', time_in_seconds])
- self.action_chain.append(['release'])
- return self
-
- def key_down(self, key_code):
- """
- Perform a "keyDown" action for the given key code. Modifier keys are
- respected by the server for the course of an action chain.
-
- :param key_code: The key to press as a result of this action.
- """
- self.action_chain.append(['keyDown', key_code])
- return self
-
- def key_up(self, key_code):
- """
- Perform a "keyUp" action for the given key code. Modifier keys are
- respected by the server for the course of an action chain.
- :param key_up: The key to release as a result of this action.
- """
- self.action_chain.append(['keyUp', key_code])
- return self
-
- def perform(self):
- """Sends the action chain built so far to the server side for
- execution and clears the current chain of actions."""
- body = {"chain": self.action_chain, "nextId": self.current_id}
- self.current_id = self.marionette._send_message("actionChain", body, key="value")
- self.action_chain = []
- return self
-
-
-class MultiActions(object):
- '''
- A MultiActions object represents a sequence of actions that may be
- performed at the same time. Its intent is to allow the simulation
- of multi-touch gestures.
- Usage example:
-
- ::
-
- # create multiaction object
- multitouch = MultiActions(marionette)
- # create several action objects
- action_1 = Actions(marionette)
- action_2 = Actions(marionette)
- # add actions to each action object/finger
- action_1.press(element1).move_to(element2).release()
- action_2.press(element3).wait().release(element3)
- # fire all the added events
- multitouch.add(action_1).add(action_2).perform()
- '''
-
- def __init__(self, marionette):
- self.multi_actions = []
- self.max_length = 0
- self.marionette = marionette
-
- def add(self, action):
- '''
- Adds a set of actions to perform.
-
- :param action: An Actions object.
- '''
- self.multi_actions.append(action.action_chain)
- if len(action.action_chain) > self.max_length:
- self.max_length = len(action.action_chain)
- return self
-
- def perform(self):
- """Perform all the actions added to this object."""
- body = {"value": self.multi_actions, "max_length": self.max_length}
- self.marionette._send_message("multiAction", body)
-
-
-class Alert(object):
- """A class for interacting with alerts.
-
- ::
-
- Alert(marionette).accept()
- Alert(merionette).dismiss()
- """
-
- def __init__(self, marionette):
- self.marionette = marionette
-
- def accept(self):
- """Accept a currently displayed modal dialog."""
- self.marionette._send_message("acceptDialog")
-
- def dismiss(self):
- """Dismiss a currently displayed modal dialog."""
- self.marionette._send_message("dismissDialog")
-
- @property
- def text(self):
- """Return the currently displayed text in a tab modal."""
- return self.marionette._send_message("getTextFromDialog", key="value")
-
- def send_keys(self, *string):
- """Send keys to the currently displayed text input area in an open
- tab modal dialog."""
- body = {"value": Marionette.convert_keys(*string)}
- self.marionette._send_message("sendKeysToDialog", body)
-
-
-class Marionette(object):
- """Represents a Marionette connection to a browser or device."""
-
- CONTEXT_CHROME = "chrome" # non-browser content: windows, dialogs, etc.
- CONTEXT_CONTENT = "content" # browser content: iframes, divs, etc.
- DEFAULT_STARTUP_TIMEOUT = 120
- DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
-
- # Bug 1336953 - Until we can remove the socket timeout parameter it has to be
- # set a default value which is larger than the longest timeout as defined by the
- # WebDriver spec. In that case its 300s for page load. Also add another minute
- # so that slow builds have enough time to send the timeout error to the client.
- DEFAULT_SOCKET_TIMEOUT = 360
-
- def __init__(self, host="localhost", port=2828, app=None, bin=None,
- baseurl=None, socket_timeout=DEFAULT_SOCKET_TIMEOUT,
- startup_timeout=None, **instance_args):
- """Construct a holder for the Marionette connection.
-
- Remember to call ``start_session`` in order to initiate the
- connection and start a Marionette session.
-
- :param host: Host where the Marionette server listens.
- Defaults to localhost.
- :param port: Port where the Marionette server listens.
- Defaults to port 2828.
- :param baseurl: Where to look for files served from Marionette's
- www directory.
- :param socket_timeout: Timeout for Marionette socket operations.
- :param startup_timeout: Seconds to wait for a connection with
- binary.
- :param bin: Path to browser binary. If any truthy value is given
- this will attempt to start a Gecko instance with the specified
- `app`.
- :param app: Type of ``instance_class`` to use for managing app
- instance. See ``marionette_driver.geckoinstance``.
- :param instance_args: Arguments to pass to ``instance_class``.
-
- """
- self.host = host
- self.port = self.local_port = int(port)
- self.bin = bin
- self.client = None
- self.instance = None
- self.session = None
- self.session_id = None
- self.process_id = None
- self.profile = None
- self.window = None
- self.chrome_window = None
- self.baseurl = baseurl
- self._test_name = None
- self.socket_timeout = socket_timeout
- self.crashed = 0
-
- self.startup_timeout = int(startup_timeout or self.DEFAULT_STARTUP_TIMEOUT)
- if self.bin:
- if not Marionette.is_port_available(self.port, host=self.host):
- ex_msg = "{0}:{1} is unavailable.".format(self.host, self.port)
- raise errors.MarionetteException(message=ex_msg)
-
- self.instance = GeckoInstance.create(
- app, host=self.host, port=self.port, bin=self.bin, **instance_args)
- self.instance.start()
- self.raise_for_port(timeout=self.startup_timeout)
-
- self.timeout = Timeouts(self)
-
- @property
- def profile_path(self):
- if self.instance and self.instance.profile:
- return self.instance.profile.profile
-
- def cleanup(self):
- if self.session:
- try:
- self.delete_session()
- except (errors.MarionetteException, IOError):
- # These exceptions get thrown if the Marionette server
- # hit an exception/died or the connection died. We can
- # do no further server-side cleanup in this case.
- pass
- if self.instance:
- self.instance.close()
-
- def __del__(self):
- self.cleanup()
-
- @staticmethod
- def is_port_available(port, host=''):
- port = int(port)
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- try:
- s.bind((host, port))
- return True
- except socket.error:
- return False
- finally:
- s.close()
-
- def wait_for_port(self, timeout=None):
- """Wait until Marionette server has been created the communication socket.
-
- :param timeout: Timeout in seconds for the server to be ready.
-
- """
- if timeout is None:
- timeout = self.DEFAULT_STARTUP_TIMEOUT
-
- runner = None
- if self.instance is not None:
- runner = self.instance.runner
-
- poll_interval = 0.1
- starttime = datetime.datetime.now()
-
- while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
- # If the instance we want to connect to is not running return immediately
- if runner is not None and not runner.is_running():
- return False
-
- sock = None
- try:
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.settimeout(0.5)
- sock.connect((self.host, self.port))
- data = sock.recv(16)
- if ":" in data:
- return True
- except socket.error:
- pass
- finally:
- if sock is not None:
- sock.close()
-
- time.sleep(poll_interval)
-
- return False
-
- @do_process_check
- def raise_for_port(self, timeout=None):
- """Raise socket.timeout if no connection can be established.
-
- :param timeout: Timeout in seconds for the server to be ready.
-
- """
- if not self.wait_for_port(timeout):
- raise socket.timeout("Timed out waiting for connection on {0}:{1}!".format(
- self.host, self.port))
-
- @do_process_check
- def _send_message(self, name, params=None, key=None):
- """Send a blocking message to the server.
-
- Marionette provides an asynchronous, non-blocking interface and
- this attempts to paper over this by providing a synchronous API
- to the user.
-
- :param name: Requested command key.
- :param params: Optional dictionary of key/value arguments.
- :param key: Optional key to extract from response.
-
- :returns: Full response from the server, or if `key` is given,
- the value of said key in the response.
- """
-
- if not self.session_id and name != "newSession":
- raise errors.MarionetteException("Please start a session")
-
- try:
- if self.protocol < 3:
- data = {"name": name}
- if params:
- data["parameters"] = params
- self.client.send(data)
- msg = self.client.receive()
-
- else:
- msg = self.client.request(name, params)
-
- except IOError:
- self.delete_session(send_request=False)
- raise
-
- res, err = msg.result, msg.error
- if err:
- self._handle_error(err)
-
- if key is not None:
- return self._unwrap_response(res.get(key))
- else:
- return self._unwrap_response(res)
-
- def _unwrap_response(self, value):
- if isinstance(value, dict) and (WEBELEMENT_KEY in value or
- W3C_WEBELEMENT_KEY in value):
- if value.get(WEBELEMENT_KEY):
- return HTMLElement(self, value.get(WEBELEMENT_KEY))
- else:
- return HTMLElement(self, value.get(W3C_WEBELEMENT_KEY))
- elif isinstance(value, list):
- return list(self._unwrap_response(item) for item in value)
- else:
- return value
-
- def _handle_error(self, obj):
- if self.protocol == 1:
- if "error" not in obj or not isinstance(obj["error"], dict):
- raise errors.MarionetteException(
- "Malformed packet, expected key 'error' to be a dict: {}".format(obj))
- error = obj["error"].get("status")
- message = obj["error"].get("message")
- stacktrace = obj["error"].get("stacktrace")
-
- else:
- error = obj["error"]
- message = obj["message"]
- stacktrace = obj["stacktrace"]
-
- raise errors.lookup(error)(message, stacktrace=stacktrace)
-
- def check_for_crash(self):
- """Check if the process crashed.
-
- :returns: True, if a crash happened since the method has been called the last time.
- """
- crash_count = 0
-
- if self.instance:
- name = self.test_name or 'marionette.py'
- crash_count = self.instance.runner.check_for_crashes(test_name=name)
- self.crashed = self.crashed + crash_count
-
- return crash_count > 0
-
- def _handle_socket_failure(self):
- """Handle socket failures for the currently connected application.
-
- If the application crashed then clean-up internal states, or in case of a content
- crash also kill the process. If there are other reasons for a socket failure,
- wait for the process to shutdown itself, or force kill it.
-
- Please note that the method expects an exception to be handled on the current stack
- frame, and is only called via the `@do_process_check` decorator.
-
- """
- exc, val, tb = sys.exc_info()
-
- # If the application hasn't been launched by Marionette no further action can be done.
- # In such cases we simply re-throw the exception.
- if not self.instance:
- raise exc, val, tb
-
- else:
- # Somehow the socket disconnected. Give the application some time to shutdown
- # itself before killing the process.
- returncode = self.instance.runner.wait(timeout=self.DEFAULT_SHUTDOWN_TIMEOUT)
-
- if returncode is None:
- message = ('Process killed because the connection to Marionette server is '
- 'lost. Check gecko.log for errors')
- # This will force-close the application without sending any other message.
- self.cleanup()
- else:
- # If Firefox quit itself check if there was a crash
- crash_count = self.check_for_crash()
-
- if crash_count > 0:
- if returncode == 0:
- message = 'Content process crashed'
- else:
- message = 'Process crashed (Exit code: {returncode})'
- else:
- message = 'Process has been unexpectedly closed (Exit code: {returncode})'
-
- self.delete_session(send_request=False, reset_session_id=True)
-
- message += ' (Reason: {reason})'
-
- raise IOError, message.format(returncode=returncode, reason=val), tb
-
- @staticmethod
- def convert_keys(*string):
- typing = []
- for val in string:
- if isinstance(val, Keys):
- typing.append(val)
- elif isinstance(val, int):
- val = str(val)
- for i in range(len(val)):
- typing.append(val[i])
- else:
- for i in range(len(val)):
- typing.append(val[i])
- return typing
-
- def get_permission(self, perm):
- script = """
- let value = {
- 'url': document.nodePrincipal.URI.spec,
- 'appId': document.nodePrincipal.appId,
- 'isInIsolatedMozBrowserElement': document.nodePrincipal.isInIsolatedMozBrowserElement,
- 'type': arguments[0]
- };
- return value;"""
- with self.using_context("content"):
- value = self.execute_script(script, script_args=(perm,), sandbox="system")
-
- with self.using_context("chrome"):
- permission = self.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let perm = arguments[0];
- let secMan = Services.scriptSecurityManager;
- let attrs = {appId: perm.appId,
- inIsolatedMozBrowser: perm.isInIsolatedMozBrowserElement};
- let principal = secMan.createCodebasePrincipal(
- Services.io.newURI(perm.url, null, null),
- attrs);
- let testPerm = Services.perms.testPermissionFromPrincipal(
- principal, perm.type);
- return testPerm;
- """, script_args=(value,))
- return permission
-
- def push_permission(self, perm, allow):
- script = """
- let allow = arguments[0];
- if (typeof(allow) == "boolean") {
- if (allow) {
- allow = Components.interfaces.nsIPermissionManager.ALLOW_ACTION;
- }
- else {
- allow = Components.interfaces.nsIPermissionManager.DENY_ACTION;
- }
- }
- let perm_type = arguments[1];
-
- Components.utils.import("resource://gre/modules/Services.jsm");
- window.wrappedJSObject.permChanged = false;
- window.wrappedJSObject.permObserver = function(subject, topic, data) {
- if (topic == "perm-changed") {
- let permission = subject.QueryInterface(Components.interfaces.nsIPermission);
- if (perm_type == permission.type) {
- Services.obs.removeObserver(window.wrappedJSObject.permObserver,
- "perm-changed");
- window.wrappedJSObject.permChanged = true;
- }
- }
- };
- Services.obs.addObserver(window.wrappedJSObject.permObserver,
- "perm-changed", false);
-
- let value = {
- 'url': document.nodePrincipal.URI.spec,
- 'appId': document.nodePrincipal.appId,
- 'isInIsolatedMozBrowserElement': document.nodePrincipal.isInIsolatedMozBrowserElement,
- 'type': perm_type,
- 'action': allow
- };
- return value;
- """
- with self.using_context("content"):
- perm = self.execute_script(script, script_args=(allow, perm,), sandbox="system")
-
- current_perm = self.get_permission(perm["type"])
- if current_perm == perm["action"]:
- with self.using_context("content"):
- self.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- Services.obs.removeObserver(window.wrappedJSObject.permObserver,
- "perm-changed");
- """, sandbox="system")
- return
-
- with self.using_context("chrome"):
- self.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let perm = arguments[0];
- let secMan = Services.scriptSecurityManager;
- let attrs = {appId: perm.appId,
- inIsolatedMozBrowser: perm.isInIsolatedMozBrowserElement};
- let principal = secMan.createCodebasePrincipal(Services.io.newURI(perm.url,
- null, null),
- attrs);
- Services.perms.addFromPrincipal(principal, perm.type, perm.action);
- return true;
- """, script_args=(perm,))
-
- with self.using_context("content"):
- self.execute_async_script("""
- let wait = function() {
- if (window.wrappedJSObject.permChanged) {
- marionetteScriptFinished();
- } else {
- window.setTimeout(wait, 100);
- }
- }();
- """, sandbox="system")
-
- @contextmanager
- def using_permissions(self, perms):
- '''
- Sets permissions for code being executed in a `with` block,
- and restores them on exit.
-
- :param perms: A dict containing one or more perms and their
- values to be set.
-
- Usage example::
-
- with marionette.using_permissions({'systemXHR': True}):
- ... do stuff ...
- '''
- original_perms = {}
- for perm in perms:
- original_perms[perm] = self.get_permission(perm)
- self.push_permission(perm, perms[perm])
-
- try:
- yield
- finally:
- for perm in original_perms:
- self.push_permission(perm, original_perms[perm])
-
- def clear_pref(self, pref):
- """Clear the user-defined value from the specified preference.
-
- :param pref: Name of the preference.
- """
- with self.using_context(self.CONTEXT_CHROME):
- self.execute_script("""
- Components.utils.import("resource://gre/modules/Preferences.jsm");
- Preferences.reset(arguments[0]);
- """, script_args=(pref,))
-
- def get_pref(self, pref, default_branch=False, value_type="nsISupportsString"):
- """Get the value of the specified preference.
-
- :param pref: Name of the preference.
- :param default_branch: Optional, if `True` the preference value will be read
- from the default branch. Otherwise the user-defined
- value if set is returned. Defaults to `False`.
- :param value_type: Optional, XPCOM interface of the pref's complex value.
- Defaults to `nsISupportsString`. Other possible values are:
- `nsILocalFile`, and `nsIPrefLocalizedString`.
-
- Usage example::
- marionette.get_pref("browser.tabs.warnOnClose")
-
- """
- with self.using_context(self.CONTEXT_CHROME):
- pref_value = self.execute_script("""
- Components.utils.import("resource://gre/modules/Preferences.jsm");
-
- let pref = arguments[0];
- let defaultBranch = arguments[1];
- let valueType = arguments[2];
-
- prefs = new Preferences({defaultBranch: defaultBranch});
- return prefs.get(pref, null, Components.interfaces[valueType]);
- """, script_args=(pref, default_branch, value_type))
- return pref_value
-
- def set_pref(self, pref, value, default_branch=False):
- """Set the value of the specified preference.
-
- :param pref: Name of the preference.
- :param value: The value to set the preference to. If the value is None,
- reset the preference to its default value. If no default
- value exists, the preference will cease to exist.
- :param default_branch: Optional, if `True` the preference value will
- be written to the default branch, and will remain until
- the application gets restarted. Otherwise a user-defined
- value is set. Defaults to `False`.
-
- Usage example::
- marionette.set_pref("browser.tabs.warnOnClose", True)
-
- """
- with self.using_context(self.CONTEXT_CHROME):
- if value is None:
- self.clear_pref(pref)
- return
-
- self.execute_script("""
- Components.utils.import("resource://gre/modules/Preferences.jsm");
-
- let pref = arguments[0];
- let value = arguments[1];
- let defaultBranch = arguments[2];
-
- prefs = new Preferences({defaultBranch: defaultBranch});
- prefs.set(pref, value);
- """, script_args=(pref, value, default_branch))
-
- def set_prefs(self, prefs, default_branch=False):
- """Set the value of a list of preferences.
-
- :param prefs: A dict containing one or more preferences and their values
- to be set. See `set_pref` for further details.
- :param default_branch: Optional, if `True` the preference value will
- be written to the default branch, and will remain until
- the application gets restarted. Otherwise a user-defined
- value is set. Defaults to `False`.
-
- Usage example::
-
- marionette.set_prefs({"browser.tabs.warnOnClose": True})
-
- """
- for pref, value in prefs.items():
- self.set_pref(pref, value, default_branch=default_branch)
-
- @contextmanager
- def using_prefs(self, prefs, default_branch=False):
- """Set preferences for code executed in a `with` block, and restores them on exit.
-
- :param prefs: A dict containing one or more preferences and their values
- to be set. See `set_prefs` for further details.
- :param default_branch: Optional, if `True` the preference value will
- be written to the default branch, and will remain until
- the application gets restarted. Otherwise a user-defined
- value is set. Defaults to `False`.
-
- Usage example::
-
- with marionette.using_prefs({"browser.tabs.warnOnClose": True}):
- # ... do stuff ...
-
- """
- original_prefs = {p: self.get_pref(p) for p in prefs}
- self.set_prefs(prefs, default_branch=default_branch)
-
- try:
- yield
- finally:
- self.set_prefs(original_prefs, default_branch=default_branch)
-
- @do_process_check
- def enforce_gecko_prefs(self, prefs):
- """Checks if the running instance has the given prefs. If not,
- it will kill the currently running instance, and spawn a new
- instance with the requested preferences.
-
- : param prefs: A dictionary whose keys are preference names.
- """
- if not self.instance:
- raise errors.MarionetteException("enforce_gecko_prefs() can only be called "
- "on Gecko instances launched by Marionette")
- pref_exists = True
- with self.using_context(self.CONTEXT_CHROME):
- for pref, value in prefs.iteritems():
- if type(value) is not str:
- value = json.dumps(value)
- pref_exists = self.execute_script("""
- let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
- let pref = '{0}';
- let value = '{1}';
- let type = prefInterface.getPrefType(pref);
- switch(type) {{
- case prefInterface.PREF_STRING:
- return value == prefInterface.getCharPref(pref).toString();
- case prefInterface.PREF_BOOL:
- return value == prefInterface.getBoolPref(pref).toString();
- case prefInterface.PREF_INT:
- return value == prefInterface.getIntPref(pref).toString();
- case prefInterface.PREF_INVALID:
- return false;
- }}
- """.format(pref, value))
- if not pref_exists:
- break
-
- if not pref_exists:
- context = self._send_message("getContext", key="value")
- self.delete_session()
- self.instance.restart(prefs)
- self.raise_for_port()
- self.start_session()
-
- # Restore the context as used before the restart
- self.set_context(context)
-
- def _request_in_app_shutdown(self, shutdown_flags=None):
- """Terminate the currently running instance from inside the application.
-
- :param shutdown_flags: If specified use additional flags for the shutdown
- of the application. Possible values here correspond
- to constants in nsIAppStartup: http://mzl.la/1X0JZsC.
- """
- flags = set([])
- if shutdown_flags:
- flags.add(shutdown_flags)
-
- # Trigger a 'quit-application-requested' observer notification so that
- # components can safely shutdown before quitting the application.
- with self.using_context("chrome"):
- canceled = self.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
- createInstance(Components.interfaces.nsISupportsPRBool);
- Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
- return cancelQuit.data;
- """)
- if canceled:
- raise errors.MarionetteException("Something canceled the quit application request")
-
- self._send_message("quitApplication", {"flags": list(flags)})
-
- @do_process_check
- def quit(self, in_app=False, callback=None):
- """Terminate the currently running instance.
-
- This command will delete the active marionette session. It also allows
- manipulation of eg. the profile data while the application is not running.
- To start the application again, start_session() has to be called.
-
- :param in_app: If True, marionette will cause a quit from within the
- browser. Otherwise the browser will be quit immediately
- by killing the process.
- :param callback: If provided and `in_app` is True, the callback will
- be used to trigger the shutdown.
- """
- if not self.instance:
- raise errors.MarionetteException("quit() can only be called "
- "on Gecko instances launched by Marionette")
-
- if in_app:
- if callable(callback):
- self._send_message("acceptConnections", {"value": False})
- callback()
- else:
- self._request_in_app_shutdown()
-
- # Ensure to explicitely mark the session as deleted
- self.delete_session(send_request=False, reset_session_id=True)
-
- # Give the application some time to shutdown
- self.instance.runner.wait(timeout=self.DEFAULT_SHUTDOWN_TIMEOUT)
- else:
- self.delete_session(reset_session_id=True)
- self.instance.close()
-
- @do_process_check
- def restart(self, clean=False, in_app=False, callback=None):
- """
- This will terminate the currently running instance, and spawn a new instance
- with the same profile and then reuse the session id when creating a session again.
-
- :param clean: If False the same profile will be used after the restart. Note
- that the in app initiated restart always maintains the same
- profile.
- :param in_app: If True, marionette will cause a restart from within the
- browser. Otherwise the browser will be restarted immediately
- by killing the process.
- :param callback: If provided and `in_app` is True, the callback will be
- used to trigger the restart.
- """
- if not self.instance:
- raise errors.MarionetteException("restart() can only be called "
- "on Gecko instances launched by Marionette")
-
- context = self._send_message("getContext", key="value")
- session_id = self.session_id
-
- if in_app:
- if clean:
- raise ValueError("An in_app restart cannot be triggered with the clean flag set")
-
- if callable(callback):
- self._send_message("acceptConnections", {"value": False})
- callback()
- else:
- self._request_in_app_shutdown("eRestart")
-
- # Ensure to explicitely mark the session as deleted
- self.delete_session(send_request=False, reset_session_id=True)
-
- try:
- self.raise_for_port()
- except socket.timeout:
- if self.instance.runner.returncode is not None:
- exc, val, tb = sys.exc_info()
- self.cleanup()
- raise exc, "Requested restart of the application was aborted", tb
-
- else:
- self.delete_session()
- self.instance.restart(clean=clean)
- self.raise_for_port()
-
- self.start_session(session_id=session_id)
-
- # Restore the context as used before the restart
- self.set_context(context)
-
- if in_app and self.process_id:
- # In some cases Firefox restarts itself by spawning into a new process group.
- # As long as mozprocess cannot track that behavior (bug 1284864) we assist by
- # informing about the new process id.
- self.instance.runner.process_handler.check_for_detached(self.process_id)
-
- def absolute_url(self, relative_url):
- '''
- Returns an absolute url for files served from Marionette's www directory.
-
- :param relative_url: The url of a static file, relative to Marionette's www directory.
- '''
- return "{0}{1}".format(self.baseurl, relative_url)
-
- @do_process_check
- def start_session(self, capabilities=None, session_id=None, timeout=60):
- """Create a new Marionette session.
-
- This method must be called before performing any other action.
-
- :param capabilities: An optional dict of desired or required capabilities.
- :param timeout: Timeout in seconds for the server to be ready.
- :param session_id: unique identifier for the session. If no session id is
- passed in then one will be generated by the marionette server.
-
- :returns: A dict of the capabilities offered.
-
- """
- self.crashed = 0
-
- if self.instance:
- returncode = self.instance.runner.returncode
- if returncode is not None:
- # We're managing a binary which has terminated, so restart it.
- self.instance.restart()
-
- self.client = transport.TcpTransport(
- self.host,
- self.port,
- self.socket_timeout)
-
- # Call wait_for_port() before attempting to connect in
- # the event gecko hasn't started yet.
- timeout = timeout or self.startup_timeout
- self.wait_for_port(timeout=timeout)
- self.protocol, _ = self.client.connect()
-
- body = {"capabilities": capabilities, "sessionId": session_id}
- resp = self._send_message("newSession", body)
-
- self.session_id = resp["sessionId"]
- self.session = resp["value"] if self.protocol == 1 else resp["capabilities"]
- # fallback to processId can be removed in Firefox 55
- self.process_id = self.session.get("moz:processID", self.session.get("processId"))
- self.profile = self.session.get("moz:profile")
-
- return self.session
-
- @property
- def test_name(self):
- return self._test_name
-
- @test_name.setter
- def test_name(self, test_name):
- self._send_message("setTestName", {"value": test_name})
- self._test_name = test_name
-
- def delete_session(self, send_request=True, reset_session_id=False):
- """Close the current session and disconnect from the server.
-
- :param send_request: Optional, if `True` a request to close the session on
- the server side will be send. Use `False` in case of eg. in_app restart()
- or quit(), which trigger a deletion themselves. Defaults to `True`.
- :param reset_session_id: Optional, if `True` the current session id will
- be reset, which will require an explicit call to `start_session()` before
- the test can continue. Defaults to `False`.
- """
- try:
- if send_request:
- self._send_message("deleteSession")
- finally:
- if reset_session_id:
- self.session_id = None
- self.session = None
- self.process_id = None
- self.profile = None
- self.window = None
-
- if self.client is not None:
- self.client.close()
-
- @property
- def session_capabilities(self):
- """A JSON dictionary representing the capabilities of the
- current session.
-
- """
- return self.session
-
- def set_script_timeout(self, timeout):
- """Sets the maximum number of ms that an asynchronous script is
- allowed to run.
-
- If a script does not return in the specified amount of time,
- a ScriptTimeoutException is raised.
-
- :param timeout: The maximum number of milliseconds an asynchronous
- script can run without causing an ScriptTimeoutException to
- be raised
-
- .. note:: `set_script_timeout` is deprecated, please use
- `timeout.script` setter.
-
- """
- warnings.warn(
- "set_script_timeout is deprecated, please use timeout.script setter",
- DeprecationWarning)
- self.timeout.script = timeout / 1000
-
- def set_search_timeout(self, timeout):
- """Sets a timeout for the find methods.
-
- When searching for an element using
- either :class:`Marionette.find_element` or
- :class:`Marionette.find_elements`, the method will continue
- trying to locate the element for up to timeout ms. This can be
- useful if, for example, the element you're looking for might
- not exist immediately, because it belongs to a page which is
- currently being loaded.
-
- :param timeout: Timeout in milliseconds.
-
- .. note:: `set_search_timeout` is deprecated, please use
- `timeout.implicit` setter.
-
- """
- warnings.warn(
- "set_search_timeout is deprecated, please use timeout.implicit setter",
- DeprecationWarning)
- self.timeout.implicit = timeout / 1000
-
- def set_page_load_timeout(self, timeout):
- """Sets a timeout for loading pages.
-
- A page load timeout specifies the amount of time the Marionette
- instance should wait for a page load operation to complete. A
- ``TimeoutException`` is returned if this limit is exceeded.
-
- :param timeout: Timeout in milliseconds.
-
- .. note:: `set_page_load_timeout` is deprecated, please use
- `timeout.page_load` setter.
-
- """
- warnings.warn(
- "set_page_load_timeout is deprecated, please use timeout.page_load setter",
- DeprecationWarning)
- self.timeout.page_load = timeout / 1000
-
- @property
- def current_window_handle(self):
- """Get the current window's handle.
-
- Returns an opaque server-assigned identifier to this window
- that uniquely identifies it within this Marionette instance.
- This can be used to switch to this window at a later point.
-
- :returns: unique window handle
- :rtype: string
- """
- self.window = self._send_message("getWindowHandle", key="value")
- return self.window
-
- @property
- def current_chrome_window_handle(self):
- """Get the current chrome window's handle. Corresponds to
- a chrome window that may itself contain tabs identified by
- window_handles.
-
- Returns an opaque server-assigned identifier to this window
- that uniquely identifies it within this Marionette instance.
- This can be used to switch to this window at a later point.
-
- :returns: unique window handle
- :rtype: string
- """
- self.chrome_window = self._send_message(
- "getCurrentChromeWindowHandle", key="value")
- return self.chrome_window
-
- def get_window_position(self):
- """Get the current window's position.
-
- :returns: a dictionary with x and y
- """
- return self._send_message(
- "getWindowPosition", key="value" if self.protocol == 1 else None)
-
- def set_window_position(self, x, y):
- """Set the position of the current window
-
- :param x: x coordinate for the top left of the window
- :param y: y coordinate for the top left of the window
- """
- self._send_message("setWindowPosition", {"x": x, "y": y})
-
- @property
- def title(self):
- """Current title of the active window."""
- return self._send_message("getTitle", key="value")
-
- @property
- def window_handles(self):
- """Get list of windows in the current context.
-
- If called in the content context it will return a list of
- references to all available browser windows. Called in the
- chrome context, it will list all available windows, not just
- browser windows (e.g. not just navigator.browser).
-
- Each window handle is assigned by the server, and the list of
- strings returned does not have a guaranteed ordering.
-
- :returns: Unordered list of unique window handles as strings
- """
- return self._send_message(
- "getWindowHandles", key="value" if self.protocol == 1 else None)
-
- @property
- def chrome_window_handles(self):
- """Get a list of currently open chrome windows.
-
- Each window handle is assigned by the server, and the list of
- strings returned does not have a guaranteed ordering.
-
- :returns: Unordered list of unique chrome window handles as strings
- """
- return self._send_message(
- "getChromeWindowHandles", key="value" if self.protocol == 1 else None)
-
- @property
- def page_source(self):
- """A string representation of the DOM."""
- return self._send_message("getPageSource", key="value")
-
- def close(self):
- """Close the current window, ending the session if it's the last
- window currently open.
-
- :returns: Unordered list of remaining unique window handles as strings
- """
- return self._send_message("close")
-
- def close_chrome_window(self):
- """Close the currently selected chrome window, ending the session
- if it's the last window open.
-
- :returns: Unordered list of remaining unique chrome window handles as strings
- """
- return self._send_message("closeChromeWindow")
-
- def set_context(self, context):
- """Sets the context that Marionette commands are running in.
-
- :param context: Context, may be one of the class properties
- `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
-
- Usage example::
-
- marionette.set_context(marionette.CONTEXT_CHROME)
- """
- if context not in [self.CONTEXT_CHROME, self.CONTEXT_CONTENT]:
- raise ValueError("Unknown context: {}".format(context))
- self._send_message("setContext", {"value": context})
-
- @contextmanager
- def using_context(self, context):
- """Sets the context that Marionette commands are running in using
- a `with` statement. The state of the context on the server is
- saved before entering the block, and restored upon exiting it.
-
- :param context: Context, may be one of the class properties
- `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
-
- Usage example::
-
- with marionette.using_context(marionette.CONTEXT_CHROME):
- # chrome scope
- ... do stuff ...
- """
- scope = self._send_message("getContext", key="value")
- self.set_context(context)
- try:
- yield
- finally:
- self.set_context(scope)
-
- def switch_to_alert(self):
- """Returns an Alert object for interacting with a currently
- displayed alert.
-
- ::
-
- alert = self.marionette.switch_to_alert()
- text = alert.text
- alert.accept()
- """
- return Alert(self)
-
- def switch_to_window(self, window_id, focus=True):
- """Switch to the specified window; subsequent commands will be
- directed at the new window.
-
- :param window_id: The id or name of the window to switch to.
-
- :param focus: A boolean value which determins whether to focus
- the window that we just switched to.
- """
- body = {"focus": focus, "name": window_id}
- self._send_message("switchToWindow", body)
- self.window = window_id
-
- def get_active_frame(self):
- """Returns an HTMLElement representing the frame Marionette is
- currently acting on."""
- return self._send_message("getActiveFrame", key="value")
-
- def switch_to_default_content(self):
- """Switch the current context to page's default content."""
- return self.switch_to_frame()
-
- def switch_to_parent_frame(self):
- """
- Switch to the Parent Frame
- """
- self._send_message("switchToParentFrame")
-
- def switch_to_frame(self, frame=None, focus=True):
- """Switch the current context to the specified frame. Subsequent
- commands will operate in the context of the specified frame,
- if applicable.
-
- :param frame: A reference to the frame to switch to. This can
- be an ``HTMLElement``, an integer index, string name, or an
- ID attribute. If you call ``switch_to_frame`` without an
- argument, it will switch to the top-level frame.
-
- :param focus: A boolean value which determins whether to focus
- the frame that we just switched to.
- """
- body = {"focus": focus}
- if isinstance(frame, HTMLElement):
- body["element"] = frame.id
- elif frame is not None:
- body["id"] = frame
- self._send_message("switchToFrame", body)
-
- def switch_to_shadow_root(self, host=None):
- """Switch the current context to the specified host's Shadow DOM.
- Subsequent commands will operate in the context of the specified Shadow
- DOM, if applicable.
-
- :param host: A reference to the host element containing Shadow DOM.
- This can be an ``HTMLElement``. If you call
- ``switch_to_shadow_root`` without an argument, it will switch to the
- parent Shadow DOM or the top-level frame.
- """
- body = {}
- if isinstance(host, HTMLElement):
- body["id"] = host.id
- return self._send_message("switchToShadowRoot", body)
-
- def get_url(self):
- """Get a string representing the current URL.
-
- On Desktop this returns a string representation of the URL of
- the current top level browsing context. This is equivalent to
- document.location.href.
-
- When in the context of the chrome, this returns the canonical
- URL of the current resource.
-
- :returns: string representation of URL
- """
- return self._send_message("getCurrentUrl", key="value")
-
- def get_window_type(self):
- """Gets the windowtype attribute of the window Marionette is
- currently acting on.
-
- This command only makes sense in a chrome context. You might use this
- method to distinguish a browser window from an editor window.
- """
- return self._send_message("getWindowType", key="value")
-
- def navigate(self, url):
- """Navigate to given `url`.
-
- Navigates the current top-level browsing context's content
- frame to the given URL and waits for the document to load or
- the session's page timeout duration to elapse before returning.
-
- The command will return with a failure if there is an error
- loading the document or the URL is blocked. This can occur if
- it fails to reach the host, the URL is malformed, the page is
- restricted (about:* pages), or if there is a certificate issue
- to name some examples.
-
- The document is considered successfully loaded when the
- `DOMContentLoaded` event on the frame element associated with the
- `window` triggers and `document.readState` is "complete".
-
- In chrome context it will change the current `window`'s location
- to the supplied URL and wait until `document.readState` equals
- "complete" or the page timeout duration has elapsed.
-
- :param url: The URL to navigate to.
- """
- self._send_message("get", {"url": url})
-
- def go_back(self):
- """Causes the browser to perform a back navigation."""
- self._send_message("goBack")
-
- def go_forward(self):
- """Causes the browser to perform a forward navigation."""
- self._send_message("goForward")
-
- def refresh(self):
- """Causes the browser to perform to refresh the current page."""
- self._send_message("refresh")
-
- def _to_json(self, args):
- if isinstance(args, list) or isinstance(args, tuple):
- wrapped = []
- for arg in args:
- wrapped.append(self._to_json(arg))
- elif isinstance(args, dict):
- wrapped = {}
- for arg in args:
- wrapped[arg] = self._to_json(args[arg])
- elif type(args) == HTMLElement:
- wrapped = {W3C_WEBELEMENT_KEY: args.id,
- WEBELEMENT_KEY: args.id}
- elif (isinstance(args, bool) or isinstance(args, basestring) or
- isinstance(args, int) or isinstance(args, float) or args is None):
- wrapped = args
- return wrapped
-
- def _from_json(self, value):
- if isinstance(value, list):
- unwrapped = []
- for item in value:
- unwrapped.append(self._from_json(item))
- elif isinstance(value, dict):
- unwrapped = {}
- for key in value:
- if key == W3C_WEBELEMENT_KEY:
- unwrapped = HTMLElement(self, value[key])
- break
- elif key == WEBELEMENT_KEY:
- unwrapped = HTMLElement(self, value[key])
- break
- else:
- unwrapped[key] = self._from_json(value[key])
- else:
- unwrapped = value
- return unwrapped
-
- def execute_js_script(self, script, script_args=(), async=True,
- new_sandbox=True, script_timeout=None,
- inactivity_timeout=None, filename=None,
- sandbox='default'):
- args = self._to_json(script_args)
- body = {"script": script,
- "args": args,
- "async": async,
- "newSandbox": new_sandbox,
- "scriptTimeout": script_timeout,
- "inactivityTimeout": inactivity_timeout,
- "filename": filename,
- "line": None}
- rv = self._send_message("executeJSScript", body, key="value")
- return self._from_json(rv)
-
- def execute_script(self, script, script_args=(), new_sandbox=True,
- sandbox="default", script_timeout=None):
- """Executes a synchronous JavaScript script, and returns the
- result (or None if the script does return a value).
-
- The script is executed in the context set by the most recent
- set_context() call, or to the CONTEXT_CONTENT context if set_context()
- has not been called.
-
- :param script: A string containing the JavaScript to execute.
- :param script_args: An interable of arguments to pass to the script.
- :param sandbox: A tag referring to the sandbox you wish to use;
- if you specify a new tag, a new sandbox will be created.
- If you use the special tag `system`, the sandbox will
- be created using the system principal which has elevated
- privileges.
- :param new_sandbox: If False, preserve global variables from
- the last execute_*script call. This is True by default, in which
- case no globals are preserved.
-
- Simple usage example:
-
- ::
-
- result = marionette.execute_script("return 1;")
- assert result == 1
-
- You can use the `script_args` parameter to pass arguments to the
- script:
-
- ::
-
- result = marionette.execute_script("return arguments[0] + arguments[1];",
- script_args=(2, 3,))
- assert result == 5
- some_element = marionette.find_element(By.ID, "someElement")
- sid = marionette.execute_script("return arguments[0].id;", script_args=(some_element,))
- assert some_element.get_attribute("id") == sid
-
- Scripts wishing to access non-standard properties of the window
- object must use window.wrappedJSObject:
-
- ::
-
- result = marionette.execute_script('''
- window.wrappedJSObject.test1 = "foo";
- window.wrappedJSObject.test2 = "bar";
- return window.wrappedJSObject.test1 + window.wrappedJSObject.test2;
- ''')
- assert result == "foobar"
-
- Global variables set by individual scripts do not persist between
- script calls by default. If you wish to persist data between
- script calls, you can set new_sandbox to False on your next call,
- and add any new variables to a new 'global' object like this:
-
- ::
-
- marionette.execute_script("global.test1 = 'foo';")
- result = self.marionette.execute_script("return global.test1;", new_sandbox=False)
- assert result == "foo"
-
- """
- args = self._to_json(script_args)
- stack = traceback.extract_stack()
- frame = stack[-2:-1][0] # grab the second-to-last frame
- body = {"script": script,
- "args": args,
- "newSandbox": new_sandbox,
- "sandbox": sandbox,
- "scriptTimeout": script_timeout,
- "line": int(frame[1]),
- "filename": os.path.basename(frame[0])}
- rv = self._send_message("executeScript", body, key="value")
- return self._from_json(rv)
-
- def execute_async_script(self, script, script_args=(), new_sandbox=True,
- sandbox="default", script_timeout=None,
- debug_script=False):
- """Executes an asynchronous JavaScript script, and returns the
- result (or None if the script does return a value).
-
- The script is executed in the context set by the most recent
- set_context() call, or to the CONTEXT_CONTENT context if
- set_context() has not been called.
-
- :param script: A string containing the JavaScript to execute.
- :param script_args: An interable of arguments to pass to the script.
- :param sandbox: A tag referring to the sandbox you wish to use; if
- you specify a new tag, a new sandbox will be created. If you
- use the special tag `system`, the sandbox will be created
- using the system principal which has elevated privileges.
- :param new_sandbox: If False, preserve global variables from
- the last execute_*script call. This is True by default,
- in which case no globals are preserved.
- :param debug_script: Capture javascript exceptions when in
- `CONTEXT_CHROME` context.
-
- Usage example:
-
- ::
-
- marionette.timeout.script = 10
- result = self.marionette.execute_async_script('''
- // this script waits 5 seconds, and then returns the number 1
- setTimeout(function() {
- marionetteScriptFinished(1);
- }, 5000);
- ''')
- assert result == 1
- """
- args = self._to_json(script_args)
- stack = traceback.extract_stack()
- frame = stack[-2:-1][0] # grab the second-to-last frame
- body = {"script": script,
- "args": args,
- "newSandbox": new_sandbox,
- "sandbox": sandbox,
- "scriptTimeout": script_timeout,
- "line": int(frame[1]),
- "filename": os.path.basename(frame[0]),
- "debug_script": debug_script}
- rv = self._send_message("executeAsyncScript", body, key="value")
- return self._from_json(rv)
-
- def find_element(self, method, target, id=None):
- """Returns an HTMLElement instances that matches the specified
- method and target in the current context.
-
- An HTMLElement instance may be used to call other methods on the
- element, such as click(). If no element is immediately found, the
- attempt to locate an element will be repeated for up to the amount of
- time set by ``timeout.implicit``. If multiple elements match the given
- criteria, only the first is returned. If no element matches, a
- NoSuchElementException will be raised.
-
- :param method: The method to use to locate the element; one of:
- "id", "name", "class name", "tag name", "css selector",
- "link text", "partial link text", "xpath", "anon" and "anon
- attribute". Note that the "name", "link text" and "partial
- link test" methods are not supported in the chrome DOM.
- :param target: The target of the search. For example, if method =
- "tag", target might equal "div". If method = "id", target would
- be an element id.
- :param id: If specified, search for elements only inside the element
- with the specified id.
- """
- body = {"value": target, "using": method}
- if id:
- body["element"] = id
- return self._send_message("findElement", body, key="value")
-
- def find_elements(self, method, target, id=None):
- """Returns a list of all HTMLElement instances that match the
- specified method and target in the current context.
-
- An HTMLElement instance may be used to call other methods on the
- element, such as click(). If no element is immediately found,
- the attempt to locate an element will be repeated for up to the
- amount of time set by ``timeout.implicit``.
-
- :param method: The method to use to locate the elements; one
- of: "id", "name", "class name", "tag name", "css selector",
- "link text", "partial link text", "xpath", "anon" and "anon
- attribute". Note that the "name", "link text" and "partial link
- test" methods are not supported in the chrome DOM.
- :param target: The target of the search. For example, if method =
- "tag", target might equal "div". If method = "id", target would be
- an element id.
- :param id: If specified, search for elements only inside the element
- with the specified id.
- """
- body = {"value": target, "using": method}
- if id:
- body["element"] = id
- return self._send_message(
- "findElements", body, key="value" if self.protocol == 1 else None)
-
- def get_active_element(self):
- el_or_ref = self._send_message("getActiveElement", key="value")
- if self.protocol < 3:
- return HTMLElement(self, el_or_ref)
- return el_or_ref
-
- def log(self, msg, level="INFO"):
- """Stores a timestamped log message in the Marionette server
- for later retrieval.
-
- :param msg: String with message to log.
- :param level: String with log level (e.g. "INFO" or "DEBUG").
- Defaults to "INFO".
- """
- body = {"value": msg, "level": level}
- self._send_message("log", body)
-
- def get_logs(self):
- """Returns the list of logged messages.
-
- Each log message is an array with three string elements: the level,
- the message, and a date.
-
- Usage example::
-
- marionette.log("I AM INFO")
- marionette.log("I AM ERROR", "ERROR")
- logs = marionette.get_logs()
- assert logs[0][1] == "I AM INFO"
- assert logs[1][1] == "I AM ERROR"
- """
- return self._send_message("getLogs",
- key="value" if self.protocol == 1 else None)
-
- def import_script(self, js_file):
- """Imports a script into the scope of the execute_script and
- execute_async_script calls.
-
- This is particularly useful if you wish to import your own
- libraries.
-
- :param js_file: Filename of JavaScript file to import.
-
- For example, Say you have a script, importfunc.js, that contains:
-
- ::
-
- let testFunc = function() { return "i'm a test function!";};
-
- Assuming this file is in the same directory as the test, you
- could do something like:
-
- ::
-
- js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importfunc.js"))
- marionette.import_script(js)
- assert "i'm a test function!" == self.marionette.execute_script("return testFunc();")
- """
- js = ""
- with open(js_file, "r") as f:
- js = f.read()
- body = {"script": js}
- self._send_message("importScript", body)
-
- def clear_imported_scripts(self):
- """Clears all imported scripts in this context, ie: calling
- clear_imported_scripts in chrome context will clear only scripts
- you imported in chrome, and will leave the scripts you imported
- in content context.
- """
- self._send_message("clearImportedScripts")
-
- def add_cookie(self, cookie):
- """Adds a cookie to your current session.
-
- :param cookie: A dictionary object, with required keys - "name"
- and "value"; optional keys - "path", "domain", "secure",
- "expiry".
-
- Usage example:
-
- ::
-
- driver.add_cookie({"name": "foo", "value": "bar"})
- driver.add_cookie({"name": "foo", "value": "bar", "path": "/"})
- driver.add_cookie({"name": "foo", "value": "bar", "path": "/",
- "secure": True})
- """
- body = {"cookie": cookie}
- self._send_message("addCookie", body)
-
- def delete_all_cookies(self):
- """Delete all cookies in the scope of the current session.
-
- Usage example:
-
- ::
-
- driver.delete_all_cookies()
- """
- self._send_message("deleteAllCookies")
-
- def delete_cookie(self, name):
- """Delete a cookie by its name.
-
- :param name: Name of cookie to delete.
-
- Usage example:
-
- ::
-
- driver.delete_cookie("foo")
- """
- self._send_message("deleteCookie", {"name": name})
-
- def get_cookie(self, name):
- """Get a single cookie by name. Returns the cookie if found,
- None if not.
-
- :param name: Name of cookie to get.
- """
- cookies = self.get_cookies()
- for cookie in cookies:
- if cookie["name"] == name:
- return cookie
- return None
-
- def get_cookies(self):
- """Get all the cookies for the current domain.
-
- This is the equivalent of calling `document.cookie` and
- parsing the result.
-
- :returns: A list of cookies for the current domain.
- """
- return self._send_message("getCookies", key="value" if self.protocol == 1 else None)
-
- def screenshot(self, element=None, highlights=None, format="base64",
- full=True, scroll=True):
- """Takes a screenshot of a web element or the current frame.
-
- The screen capture is returned as a lossless PNG image encoded
- as a base 64 string by default. If the `element` argument is defined the
- capture area will be limited to the bounding box of that
- element. Otherwise, the capture area will be the bounding box
- of the current frame.
-
- :param element: The element to take a screenshot of. If None, will
- take a screenshot of the current frame.
-
- :param highlights: A list of HTMLElement objects to draw a red
- box around in the returned screenshot.
-
- :param format: if "base64" (the default), returns the screenshot
- as a base64-string. If "binary", the data is decoded and
- returned as raw binary. If "hash", the data is hashed using
- the SHA-256 algorithm and the result is returned as a hex digest.
-
- :param full: If True (the default), the capture area will be the
- complete frame. Else only the viewport is captured. Only applies
- when `element` is None.
-
- :param scroll: When `element` is provided, scroll to it before
- taking the screenshot (default). Otherwise, avoid scrolling
- `element` into view.
- """
-
- if element:
- element = element.id
- lights = None
- if highlights:
- lights = [highlight.id for highlight in highlights]
-
- body = {"id": element,
- "highlights": lights,
- "full": full,
- "hash": False,
- "scroll": scroll}
- if format == "hash":
- body["hash"] = True
- data = self._send_message("takeScreenshot", body, key="value")
-
- if format == "base64" or format == "hash":
- return data
- elif format == "binary":
- return base64.b64decode(data.encode("ascii"))
- else:
- raise ValueError("format parameter must be either 'base64'"
- " or 'binary', not {0}".format(repr(format)))
-
- @property
- def orientation(self):
- """Get the current browser orientation.
-
- Will return one of the valid primary orientation values
- portrait-primary, landscape-primary, portrait-secondary, or
- landscape-secondary.
- """
- return self._send_message("getScreenOrientation", key="value")
-
- def set_orientation(self, orientation):
- """Set the current browser orientation.
-
- The supplied orientation should be given as one of the valid
- orientation values. If the orientation is unknown, an error
- will be raised.
-
- Valid orientations are "portrait" and "landscape", which fall
- back to "portrait-primary" and "landscape-primary"
- respectively, and "portrait-secondary" as well as
- "landscape-secondary".
-
- :param orientation: The orientation to lock the screen in.
- """
- body = {"orientation": orientation}
- self._send_message("setScreenOrientation", body)
-
- @property
- def window_size(self):
- """Get the current browser window size.
-
- Will return the current browser window size in pixels. Refers to
- window outerWidth and outerHeight values, which include scroll bars,
- title bars, etc.
-
- :returns: dictionary representation of current window width and height
- """
- return self._send_message("getWindowSize",
- key="value" if self.protocol == 1 else None)
-
- def set_window_size(self, width, height):
- """Resize the browser window currently in focus.
-
- The supplied width and height values refer to the window outerWidth
- and outerHeight values, which include scroll bars, title bars, etc.
-
- An error will be returned if the requested window size would result
- in the window being in the maximised state.
-
- :param width: The width to resize the window to.
- :param height: The height to resize the window to.
-
- """
- body = {"width": width, "height": height}
- return self._send_message("setWindowSize", body)
-
- def maximize_window(self):
- """ Resize the browser window currently receiving commands. The action
- should be equivalent to the user pressing the the maximize button
- """
- return self._send_message("maximizeWindow")
diff --git a/testing/marionette/client/marionette_driver/selection.py b/testing/marionette/client/marionette_driver/selection.py
deleted file mode 100644
index 30e66deaa9..0000000000
--- a/testing/marionette/client/marionette_driver/selection.py
+++ /dev/null
@@ -1,227 +0,0 @@
-# -*- coding: utf-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/.
-
-
-class SelectionManager(object):
- '''Interface for manipulating the selection and carets of the element.
-
- We call the blinking cursor (nsCaret) as cursor, and call AccessibleCaret as
- caret for short.
-
- Simple usage example:
-
- ::
-
- element = marionette.find_element(By.ID, 'input')
- sel = SelectionManager(element)
- sel.move_caret_to_front()
-
- '''
-
- def __init__(self, element):
- self.element = element
-
- def _input_or_textarea(self):
- '''Return True if element is either <input> or <textarea>.'''
- return self.element.tag_name in ('input', 'textarea')
-
- def js_selection_cmd(self):
- '''Return a command snippet to get selection object.
-
- If the element is <input> or <textarea>, return the selection object
- associated with it. Otherwise, return the current selection object.
-
- Note: "element" must be provided as the first argument to
- execute_script().
-
- '''
- if self._input_or_textarea():
- # We must unwrap sel so that DOMRect could be returned to Python
- # side.
- return '''var sel = arguments[0].editor.selection;'''
- else:
- return '''var sel = window.getSelection();'''
-
- def move_cursor_by_offset(self, offset, backward=False):
- '''Move cursor in the element by character offset.
-
- :param offset: Move the cursor to the direction by offset characters.
- :param backward: Optional, True to move backward; Default to False to
- move forward.
-
- '''
- cmd = self.js_selection_cmd() + '''
- for (let i = 0; i < {0}; ++i) {{
- sel.modify("move", "{1}", "character");
- }}
- '''.format(offset, 'backward' if backward else 'forward')
-
- self.element.marionette.execute_script(
- cmd, script_args=[self.element], sandbox='system')
-
- def move_cursor_to_front(self):
- '''Move cursor in the element to the front of the content.'''
- if self._input_or_textarea():
- cmd = '''arguments[0].setSelectionRange(0, 0);'''
- else:
- cmd = '''var sel = window.getSelection();
- sel.collapse(arguments[0].firstChild, 0);'''
-
- self.element.marionette.execute_script(cmd, script_args=[self.element])
-
- def move_cursor_to_end(self):
- '''Move cursor in the element to the end of the content.'''
- if self._input_or_textarea():
- cmd = '''var len = arguments[0].value.length;
- arguments[0].setSelectionRange(len, len);'''
- else:
- cmd = '''var sel = window.getSelection();
- sel.collapse(arguments[0].lastChild, arguments[0].lastChild.length);'''
-
- self.element.marionette.execute_script(cmd, script_args=[self.element])
-
- def selection_rect_list(self, idx):
- '''Return the selection's DOMRectList object for the range at given idx.
-
- If the element is either <input> or <textarea>, return the DOMRectList of
- the range at given idx of the selection within the element. Otherwise,
- return the DOMRectList of the of the range at given idx of current selection.
-
- '''
- cmd = self.js_selection_cmd() +\
- '''return sel.getRangeAt({}).getClientRects();'''.format(idx)
- return self.element.marionette.execute_script(cmd,
- script_args=[self.element],
- sandbox='system')
-
- def range_count(self):
- '''Get selection's range count'''
- cmd = self.js_selection_cmd() +\
- '''return sel.rangeCount;'''
- return self.element.marionette.execute_script(cmd,
- script_args=[self.element],
- sandbox='system')
-
- def _selection_location_helper(self, location_type):
- '''Return the start and end location of the selection in the element.
-
- Return a tuple containing two pairs of (x, y) coordinates of the start
- and end locations in the element. The coordinates are relative to the
- top left-hand corner of the element. Both ltr and rtl directions are
- considered.
-
- '''
- range_count = self.range_count()
- first_rect_list = self.selection_rect_list(0)
- last_rect_list = self.selection_rect_list(range_count - 1)
- last_list_length = last_rect_list['length']
- first_rect, last_rect = first_rect_list['0'], last_rect_list[str(last_list_length - 1)]
- origin_x, origin_y = self.element.rect['x'], self.element.rect['y']
-
- if self.element.get_property('dir') == 'rtl': # such as Arabic
- start_pos, end_pos = 'right', 'left'
- else:
- start_pos, end_pos = 'left', 'right'
-
- # Calculate y offset according to different needs.
- if location_type == 'center':
- start_y_offset = first_rect['height'] / 2.0
- end_y_offset = last_rect['height'] / 2.0
- elif location_type == 'caret':
- # Selection carets' tip are below the bottom of the two ends of the
- # selection. Add 5px to y should be sufficient to locate them.
- caret_tip_y_offset = 5
- start_y_offset = first_rect['height'] + caret_tip_y_offset
- end_y_offset = last_rect['height'] + caret_tip_y_offset
- else:
- start_y_offset = end_y_offset = 0
-
- caret1_x = first_rect[start_pos] - origin_x
- caret1_y = first_rect['top'] + start_y_offset - origin_y
- caret2_x = last_rect[end_pos] - origin_x
- caret2_y = last_rect['top'] + end_y_offset - origin_y
-
- return ((caret1_x, caret1_y), (caret2_x, caret2_y))
-
- def selection_location(self):
- '''Return the start and end location of the selection in the element.
-
- Return a tuple containing two pairs of (x, y) coordinates of the start
- and end of the selection. The coordinates are relative to the top
- left-hand corner of the element. Both ltr and rtl direction are
- considered.
-
- '''
- return self._selection_location_helper('center')
-
- def carets_location(self):
- '''Return a pair of the two carets' location.
-
- Return a tuple containing two pairs of (x, y) coordinates of the two
- carets' tip. The coordinates are relative to the top left-hand corner of
- the element. Both ltr and rtl direction are considered.
-
- '''
- return self._selection_location_helper('caret')
-
- def cursor_location(self):
- '''Return the blanking cursor's center location within the element.
-
- Return (x, y) coordinates of the cursor's center relative to the top
- left-hand corner of the element.
-
- '''
- return self._selection_location_helper('center')[0]
-
- def first_caret_location(self):
- '''Return the first caret's location.
-
- Return (x, y) coordinates of the first caret's tip relative to the top
- left-hand corner of the element.
-
- '''
- return self.carets_location()[0]
-
- def second_caret_location(self):
- '''Return the second caret's location.
-
- Return (x, y) coordinates of the second caret's tip relative to the top
- left-hand corner of the element.
-
- '''
- return self.carets_location()[1]
-
- def select_all(self):
- '''Select all the content in the element.'''
- if self._input_or_textarea():
- cmd = '''var len = arguments[0].value.length;
- arguments[0].focus();
- arguments[0].setSelectionRange(0, len);'''
- else:
- cmd = '''var range = document.createRange();
- range.setStart(arguments[0].firstChild, 0);
- range.setEnd(arguments[0].lastChild, arguments[0].lastChild.length);
- var sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);'''
-
- self.element.marionette.execute_script(cmd, script_args=[self.element])
-
- @property
- def content(self):
- '''Return all the content of the element.'''
- if self._input_or_textarea():
- return self.element.get_property('value')
- else:
- return self.element.text
-
- @property
- def selected_content(self):
- '''Return the selected portion of the content in the element.'''
- cmd = self.js_selection_cmd() +\
- '''return sel.toString();'''
- return self.element.marionette.execute_script(cmd,
- script_args=[self.element],
- sandbox='system')
diff --git a/testing/marionette/client/marionette_driver/timeout.py b/testing/marionette/client/marionette_driver/timeout.py
deleted file mode 100644
index e2fa94f4fd..0000000000
--- a/testing/marionette/client/marionette_driver/timeout.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# 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 errors
-
-
-DEFAULT_SCRIPT_TIMEOUT = 30
-DEFAULT_PAGE_LOAD_TIMEOUT = 300
-DEFAULT_IMPLICIT_WAIT_TIMEOUT = 0
-
-
-class Timeouts(object):
- """Manage timeout settings in the Marionette session.
-
- Usage::
-
- marionette = Marionette(...)
- marionette.start_session()
- marionette.timeout.page_load = 10
- marionette.timeout.page_load
- # => 10
-
- """
-
- def __init__(self, marionette):
- self._marionette = marionette
-
- def _set(self, name, sec):
- ms = sec * 1000
- try:
- self._marionette._send_message("setTimeouts", {name: ms})
- except errors.UnknownCommandException:
- # remove when 55 is stable
- self._marionette._send_message("timeouts", {"type": name, "ms": ms})
-
- def _get(self, name):
- ms = self._marionette._send_message("getTimeouts", key=name)
- return ms / 1000
-
- @property
- def script(self):
- """Get the session's script timeout. This specifies the time
- to wait for injected scripts to finished before interrupting
- them. It is by default 30 seconds.
-
- """
- return self._get("script")
-
- @script.setter
- def script(self, sec):
- """Set the session's script timeout. This specifies the time
- to wait for injected scripts to finish before interrupting them.
-
- """
- self._set("script", sec)
-
- @property
- def page_load(self):
- """Get the session's page load timeout. This specifies the time
- to wait for the page loading to complete. It is by default 5
- minutes (or 300 seconds).
-
- """
- return self._get("page load")
-
- @page_load.setter
- def page_load(self, sec):
- """Set the session's page load timeout. This specifies the time
- to wait for the page loading to complete.
-
- """
- self._set("page load", sec)
-
- @property
- def implicit(self):
- """Get the session's implicit wait timeout. This specifies the
- time to wait for the implicit element location strategy when
- retrieving elements. It is by default disabled (0 seconds).
-
- """
- return self._get("implicit")
-
- @implicit.setter
- def implicit(self, sec):
- """Set the session's implicit wait timeout. This specifies the
- time to wait for the implicit element location strategy when
- retrieving elements.
-
- """
- self._set("implicit", sec)
-
- def reset(self):
- """Resets timeouts to their default values."""
- self.script = DEFAULT_SCRIPT_TIMEOUT
- self.page_load = DEFAULT_PAGE_LOAD_TIMEOUT
- self.implicit = DEFAULT_IMPLICIT_WAIT_TIMEOUT
diff --git a/testing/marionette/client/marionette_driver/transport.py b/testing/marionette/client/marionette_driver/transport.py
deleted file mode 100644
index 82828fdef1..0000000000
--- a/testing/marionette/client/marionette_driver/transport.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# 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 json
-import socket
-import time
-
-
-class SocketTimeout(object):
- def __init__(self, socket, timeout):
- self.sock = socket
- self.timeout = timeout
- self.old_timeout = None
-
- def __enter__(self):
- self.old_timeout = self.sock.gettimeout()
- self.sock.settimeout(self.timeout)
-
- def __exit__(self, *args, **kwargs):
- self.sock.settimeout(self.old_timeout)
-
-
-class Message(object):
- def __init__(self, msgid):
- self.id = msgid
-
- def __eq__(self, other):
- return self.id == other.id
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
-
-class Command(Message):
- TYPE = 0
-
- def __init__(self, msgid, name, params):
- Message.__init__(self, msgid)
- self.name = name
- self.params = params
-
- def __str__(self):
- return "<Command id={0}, name={1}, params={2}>".format(self.id, self.name, self.params)
-
- def to_msg(self):
- msg = [Command.TYPE, self.id, self.name, self.params]
- return json.dumps(msg)
-
- @staticmethod
- def from_msg(payload):
- data = json.loads(payload)
- assert data[0] == Command.TYPE
- cmd = Command(data[1], data[2], data[3])
- return cmd
-
-
-class Response(Message):
- TYPE = 1
-
- def __init__(self, msgid, error, result):
- Message.__init__(self, msgid)
- self.error = error
- self.result = result
-
- def __str__(self):
- return "<Response id={0}, error={1}, result={2}>".format(self.id, self.error, self.result)
-
- def to_msg(self):
- msg = [Response.TYPE, self.id, self.error, self.result]
- return json.dumps(msg)
-
- @staticmethod
- def from_msg(payload):
- data = json.loads(payload)
- assert data[0] == Response.TYPE
- return Response(data[1], data[2], data[3])
-
-
-class Proto2Command(Command):
- """Compatibility shim that marshals messages from a protocol level
- 2 and below remote into ``Command`` objects.
- """
-
- def __init__(self, name, params):
- Command.__init__(self, None, name, params)
-
-
-class Proto2Response(Response):
- """Compatibility shim that marshals messages from a protocol level
- 2 and below remote into ``Response`` objects.
- """
-
- def __init__(self, error, result):
- Response.__init__(self, None, error, result)
-
- @staticmethod
- def from_data(data):
- err, res = None, None
- if "error" in data:
- err = data
- else:
- res = data
- return Proto2Response(err, res)
-
-
-class TcpTransport(object):
- """Socket client that communciates with Marionette via TCP.
-
- It speaks the protocol of the remote debugger in Gecko, in which
- messages are always preceded by the message length and a colon, e.g.:
-
- 7:MESSAGE
-
- On top of this protocol it uses a Marionette message format, that
- depending on the protocol level offered by the remote server, varies.
- Supported protocol levels are 1 and above.
- """
- max_packet_length = 4096
-
- def __init__(self, addr, port, socket_timeout=60.0):
- """If `socket_timeout` is `0` or `0.0`, non-blocking socket mode
- will be used. Setting it to `1` or `None` disables timeouts on
- socket operations altogether.
- """
- self.addr = addr
- self.port = port
- self._socket_timeout = socket_timeout
-
- self.protocol = 1
- self.application_type = None
- self.last_id = 0
- self.expected_response = None
- self.sock = None
-
- @property
- def socket_timeout(self):
- return self._socket_timeout
-
- @socket_timeout.setter
- def socket_timeout(self, value):
- if self.sock:
- self.sock.settimeout(value)
- self._socket_timeout = value
-
- def _unmarshal(self, packet):
- msg = None
-
- # protocol 3 and above
- if self.protocol >= 3:
- typ = int(packet[1])
- if typ == Command.TYPE:
- msg = Command.from_msg(packet)
- elif typ == Response.TYPE:
- msg = Response.from_msg(packet)
-
- # protocol 2 and below
- else:
- data = json.loads(packet)
-
- msg = Proto2Response.from_data(data)
-
- return msg
-
- def receive(self, unmarshal=True):
- """Wait for the next complete response from the remote.
-
- :param unmarshal: Default is to deserialise the packet and
- return a ``Message`` type. Setting this to false will return
- the raw packet.
- """
- now = time.time()
- data = ""
- bytes_to_recv = 10
-
- while self.socket_timeout is None or (time.time() - now < self.socket_timeout):
- try:
- chunk = self.sock.recv(bytes_to_recv)
- data += chunk
- except socket.timeout:
- pass
- else:
- if not chunk:
- raise socket.error("No data received over socket")
-
- sep = data.find(":")
- if sep > -1:
- length = data[0:sep]
- remaining = data[sep + 1:]
-
- if len(remaining) == int(length):
- if unmarshal:
- msg = self._unmarshal(remaining)
- self.last_id = msg.id
-
- if self.protocol >= 3:
- self.last_id = msg.id
-
- # keep reading incoming responses until
- # we receive the user's expected response
- if isinstance(msg, Response) and msg != self.expected_response:
- return self.receive(unmarshal)
-
- return msg
-
- else:
- return remaining
-
- bytes_to_recv = int(length) - len(remaining)
-
- raise socket.timeout("Connection timed out after {}s".format(self.socket_timeout))
-
- def connect(self):
- """Connect to the server and process the hello message we expect
- to receive in response.
-
- Returns a tuple of the protocol level and the application type.
- """
- try:
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.settimeout(self.socket_timeout)
-
- self.sock.connect((self.addr, self.port))
- except:
- # Unset self.sock so that the next attempt to send will cause
- # another connection attempt.
- self.sock = None
- raise
-
- with SocketTimeout(self.sock, 2.0):
- # first packet is always a JSON Object
- # which we can use to tell which protocol level we are at
- raw = self.receive(unmarshal=False)
- hello = json.loads(raw)
- self.protocol = hello.get("marionetteProtocol", 1)
- self.application_type = hello.get("applicationType")
-
- return (self.protocol, self.application_type)
-
- def send(self, obj):
- """Send message to the remote server. Allowed input is a
- ``Message`` instance or a JSON serialisable object.
- """
- if not self.sock:
- self.connect()
-
- if isinstance(obj, Message):
- data = obj.to_msg()
- if isinstance(obj, Command):
- self.expected_response = obj
- else:
- data = json.dumps(obj)
- payload = "{0}:{1}".format(len(data), data)
-
- totalsent = 0
- while totalsent < len(payload):
- sent = self.sock.send(payload[totalsent:])
- if sent == 0:
- raise IOError("Socket error after sending {0} of {1} bytes"
- .format(totalsent, len(payload)))
- else:
- totalsent += sent
-
- def respond(self, obj):
- """Send a response to a command. This can be an arbitrary JSON
- serialisable object or an ``Exception``.
- """
- res, err = None, None
- if isinstance(obj, Exception):
- err = obj
- else:
- res = obj
- msg = Response(self.last_id, err, res)
- self.send(msg)
- return self.receive()
-
- def request(self, name, params):
- """Sends a message to the remote server and waits for a response
- to come back.
- """
- self.last_id = self.last_id + 1
- cmd = Command(self.last_id, name, params)
- self.send(cmd)
- return self.receive()
-
- def close(self):
- """Close the socket."""
- if self.sock:
- try:
- self.sock.shutdown(socket.SHUT_RDWR)
- except IOError as exc:
- # Errno 57 is "socket not connected", which we don't care about here.
- if exc.errno != 57:
- raise
-
- self.sock.close()
- self.sock = None
-
- def __del__(self):
- self.close()
diff --git a/testing/marionette/client/marionette_driver/wait.py b/testing/marionette/client/marionette_driver/wait.py
deleted file mode 100644
index c89465ce42..0000000000
--- a/testing/marionette/client/marionette_driver/wait.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# 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 collections
-import errors
-import sys
-import time
-
-DEFAULT_TIMEOUT = 5
-DEFAULT_INTERVAL = 0.1
-
-
-class Wait(object):
-
- """An explicit conditional utility class for waiting until a condition
- evaluates to true or not null.
-
- This will repeatedly evaluate a condition in anticipation for a
- truthy return value, or its timeout to expire, or its waiting
- predicate to become true.
-
- A `Wait` instance defines the maximum amount of time to wait for a
- condition, as well as the frequency with which to check the
- condition. Furthermore, the user may configure the wait to ignore
- specific types of exceptions whilst waiting, such as
- `errors.NoSuchElementException` when searching for an element on
- the page.
-
- """
-
- def __init__(self, marionette, timeout=DEFAULT_TIMEOUT,
- interval=DEFAULT_INTERVAL, ignored_exceptions=None,
- clock=None):
- """Configure the Wait instance to have a custom timeout, interval, and
- list of ignored exceptions. Optionally a different time
- implementation than the one provided by the standard library
- (time) can also be provided.
-
- Sample usage::
-
- # Wait 30 seconds for window to open, checking for its presence once
- # every 5 seconds.
- wait = Wait(marionette, timeout=30, interval=5,
- ignored_exceptions=errors.NoSuchWindowException)
- window = wait.until(lambda m: m.switch_to_window(42))
-
- :param marionette: The input value to be provided to
- conditions, usually a Marionette instance.
-
- :param timeout: How long to wait for the evaluated condition
- to become true. The default timeout is
- `wait.DEFAULT_TIMEOUT`.
-
- :param interval: How often the condition should be evaluated.
- In reality the interval may be greater as the cost of
- evaluating the condition function. If that is not the case the
- interval for the next condition function call is shortend to keep
- the original interval sequence as best as possible.
- The default polling interval is `wait.DEFAULT_INTERVAL`.
-
- :param ignored_exceptions: Ignore specific types of exceptions
- whilst waiting for the condition. Any exceptions not
- whitelisted will be allowed to propagate, terminating the
- wait.
-
- :param clock: Allows overriding the use of the runtime's
- default time library. See `wait.SystemClock` for
- implementation details.
-
- """
-
- self.marionette = marionette
- self.timeout = timeout
- self.clock = clock or SystemClock()
- self.end = self.clock.now + self.timeout
- self.interval = interval
-
- exceptions = []
- if ignored_exceptions is not None:
- if isinstance(ignored_exceptions, collections.Iterable):
- exceptions.extend(iter(ignored_exceptions))
- else:
- exceptions.append(ignored_exceptions)
- self.exceptions = tuple(set(exceptions))
-
- def until(self, condition, is_true=None, message=""):
- """Repeatedly runs condition until its return value evaluates to true,
- or its timeout expires or the predicate evaluates to true.
-
- This will poll at the given interval until the given timeout
- is reached, or the predicate or conditions returns true. A
- condition that returns null or does not evaluate to true will
- fully elapse its timeout before raising an
- `errors.TimeoutException`.
-
- If an exception is raised in the condition function and it's
- not ignored, this function will raise immediately. If the
- exception is ignored, it will continue polling for the
- condition until it returns successfully or a
- `TimeoutException` is raised.
-
- :param condition: A callable function whose return value will
- be returned by this function if it evaluates to true.
-
- :param is_true: An optional predicate that will terminate and
- return when it evaluates to False. It should be a
- function that will be passed clock and an end time. The
- default predicate will terminate a wait when the clock
- elapses the timeout.
-
- :param message: An optional message to include in the
- exception's message if this function times out.
-
- """
-
- rv = None
- last_exc = None
- until = is_true or until_pred
- start = self.clock.now
-
- while not until(self.clock, self.end):
- try:
- next = self.clock.now + self.interval
- rv = condition(self.marionette)
- except (KeyboardInterrupt, SystemExit):
- raise
- except self.exceptions:
- last_exc = sys.exc_info()
-
- # Re-adjust the interval depending on how long the callback
- # took to evaluate the condition
- interval_new = max(next - self.clock.now, 0)
-
- if not rv:
- self.clock.sleep(interval_new)
- continue
-
- if rv is not None:
- return rv
-
- self.clock.sleep(interval_new)
-
- if message:
- message = " with message: {}".format(message)
-
- raise errors.TimeoutException(
- "Timed out after {0} seconds{1}".format(round((self.clock.now - start), 1),
- message if message else ""),
- cause=last_exc)
-
-
-def until_pred(clock, end):
- return clock.now >= end
-
-
-class SystemClock(object):
-
- def __init__(self):
- self._time = time
-
- def sleep(self, duration):
- self._time.sleep(duration)
-
- @property
- def now(self):
- return self._time.time()
diff --git a/testing/marionette/client/requirements.txt b/testing/marionette/client/requirements.txt
deleted file mode 100644
index a06a719acf..0000000000
--- a/testing/marionette/client/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-mozrunner >= 6.13
-mozversion >= 1.1
diff --git a/testing/marionette/client/setup.py b/testing/marionette/client/setup.py
deleted file mode 100644
index b73b17d08a..0000000000
--- a/testing/marionette/client/setup.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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
-import re
-from setuptools import setup, find_packages
-
-THIS_DIR = os.path.dirname(os.path.realpath(__name__))
-
-
-def read(*parts):
- with open(os.path.join(THIS_DIR, *parts)) as f:
- return f.read()
-
-
-def get_version():
- return re.findall("__version__ = '([\d\.]+)'",
- read('marionette_driver', '__init__.py'), re.M)[0]
-
-
-setup(name='marionette_driver',
- version=get_version(),
- description="Marionette Driver",
- long_description='See http://marionette-client.readthedocs.org/en/latest/',
- # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
- 'Operating System :: MacOS :: MacOS X',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: POSIX',
- 'Topic :: Software Development :: Quality Assurance',
- 'Topic :: Software Development :: Testing',
- 'Topic :: Utilities',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2.7',
- ],
- keywords='mozilla',
- author='Auto-tools',
- author_email='tools-marionette@lists.mozilla.org',
- url='https://wiki.mozilla.org/Auto-tools/Projects/Marionette',
- license='MPL',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=read('requirements.txt').splitlines(),
- )
diff --git a/testing/marionette/components/marionette.js b/testing/marionette/components/marionette.js
deleted file mode 100644
index 252252823b..0000000000
--- a/testing/marionette/components/marionette.js
+++ /dev/null
@@ -1,237 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {Constructor: CC, interfaces: Ci, utils: Cu, classes: Cc} = Components;
-
-const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1";
-const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
-
-const DEFAULT_PORT = 2828;
-const ENABLED_PREF = "marionette.defaultPrefs.enabled";
-const PORT_PREF = "marionette.defaultPrefs.port";
-const FORCELOCAL_PREF = "marionette.force-local";
-const LOG_PREF = "marionette.logging";
-
-/**
- * Besides starting based on existing prefs in a profile and a commandline flag,
- * we also support inheriting prefs out of an env var, and to start marionette
- * that way.
- * This allows marionette prefs to persist when we do a restart into a
- * different profile in order to test things like Firefox refresh.
- * The env var itself, if present, is interpreted as a JSON structure, with the
- * keys mapping to preference names in the "marionette." branch, and the values
- * to the values of those prefs. So something like {"defaultPrefs.enabled": true}
- * in the env var would result in the marionette.defaultPrefs.enabled pref being
- * set to true, thus triggering marionette being enabled for that startup.
- */
-const ENV_PREF_VAR = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
-
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
- "nsIServerSocket",
- "initSpecialConnection");
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function MarionetteComponent() {
- this.loaded_ = false;
- this.observerService = Services.obs;
- this.logger = this.setupLogger_(this.determineLoggingLevel_());
-}
-
-MarionetteComponent.prototype = {
- classDescription: "Marionette component",
- classID: MARIONETTE_CID,
- contractID: MARIONETTE_CONTRACTID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler, Ci.nsIObserver]),
- _xpcom_categories: [
- {category: "command-line-handler", entry: "b-marionette"},
- {category: "profile-after-change", service: true}
- ],
- enabled: false,
- finalUiStartup: false,
- server: null,
-};
-
-MarionetteComponent.prototype.setupLogger_ = function (level) {
- let log = Log.repository.getLogger("Marionette");
- log.level = level;
- log.addAppender(new Log.DumpAppender());
- return log;
-};
-
-MarionetteComponent.prototype.determineLoggingLevel_ = function() {
- let level = Log.Level.Info;
-
- // marionette.logging pref can override default
- // with an entry from the Log.Level enum
- if (Preferences.has(LOG_PREF)) {
- let p = Preferences.get(LOG_PREF);
-
- switch (typeof p) {
- // Gecko >= 46
- case "string":
- let s = p.toLowerCase();
- s = s.charAt(0).toUpperCase() + s.slice(1);
- level = Log.Level[s];
- break;
-
- // Gecko <= 45
- case "boolean":
- if (p) {
- level = Log.Level.Trace;
- }
- break;
- }
- }
-
- return level;
-};
-
-MarionetteComponent.prototype.onSocketAccepted = function(
- socket, transport) {
- this.logger.info("onSocketAccepted for Marionette dummy socket");
-};
-
-MarionetteComponent.prototype.onStopListening = function (socket, status) {
- this.logger.info(`onStopListening for Marionette dummy socket, code ${status}`);
- socket.close();
-};
-
-/** Check cmdLine argument for {@code --marionette}. */
-MarionetteComponent.prototype.handle = function (cmdLine) {
- // if the CLI is there then lets do work otherwise nothing to see
- if (cmdLine.handleFlag("marionette", false)) {
- this.enabled = true;
- this.logger.debug("Marionette enabled via command-line flag");
- this.init();
- }
-};
-
-MarionetteComponent.prototype.observe = function (subj, topic, data) {
- switch (topic) {
- case "profile-after-change":
- this.maybeReadPrefsFromEnvironment();
- // Using final-ui-startup as the xpcom category doesn't seem to work,
- // so we wait for that by adding an observer here.
- this.observerService.addObserver(this, "final-ui-startup", false);
-#ifdef ENABLE_MARIONETTE
- this.enabled = Preferences.get(ENABLED_PREF, false);
- if (this.enabled) {
- this.logger.debug("Marionette enabled via build flag and pref");
-
- // We want to suppress the modal dialog that's shown
- // when starting up in safe-mode to enable testing.
- if (Services.appinfo.inSafeMode) {
- this.observerService.addObserver(this, "domwindowopened", false);
- }
- }
-#endif
- break;
-
- case "final-ui-startup":
- this.finalUiStartup = true;
- this.observerService.removeObserver(this, topic);
- this.observerService.addObserver(this, "xpcom-shutdown", false);
- this.init();
- break;
-
- case "domwindowopened":
- this.observerService.removeObserver(this, topic);
- this.suppressSafeModeDialog_(subj);
- break;
-
- case "xpcom-shutdown":
- this.observerService.removeObserver(this, "xpcom-shutdown");
- this.uninit();
- break;
- }
-};
-
-MarionetteComponent.prototype.maybeReadPrefsFromEnvironment = function() {
- let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- if (env.exists(ENV_PREF_VAR)) {
- let prefStr = env.get(ENV_PREF_VAR);
- let prefs;
- try {
- prefs = JSON.parse(prefStr);
- } catch (ex) {
- Cu.reportError("Invalid marionette prefs in environment; prefs won't have been applied.");
- Cu.reportError(ex);
- }
- if (prefs) {
- for (let prefName of Object.keys(prefs)) {
- Preferences.set("marionette." + prefName, prefs[prefName]);
- }
- }
- }
-}
-
-MarionetteComponent.prototype.suppressSafeModeDialog_ = function (win) {
- // Wait for the modal dialog to finish loading.
- win.addEventListener("load", function onload() {
- win.removeEventListener("load", onload);
-
- if (win.document.getElementById("safeModeDialog")) {
- // Accept the dialog to start in safe-mode
- win.setTimeout(() => {
- win.document.documentElement.getButton("accept").click();
- });
- }
- });
-};
-
-MarionetteComponent.prototype.init = function() {
- if (this.loaded_ || !this.enabled || !this.finalUiStartup) {
- return;
- }
-
- this.loaded_ = true;
-
- let forceLocal = Preferences.get(FORCELOCAL_PREF,
- Services.appinfo.name == "B2G" ? false : true);
- Preferences.set(FORCELOCAL_PREF, forceLocal);
-
- if (!forceLocal) {
- // See bug 800138. Because the first socket that opens with
- // force-local=false fails, we open a dummy socket that will fail.
- // keepWhenOffline=true so that it still work when offline (local).
- // This allows the following attempt by Marionette to open a socket
- // to succeed.
- let insaneSacrificialGoat =
- new ServerSocket(666, Ci.nsIServerSocket.KeepWhenOffline, 4);
- insaneSacrificialGoat.asyncListen(this);
- }
-
- let port = Preferences.get(PORT_PREF, DEFAULT_PORT);
-
- let s;
- try {
- Cu.import("chrome://marionette/content/server.js");
- s = new MarionetteServer(port, forceLocal);
- s.start();
- this.logger.info(`Listening on port ${s.port}`);
- } catch (e) {
- this.logger.error(`Error on starting server: ${e}`);
- dump(e.toString() + "\n" + e.stack + "\n");
- } finally {
- if (s) {
- this.server = s;
- }
- }
-};
-
-MarionetteComponent.prototype.uninit = function() {
- if (!this.loaded_) {
- return;
- }
- this.server.stop();
- this.loaded_ = false;
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
diff --git a/testing/marionette/components/marionette.manifest b/testing/marionette/components/marionette.manifest
deleted file mode 100644
index ebe904960d..0000000000
--- a/testing/marionette/components/marionette.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-component {786a1369-dca5-4adc-8486-33d23c88010a} marionette.js
-contract @mozilla.org/marionette;1 {786a1369-dca5-4adc-8486-33d23c88010a}
-category command-line-handler b-marionette @mozilla.org/marionette;1
-category profile-after-change Marionette @mozilla.org/marionette;1
diff --git a/testing/marionette/components/moz.build b/testing/marionette/components/moz.build
deleted file mode 100644
index 7fc4113a5a..0000000000
--- a/testing/marionette/components/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# 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/.
-
-EXTRA_COMPONENTS += ["marionette.manifest"]
-EXTRA_PP_COMPONENTS += ["marionette.js"]
-
-if CONFIG["ENABLE_MARIONETTE"]:
- DEFINES["ENABLE_MARIONETTE"] = 1
diff --git a/testing/marionette/cookies.js b/testing/marionette/cookies.js
deleted file mode 100644
index 5bd385aa28..0000000000
--- a/testing/marionette/cookies.js
+++ /dev/null
@@ -1,131 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("chrome://marionette/content/error.js");
-
-const logger = Log.repository.getLogger("Marionette");
-
-this.EXPORTED_SYMBOLS = ["Cookies"];
-
-const IPV4_PORT_EXPR = /:\d+$/;
-
-/**
- * Interface for manipulating cookies from content space.
- */
-this.Cookies = class {
-
- /**
- * @param {function(): Document} documentFn
- * Closure that returns the current content document.
- * @param {Proxy(SyncChromeSender)} chromeProxy
- * A synchronous proxy interface to chrome space.
- */
- constructor(documentFn, chromeProxy) {
- this.documentFn_ = documentFn;
- this.chrome = chromeProxy;
- }
-
- get document() {
- return this.documentFn_();
- }
-
- [Symbol.iterator]() {
- let path = this.document.location.pathname || "/";
- let cs = this.chrome.getVisibleCookies(path, this.document.location.hostname)[0];
- return cs[Symbol.iterator]();
- }
-
- /**
- * Add a new cookie to a content document.
- *
- * @param {string} name
- * Cookie key.
- * @param {string} value
- * Cookie value.
- * @param {Object.<string, ?>} opts
- * An object with the optional fields {@code domain}, {@code path},
- * {@code secure}, {@code httpOnly}, and {@code expiry}.
- *
- * @return {Object.<string, ?>}
- * A serialisation of the cookie that was added.
- *
- * @throws UnableToSetCookieError
- * If the document's content type isn't HTML, the current document's
- * domain is a mismatch to the cookie's provided domain, or there
- * otherwise was issues with the input data.
- */
- add(name, value, opts={}) {
- if (typeof this.document == "undefined" || !this.document.contentType.match(/html/i)) {
- throw new UnableToSetCookieError(
- "You may only set cookies on HTML documents: " + this.document.contentType);
- }
-
- if (!opts.expiry) {
- // date twenty years into future, in seconds
- let date = new Date();
- let now = new Date(Date.now());
- date.setYear(now.getFullYear() + 20);
- opts.expiry = date.getTime() / 1000;
- }
-
- if (!opts.domain) {
- opts.domain = this.document.location.host;
- } else if (this.document.location.host.indexOf(opts.domain) < 0) {
- throw new InvalidCookieDomainError(
- "You may only set cookies for the current domain");
- }
-
- // remove port from domain, if present.
- // unfortunately this catches IPv6 addresses by mistake
- // TODO: Bug 814416
- opts.domain = opts.domain.replace(IPV4_PORT_EXPR, "");
-
- let cookie = {
- domain: opts.domain,
- path: opts.path,
- name: name,
- value: value,
- secure: opts.secure,
- httpOnly: opts.httpOnly,
- session: false,
- expiry: opts.expiry,
- };
- if (!this.chrome.addCookie(cookie)) {
- throw new UnableToSetCookieError();
- }
-
- return cookie;
- }
-
- /**
- * Delete cookie by reference or by name.
- *
- * @param {(string|Object.<string, ?>)} cookie
- * Name of cookie or cookie object.
- *
- * @throws {UnknownError}
- * If unable to delete the cookie.
- */
- delete(cookie) {
- let name;
- if (cookie.hasOwnProperty("name")) {
- name = cookie.name;
- } else {
- name = cookie;
- }
-
- for (let candidate of this) {
- if (candidate.name == name) {
- if (!this.chrome.deleteCookie(candidate)) {
- throw new UnknownError("Unable to delete cookie by name: " + name);
- }
- }
- }
- }
-};
diff --git a/testing/marionette/dispatcher.js b/testing/marionette/dispatcher.js
deleted file mode 100644
index 1f09ef8bf8..0000000000
--- a/testing/marionette/dispatcher.js
+++ /dev/null
@@ -1,228 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/driver.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/message.js");
-
-this.EXPORTED_SYMBOLS = ["Dispatcher"];
-
-const PROTOCOL_VERSION = 3;
-
-const logger = Log.repository.getLogger("Marionette");
-
-/**
- * Manages a Marionette connection, and dispatches packets received to
- * their correct destinations.
- *
- * @param {number} connId
- * Unique identifier of the connection this dispatcher should handle.
- * @param {DebuggerTransport} transport
- * Debugger transport connection to the client.
- * @param {function(): GeckoDriver} driverFactory
- * A factory function that produces a GeckoDriver.
- */
-this.Dispatcher = function (connId, transport, driverFactory) {
- this.connId = connId;
- this.conn = transport;
-
- // transport hooks are Dispatcher#onPacket
- // and Dispatcher#onClosed
- this.conn.hooks = this;
-
- // callback for when connection is closed
- this.onclose = null;
-
- // last received/sent message ID
- this.lastId = 0;
-
- this.driver = driverFactory();
-
- // lookup of commands sent by server to client by message ID
- this.commands_ = new Map();
-};
-
-/**
- * Debugger transport callback that cleans up
- * after a connection is closed.
- */
-Dispatcher.prototype.onClosed = function (reason) {
- this.driver.deleteSession();
- if (this.onclose) {
- this.onclose(this);
- }
-};
-
-/**
- * Callback that receives data packets from the client.
- *
- * If the message is a Response, we look up the command previously issued
- * to the client and run its callback, if any. In case of a Command,
- * the corresponding is executed.
- *
- * @param {Array.<number, number, ?, ?>} data
- * A four element array where the elements, in sequence, signifies
- * message type, message ID, method name or error, and parameters
- * or result.
- */
-Dispatcher.prototype.onPacket = function (data) {
- let msg = Message.fromMsg(data);
- msg.origin = MessageOrigin.Client;
- this.log_(msg);
-
- if (msg instanceof Response) {
- let cmd = this.commands_.get(msg.id);
- this.commands_.delete(msg.id);
- cmd.onresponse(msg);
- } else if (msg instanceof Command) {
- this.lastId = msg.id;
- this.execute(msg);
- }
-};
-
-/**
- * Executes a WebDriver command and sends back a response when it has
- * finished executing.
- *
- * Commands implemented in GeckoDriver and registered in its
- * {@code GeckoDriver.commands} attribute. The return values from
- * commands are expected to be Promises. If the resolved value of said
- * promise is not an object, the response body will be wrapped in an object
- * under a "value" field.
- *
- * If the command implementation sends the response itself by calling
- * {@code resp.send()}, the response is guaranteed to not be sent twice.
- *
- * Errors thrown in commands are marshaled and sent back, and if they
- * are not WebDriverError instances, they are additionally propagated and
- * reported to {@code Components.utils.reportError}.
- *
- * @param {Command} cmd
- * The requested command to execute.
- */
-Dispatcher.prototype.execute = function (cmd) {
- let resp = new Response(cmd.id, this.send.bind(this));
- let sendResponse = () => resp.sendConditionally(resp => !resp.sent);
- let sendError = resp.sendError.bind(resp);
-
- let req = Task.spawn(function*() {
- let fn = this.driver.commands[cmd.name];
- if (typeof fn == "undefined") {
- throw new UnknownCommandError(cmd.name);
- }
-
- if (cmd.name !== "newSession") {
- assert.session(this.driver);
- }
-
- let rv = yield fn.bind(this.driver)(cmd, resp);
-
- if (typeof rv != "undefined") {
- if (typeof rv != "object") {
- resp.body = {value: rv};
- } else {
- resp.body = rv;
- }
- }
- }.bind(this));
-
- req.then(sendResponse, sendError).catch(error.report);
-};
-
-Dispatcher.prototype.sendError = function (err, cmdId) {
- let resp = new Response(cmdId, this.send.bind(this));
- resp.sendError(err);
-};
-
-// Convenience methods:
-
-/**
- * When a client connects we send across a JSON Object defining the
- * protocol level.
- *
- * This is the only message sent by Marionette that does not follow
- * the regular message format.
- */
-Dispatcher.prototype.sayHello = function() {
- let whatHo = {
- applicationType: "gecko",
- marionetteProtocol: PROTOCOL_VERSION,
- };
- this.sendRaw(whatHo);
-};
-
-
-/**
- * Delegates message to client based on the provided {@code cmdId}.
- * The message is sent over the debugger transport socket.
- *
- * The command ID is a unique identifier assigned to the client's request
- * that is used to distinguish the asynchronous responses.
- *
- * Whilst responses to commands are synchronous and must be sent in the
- * correct order.
- *
- * @param {Command,Response} msg
- * The command or response to send.
- */
-Dispatcher.prototype.send = function (msg) {
- msg.origin = MessageOrigin.Server;
- if (msg instanceof Command) {
- this.commands_.set(msg.id, msg);
- this.sendToEmulator(msg);
- } else if (msg instanceof Response) {
- this.sendToClient(msg);
- }
-};
-
-// Low-level methods:
-
-/**
- * Send given response to the client over the debugger transport socket.
- *
- * @param {Response} resp
- * The response to send back to the client.
- */
-Dispatcher.prototype.sendToClient = function (resp) {
- this.driver.responseCompleted();
- this.sendMessage(resp);
-};
-
-/**
- * Marshal message to the Marionette message format and send it.
- *
- * @param {Command,Response} msg
- * The message to send.
- */
-Dispatcher.prototype.sendMessage = function (msg) {
- this.log_(msg);
- let payload = msg.toMsg();
- this.sendRaw(payload);
-};
-
-/**
- * Send the given payload over the debugger transport socket to the
- * connected client.
- *
- * @param {Object} payload
- * The payload to ship.
- */
-Dispatcher.prototype.sendRaw = function (payload) {
- this.conn.send(payload);
-};
-
-Dispatcher.prototype.log_ = function (msg) {
- let a = (msg.origin == MessageOrigin.Client ? " -> " : " <- ");
- let s = JSON.stringify(msg.toMsg());
- logger.trace(this.connId + a + s);
-};
diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js
deleted file mode 100644
index 7ef72d3bb9..0000000000
--- a/testing/marionette/driver.js
+++ /dev/null
@@ -1,2907 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Ci.mozIJSSubScriptLoader);
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(
- this, "cookieManager", "@mozilla.org/cookiemanager;1", "nsICookieManager2");
-
-Cu.import("chrome://marionette/content/accessibility.js");
-Cu.import("chrome://marionette/content/addon.js");
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/atom.js");
-Cu.import("chrome://marionette/content/browser.js");
-Cu.import("chrome://marionette/content/capture.js");
-Cu.import("chrome://marionette/content/cert.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/evaluate.js");
-Cu.import("chrome://marionette/content/event.js");
-Cu.import("chrome://marionette/content/interaction.js");
-Cu.import("chrome://marionette/content/l10n.js");
-Cu.import("chrome://marionette/content/legacyaction.js");
-Cu.import("chrome://marionette/content/logging.js");
-Cu.import("chrome://marionette/content/modal.js");
-Cu.import("chrome://marionette/content/proxy.js");
-Cu.import("chrome://marionette/content/session.js");
-Cu.import("chrome://marionette/content/simpletest.js");
-
-this.EXPORTED_SYMBOLS = ["GeckoDriver", "Context"];
-
-var FRAME_SCRIPT = "chrome://marionette/content/listener.js";
-const BROWSER_STARTUP_FINISHED = "browser-delayed-startup-finished";
-const CLICK_TO_START_PREF = "marionette.debugging.clicktostart";
-const CONTENT_LISTENER_PREF = "marionette.contentListener";
-
-const SUPPORTED_STRATEGIES = new Set([
- element.Strategy.ClassName,
- element.Strategy.Selector,
- element.Strategy.ID,
- element.Strategy.TagName,
- element.Strategy.XPath,
- element.Strategy.Anon,
- element.Strategy.AnonAttribute,
-]);
-
-const logger = Log.repository.getLogger("Marionette");
-const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
- .getService(Ci.nsIMessageBroadcaster);
-
-// This is used to prevent newSession from returning before the telephony
-// API's are ready; see bug 792647. This assumes that marionette-server.js
-// will be loaded before the 'system-message-listener-ready' message
-// is fired. If this stops being true, this approach will have to change.
-var systemMessageListenerReady = false;
-Services.obs.addObserver(function() {
- systemMessageListenerReady = true;
-}, "system-message-listener-ready", false);
-
-// This is used on desktop to prevent newSession from returning before a page
-// load initiated by the Firefox command line has completed.
-var delayedBrowserStarted = false;
-Services.obs.addObserver(function () {
- delayedBrowserStarted = true;
-}, BROWSER_STARTUP_FINISHED, false);
-
-this.Context = {
- CHROME: "chrome",
- CONTENT: "content",
-};
-
-this.Context.fromString = function (s) {
- s = s.toUpperCase();
- if (s in this) {
- return this[s];
- }
- return null;
-};
-
-/**
- * Implements (parts of) the W3C WebDriver protocol. GeckoDriver lives
- * in chrome space and mediates calls to the message listener of the current
- * browsing context's content frame message listener via ListenerProxy.
- *
- * Throughout this prototype, functions with the argument {@code cmd}'s
- * documentation refers to the contents of the {@code cmd.parameters}
- * object.
- *
- * @param {string} appName
- * Description of the product, for example "B2G" or "Firefox".
- * @param {MarionetteServer} server
- * The instance of Marionette server.
- */
-this.GeckoDriver = function (appName, server) {
- this.appName = appName;
- this._server = server;
-
- this.sessionId = null;
- this.wins = new browser.Windows();
- this.browsers = {};
- // points to current browser
- this.curBrowser = null;
- // topmost chrome frame
- this.mainFrame = null;
- // chrome iframe that currently has focus
- this.curFrame = null;
- this.mainContentFrameId = null;
- this.mozBrowserClose = null;
- this.currentFrameElement = null;
- // frame ID of the current remote frame, used for mozbrowserclose events
- this.oopFrameId = null;
- this.observing = null;
- this._browserIds = new WeakMap();
-
- // The curent context decides if commands should affect chrome- or
- // content space.
- this.context = Context.CONTENT;
-
- this.importedScripts = new evaluate.ScriptStorageService(
- [Context.CHROME, Context.CONTENT]);
- this.sandboxes = new Sandboxes(() => this.getCurrentWindow());
- this.legacyactions = new legacyaction.Chain();
-
- this.timer = null;
- this.inactivityTimer = null;
-
- this.marionetteLog = new logging.ContentLogger();
- this.testName = null;
-
- this.capabilities = new session.Capabilities();
-
- this.mm = globalMessageManager;
- this.listener = proxy.toListener(() => this.mm, this.sendAsync.bind(this));
-
- // always keep weak reference to current dialogue
- this.dialog = null;
- let handleDialog = (subject, topic) => {
- let winr;
- if (topic == modal.COMMON_DIALOG_LOADED) {
- winr = Cu.getWeakReference(subject);
- }
- this.dialog = new modal.Dialog(() => this.curBrowser, winr);
- };
- modal.addHandler(handleDialog);
-};
-
-Object.defineProperty(GeckoDriver.prototype, "a11yChecks", {
- get: function () {
- return this.capabilities.get("moz:accessibilityChecks");
- }
-});
-
-Object.defineProperty(GeckoDriver.prototype, "proxy", {
- get: function () {
- return this.capabilities.get("proxy");
- }
-});
-
-Object.defineProperty(GeckoDriver.prototype, "secureTLS", {
- get: function () {
- return !this.capabilities.get("acceptInsecureCerts");
- }
-});
-
-Object.defineProperty(GeckoDriver.prototype, "timeouts", {
- get: function () {
- return this.capabilities.get("timeouts");
- },
-
- set: function (newTimeouts) {
- this.capabilities.set("timeouts", newTimeouts);
- },
-});
-
-Object.defineProperty(GeckoDriver.prototype, "windowHandles", {
- get: function () {
- let hs = [];
- let winEn = Services.wm.getEnumerator(null);
-
- while (winEn.hasMoreElements()) {
- let win = winEn.getNext();
- let tabBrowser = browser.getTabBrowser(win);
-
- if (tabBrowser) {
- tabBrowser.tabs.forEach(tab => {
- let winId = this.getIdForBrowser(browser.getBrowserForTab(tab));
- if (winId !== null) {
- hs.push(winId);
- }
- });
- } else {
- // For other chrome windows beside the browser window, only add the window itself.
- hs.push(getOuterWindowId(win));
- }
- }
-
- return hs;
- },
-});
-
-Object.defineProperty(GeckoDriver.prototype, "chromeWindowHandles", {
- get : function () {
- let hs = [];
- let winEn = Services.wm.getEnumerator(null);
-
- while (winEn.hasMoreElements()) {
- hs.push(getOuterWindowId(winEn.getNext()));
- }
-
- return hs;
- },
-});
-
-GeckoDriver.prototype.QueryInterface = XPCOMUtils.generateQI([
- Ci.nsIMessageListener,
- Ci.nsIObserver,
- Ci.nsISupportsWeakReference,
-]);
-
-/**
- * Switches to the global ChromeMessageBroadcaster, potentially replacing
- * a frame-specific ChromeMessageSender. Has no effect if the global
- * ChromeMessageBroadcaster is already in use. If this replaces a
- * frame-specific ChromeMessageSender, it removes the message listeners
- * from that sender, and then puts the corresponding frame script "to
- * sleep", which removes most of the message listeners from it as well.
- */
-GeckoDriver.prototype.switchToGlobalMessageManager = function() {
- if (this.curBrowser && this.curBrowser.frameManager.currentRemoteFrame !== null) {
- this.curBrowser.frameManager.removeMessageManagerListeners(this.mm);
- this.sendAsync("sleepSession");
- this.curBrowser.frameManager.currentRemoteFrame = null;
- }
- this.mm = globalMessageManager;
-};
-
-/**
- * Helper method to send async messages to the content listener.
- * Correct usage is to pass in the name of a function in listener.js,
- * a serialisable object, and optionally the current command's ID
- * when not using the modern dispatching technique.
- *
- * @param {string} name
- * Suffix of the targetted message listener
- * ({@code Marionette:<suffix>}).
- * @param {Object=} msg
- * Optional JSON serialisable object to send to the listener.
- * @param {number=} commandID
- * Optional command ID to ensure synchronisity.
- */
-GeckoDriver.prototype.sendAsync = function (name, data, commandID) {
- name = "Marionette:" + name;
- let payload = copy(data);
-
- // TODO(ato): When proxy.AsyncMessageChannel
- // is used for all chrome <-> content communication
- // this can be removed.
- if (commandID) {
- payload.command_id = commandID;
- }
-
- if (!this.curBrowser.frameManager.currentRemoteFrame) {
- this.broadcastDelayedAsyncMessage_(name, payload);
- } else {
- this.sendTargettedAsyncMessage_(name, payload);
- }
-};
-
-GeckoDriver.prototype.broadcastDelayedAsyncMessage_ = function (name, payload) {
- this.curBrowser.executeWhenReady(() => {
- if (this.curBrowser.curFrameId) {
- const target = name + this.curBrowser.curFrameId;
- this.mm.broadcastAsyncMessage(target, payload);
- } else {
- throw new NoSuchWindowError(
- "No such content frame; perhaps the listener was not registered?");
- }
- });
-};
-
-GeckoDriver.prototype.sendTargettedAsyncMessage_ = function (name, payload) {
- const curRemoteFrame = this.curBrowser.frameManager.currentRemoteFrame;
- const target = name + curRemoteFrame.targetFrameId;
-
- try {
- this.mm.sendAsyncMessage(target, payload);
- } catch (e) {
- switch (e.result) {
- case Cr.NS_ERROR_FAILURE:
- case Cr.NS_ERROR_NOT_INITIALIZED:
- throw new NoSuchWindowError();
-
- default:
- throw new WebDriverError(e);
- }
- }
-};
-
-/**
- * Gets the current active window.
- *
- * @return {nsIDOMWindow}
- */
-GeckoDriver.prototype.getCurrentWindow = function() {
- let typ = null;
- if (this.curFrame === null) {
- if (this.curBrowser === null) {
- if (this.context == Context.CONTENT) {
- typ = "navigator:browser";
- }
- return Services.wm.getMostRecentWindow(typ);
- } else {
- return this.curBrowser.window;
- }
- } else {
- return this.curFrame;
- }
-};
-
-GeckoDriver.prototype.addFrameCloseListener = function (action) {
- let win = this.getCurrentWindow();
- this.mozBrowserClose = e => {
- if (e.target.id == this.oopFrameId) {
- win.removeEventListener("mozbrowserclose", this.mozBrowserClose, true);
- this.switchToGlobalMessageManager();
- throw new NoSuchWindowError("The window closed during action: " + action);
- }
- };
- win.addEventListener("mozbrowserclose", this.mozBrowserClose, true);
-};
-
-/**
- * Create a new browsing context for window and add to known browsers.
- *
- * @param {nsIDOMWindow} win
- * Window for which we will create a browsing context.
- *
- * @return {string}
- * Returns the unique server-assigned ID of the window.
- */
-GeckoDriver.prototype.addBrowser = function (win) {
- let bc = new browser.Context(win, this);
- let winId = getOuterWindowId(win);
-
- this.browsers[winId] = bc;
- this.curBrowser = this.browsers[winId];
- if (!this.wins.has(winId)) {
- // add this to seenItems so we can guarantee
- // the user will get winId as this window's id
- this.wins.set(winId, win);
- }
-};
-
-/**
- * Registers a new browser, win, with Marionette.
- *
- * If we have not seen the browser content window before, the listener
- * frame script will be loaded into it. If isNewSession is true, we will
- * switch focus to the start frame when it registers.
- *
- * @param {nsIDOMWindow} win
- * Window whose browser we need to access.
- * @param {boolean=false} isNewSession
- * True if this is the first time we're talking to this browser.
- */
-GeckoDriver.prototype.startBrowser = function (win, isNewSession = false) {
- this.mainFrame = win;
- this.curFrame = null;
- this.addBrowser(win);
- this.curBrowser.isNewSession = isNewSession;
- this.curBrowser.startSession(isNewSession, win, this.whenBrowserStarted.bind(this));
-};
-
-/**
- * Callback invoked after a new session has been started in a browser.
- * Loads the Marionette frame script into the browser if needed.
- *
- * @param {nsIDOMWindow} win
- * Window whose browser we need to access.
- * @param {boolean} isNewSession
- * True if this is the first time we're talking to this browser.
- */
-GeckoDriver.prototype.whenBrowserStarted = function (win, isNewSession) {
- let mm = win.window.messageManager;
- if (mm) {
- if (!isNewSession) {
- // Loading the frame script corresponds to a situation we need to
- // return to the server. If the messageManager is a message broadcaster
- // with no children, we don't have a hope of coming back from this call,
- // so send the ack here. Otherwise, make a note of how many child scripts
- // will be loaded so we known when it's safe to return.
- // Child managers may not have child scripts yet (e.g. socialapi), only
- // count child managers that have children, but only count the top level
- // children as they are the ones that we expect a response from.
- if (mm.childCount !== 0) {
- this.curBrowser.frameRegsPending = 0;
- for (let i = 0; i < mm.childCount; i++) {
- if (mm.getChildAt(i).childCount !== 0) {
- this.curBrowser.frameRegsPending += 1;
- }
- }
- }
- }
-
- if (!Preferences.get(CONTENT_LISTENER_PREF) || !isNewSession) {
- // load listener into the remote frame
- // and any applicable new frames
- // opened after this call
- mm.loadFrameScript(FRAME_SCRIPT, true);
- Preferences.set(CONTENT_LISTENER_PREF, true);
- }
- } else {
- logger.error(
- `Could not load listener into content for page ${win.location.href}`);
- }
-};
-
-/**
- * Recursively get all labeled text.
- *
- * @param {nsIDOMElement} el
- * The parent element.
- * @param {Array.<string>} lines
- * Array that holds the text lines.
- */
-GeckoDriver.prototype.getVisibleText = function (el, lines) {
- try {
- if (atom.isElementDisplayed(el, this.getCurrentWindow())) {
- if (el.value) {
- lines.push(el.value);
- }
- for (let child in el.childNodes) {
- this.getVisibleText(el.childNodes[child], lines);
- }
- }
- } catch (e) {
- if (el.nodeName == "#text") {
- lines.push(el.textContent);
- }
- }
-};
-
-/**
- * Handles registration of new content listener browsers. Depending on
- * their type they are either accepted or ignored.
- */
-GeckoDriver.prototype.registerBrowser = function (id, be) {
- let nullPrevious = this.curBrowser.curFrameId === null;
- let listenerWindow = Services.wm.getOuterWindowWithId(id);
-
- // go in here if we're already in a remote frame
- if (this.curBrowser.frameManager.currentRemoteFrame !== null &&
- (!listenerWindow || this.mm == this.curBrowser.frameManager
- .currentRemoteFrame.messageManager.get())) {
- // The outerWindowID from an OOP frame will not be meaningful to
- // the parent process here, since each process maintains its own
- // independent window list. So, it will either be null (!listenerWindow)
- // if we're already in a remote frame, or it will point to some
- // random window, which will hopefully cause an href mismatch.
- // Currently this only happens in B2G for OOP frames registered in
- // Marionette:switchToFrame, so we'll acknowledge the switchToFrame
- // message here.
- //
- // TODO: Should have a better way of determining that this message
- // is from a remote frame.
- this.curBrowser.frameManager.currentRemoteFrame.targetFrameId =
- this.generateFrameId(id);
- }
-
- let reg = {};
- // this will be sent to tell the content process if it is the main content
- let mainContent = this.curBrowser.mainContentId === null;
- if (be.getAttribute("type") != "content") {
- // curBrowser holds all the registered frames in knownFrames
- let uid = this.generateFrameId(id);
- reg.id = uid;
- reg.remotenessChange = this.curBrowser.register(uid, be);
- }
-
- // set to true if we updated mainContentId
- mainContent = mainContent && this.curBrowser.mainContentId !== null;
- if (mainContent) {
- this.mainContentFrameId = this.curBrowser.curFrameId;
- }
-
- this.wins.set(reg.id, listenerWindow);
- if (nullPrevious && (this.curBrowser.curFrameId !== null)) {
- this.sendAsync(
- "newSession",
- this.capabilities.toJSON(),
- this.newSessionCommandId);
- if (this.curBrowser.isNewSession) {
- this.newSessionCommandId = null;
- }
- }
-
- return [reg, mainContent, this.capabilities.toJSON()];
-};
-
-GeckoDriver.prototype.registerPromise = function () {
- const li = "Marionette:register";
-
- return new Promise(resolve => {
- let cb = msg => {
- let wid = msg.json.value;
- let be = msg.target;
- let rv = this.registerBrowser(wid, be);
-
- if (this.curBrowser.frameRegsPending > 0) {
- this.curBrowser.frameRegsPending--;
- }
-
- if (this.curBrowser.frameRegsPending === 0) {
- this.mm.removeMessageListener(li, cb);
- resolve();
- }
-
- // this is a sync message and listeners expect the ID back
- return rv;
- };
- this.mm.addMessageListener(li, cb);
- });
-};
-
-GeckoDriver.prototype.listeningPromise = function () {
- const li = "Marionette:listenersAttached";
- return new Promise(resolve => {
- let cb = () => {
- this.mm.removeMessageListener(li, cb);
- resolve();
- };
- this.mm.addMessageListener(li, cb);
- });
-};
-
-/** Create a new session. */
-GeckoDriver.prototype.newSession = function* (cmd, resp) {
- if (this.sessionId) {
- throw new SessionNotCreatedError("Maximum number of active sessions");
- }
-
- this.sessionId = cmd.parameters.sessionId ||
- cmd.parameters.session_id ||
- element.generateUUID();
- this.newSessionCommandId = cmd.id;
-
- try {
- this.capabilities = session.Capabilities.fromJSON(
- cmd.parameters.capabilities, {merge: true});
- logger.config("Matched capabilities: " +
- JSON.stringify(this.capabilities));
- } catch (e) {
- throw new SessionNotCreatedError(e);
- }
-
- if (!this.secureTLS) {
- logger.warn("TLS certificate errors will be ignored for this session");
- let acceptAllCerts = new cert.InsecureSweepingOverride();
- cert.installOverride(acceptAllCerts);
- }
-
- if (this.proxy.init()) {
- logger.info("Proxy settings initialised: " + JSON.stringify(this.proxy));
- }
-
- // If we are testing accessibility with marionette, start a11y service in
- // chrome first. This will ensure that we do not have any content-only
- // services hanging around.
- if (this.a11yChecks && accessibility.service) {
- logger.info("Preemptively starting accessibility service in Chrome");
- }
-
- let registerBrowsers = this.registerPromise();
- let browserListening = this.listeningPromise();
-
- let waitForWindow = function() {
- let win = this.getCurrentWindow();
- if (!win) {
- // if the window isn't even created, just poll wait for it
- let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- checkTimer.initWithCallback(waitForWindow.bind(this), 100,
- Ci.nsITimer.TYPE_ONE_SHOT);
- } else if (win.document.readyState != "complete") {
- // otherwise, wait for it to be fully loaded before proceeding
- let listener = ev => {
- // ensure that we proceed, on the top level document load event
- // (not an iframe one...)
- if (ev.target != win.document) {
- return;
- }
- win.removeEventListener("load", listener);
- waitForWindow.call(this);
- };
- win.addEventListener("load", listener, true);
- } else {
- let clickToStart = Preferences.get(CLICK_TO_START_PREF);
- if (clickToStart && (this.appName != "B2G")) {
- let pService = Cc["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Ci.nsIPromptService);
- pService.alert(win, "", "Click to start execution of marionette tests");
- }
- this.startBrowser(win, true);
- }
- };
-
- let runSessionStart = function() {
- if (!Preferences.get(CONTENT_LISTENER_PREF)) {
- waitForWindow.call(this);
- } else if (this.appName != "Firefox" && this.curBrowser === null) {
- // if there is a content listener, then we just wake it up
- this.addBrowser(this.getCurrentWindow());
- this.curBrowser.startSession(this.whenBrowserStarted.bind(this));
- this.mm.broadcastAsyncMessage("Marionette:restart", {});
- } else {
- throw new WebDriverError("Session already running");
- }
- this.switchToGlobalMessageManager();
- };
-
- if (!delayedBrowserStarted && this.appName != "B2G") {
- let self = this;
- Services.obs.addObserver(function onStart() {
- Services.obs.removeObserver(onStart, BROWSER_STARTUP_FINISHED);
- runSessionStart.call(self);
- }, BROWSER_STARTUP_FINISHED, false);
- } else {
- runSessionStart.call(this);
- }
-
- yield registerBrowsers;
- yield browserListening;
-
- if (this.curBrowser.tab) {
- browser.getBrowserForTab(this.curBrowser.tab).focus();
- }
-
- return {
- sessionId: this.sessionId,
- capabilities: this.capabilities,
- };
-};
-
-/**
- * Send the current session's capabilities to the client.
- *
- * Capabilities informs the client of which WebDriver features are
- * supported by Firefox and Marionette. They are immutable for the
- * length of the session.
- *
- * The return value is an immutable map of string keys
- * ("capabilities") to values, which may be of types boolean,
- * numerical or string.
- */
-GeckoDriver.prototype.getSessionCapabilities = function (cmd, resp) {
- resp.body.capabilities = this.capabilities;
-};
-
-/**
- * Log message. Accepts user defined log-level.
- *
- * @param {string} value
- * Log message.
- * @param {string} level
- * Arbitrary log level.
- */
-GeckoDriver.prototype.log = function (cmd, resp) {
- // if level is null, we want to use ContentLogger#send's default
- this.marionetteLog.log(
- cmd.parameters.value,
- cmd.parameters.level || undefined);
-};
-
-/** Return all logged messages. */
-GeckoDriver.prototype.getLogs = function (cmd, resp) {
- resp.body = this.marionetteLog.get();
-};
-
-/**
- * Sets the context of the subsequent commands to be either "chrome" or
- * "content".
- *
- * @param {string} value
- * Name of the context to be switched to. Must be one of "chrome" or
- * "content".
- */
-GeckoDriver.prototype.setContext = function (cmd, resp) {
- let val = cmd.parameters.value;
- let ctx = Context.fromString(val);
- if (ctx === null) {
- throw new WebDriverError(`Invalid context: ${val}`);
- }
- this.context = ctx;
-};
-
-/** Gets the context of the server, either "chrome" or "content". */
-GeckoDriver.prototype.getContext = function (cmd, resp) {
- resp.body.value = this.context.toString();
-};
-
-/**
- * Executes a JavaScript function in the context of the current browsing
- * context, if in content space, or in chrome space otherwise, and returns
- * the return value of the function.
- *
- * It is important to note that if the {@code sandboxName} parameter
- * is left undefined, the script will be evaluated in a mutable sandbox,
- * causing any change it makes on the global state of the document to have
- * lasting side-effects.
- *
- * @param {string} script
- * Script to evaluate as a function body.
- * @param {Array.<(string|boolean|number|object|WebElement)>} args
- * Arguments exposed to the script in {@code arguments}. The array
- * items must be serialisable to the WebDriver protocol.
- * @param {number} scriptTimeout
- * Duration in milliseconds of when to interrupt and abort the
- * script evaluation.
- * @param {string=} sandbox
- * Name of the sandbox to evaluate the script in. The sandbox is
- * cached for later re-use on the same Window object if
- * {@code newSandbox} is false. If he parameter is undefined,
- * the script is evaluated in a mutable sandbox. If the parameter
- * is "system", it will be evaluted in a sandbox with elevated system
- * privileges, equivalent to chrome space.
- * @param {boolean=} newSandbox
- * Forces the script to be evaluated in a fresh sandbox. Note that if
- * it is undefined, the script will normally be evaluted in a fresh
- * sandbox.
- * @param {string=} filename
- * Filename of the client's program where this script is evaluated.
- * @param {number=} line
- * Line in the client's program where this script is evaluated.
- * @param {boolean=} debug_script
- * Attach an {@code onerror} event handler on the Window object.
- * It does not differentiate content errors from chrome errors.
- * @param {boolean=} directInject
- * Evaluate the script without wrapping it in a function.
- *
- * @return {(string|boolean|number|object|WebElement)}
- * Return value from the script, or null which signifies either the
- * JavaScript notion of null or undefined.
- *
- * @throws ScriptTimeoutError
- * If the script was interrupted due to reaching the {@code
- * scriptTimeout} or default timeout.
- * @throws JavaScriptError
- * If an Error was thrown whilst evaluating the script.
- */
-GeckoDriver.prototype.executeScript = function*(cmd, resp) {
- let {script, args, scriptTimeout} = cmd.parameters;
- scriptTimeout = scriptTimeout || this.timeouts.script;
-
- let opts = {
- sandboxName: cmd.parameters.sandbox,
- newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
- cmd.parameters.newSandbox,
- filename: cmd.parameters.filename,
- line: cmd.parameters.line,
- debug: cmd.parameters.debug_script,
- };
-
- resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
-};
-
-/**
- * Executes a JavaScript function in the context of the current browsing
- * context, if in content space, or in chrome space otherwise, and returns
- * the object passed to the callback.
- *
- * The callback is always the last argument to the {@code arguments}
- * list passed to the function scope of the script. It can be retrieved
- * as such:
- *
- * let callback = arguments[arguments.length - 1];
- * callback("foo");
- * // "foo" is returned
- *
- * It is important to note that if the {@code sandboxName} parameter
- * is left undefined, the script will be evaluated in a mutable sandbox,
- * causing any change it makes on the global state of the document to have
- * lasting side-effects.
- *
- * @param {string} script
- * Script to evaluate as a function body.
- * @param {Array.<(string|boolean|number|object|WebElement)>} args
- * Arguments exposed to the script in {@code arguments}. The array
- * items must be serialisable to the WebDriver protocol.
- * @param {number} scriptTimeout
- * Duration in milliseconds of when to interrupt and abort the
- * script evaluation.
- * @param {string=} sandbox
- * Name of the sandbox to evaluate the script in. The sandbox is
- * cached for later re-use on the same Window object if
- * {@code newSandbox} is false. If the parameter is undefined,
- * the script is evaluated in a mutable sandbox. If the parameter
- * is "system", it will be evaluted in a sandbox with elevated system
- * privileges, equivalent to chrome space.
- * @param {boolean=} newSandbox
- * Forces the script to be evaluated in a fresh sandbox. Note that if
- * it is undefined, the script will normally be evaluted in a fresh
- * sandbox.
- * @param {string=} filename
- * Filename of the client's program where this script is evaluated.
- * @param {number=} line
- * Line in the client's program where this script is evaluated.
- * @param {boolean=} debug_script
- * Attach an {@code onerror} event handler on the Window object.
- * It does not differentiate content errors from chrome errors.
- * @param {boolean=} directInject
- * Evaluate the script without wrapping it in a function.
- *
- * @return {(string|boolean|number|object|WebElement)}
- * Return value from the script, or null which signifies either the
- * JavaScript notion of null or undefined.
- *
- * @throws ScriptTimeoutError
- * If the script was interrupted due to reaching the {@code
- * scriptTimeout} or default timeout.
- * @throws JavaScriptError
- * If an Error was thrown whilst evaluating the script.
- */
-GeckoDriver.prototype.executeAsyncScript = function* (cmd, resp) {
- let {script, args, scriptTimeout} = cmd.parameters;
- scriptTimeout = scriptTimeout || this.timeouts.script;
-
- let opts = {
- sandboxName: cmd.parameters.sandbox,
- newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
- cmd.parameters.newSandbox,
- filename: cmd.parameters.filename,
- line: cmd.parameters.line,
- debug: cmd.parameters.debug_script,
- async: true,
- };
-
- resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
-};
-
-GeckoDriver.prototype.execute_ = function (script, args, timeout, opts = {}) {
- switch (this.context) {
- case Context.CONTENT:
- // evaluate in content with lasting side-effects
- if (!opts.sandboxName) {
- return this.listener.execute(script, args, timeout, opts);
-
- // evaluate in content with sandbox
- } else {
- return this.listener.executeInSandbox(script, args, timeout, opts);
- }
-
- case Context.CHROME:
- let sb = this.sandboxes.get(opts.sandboxName, opts.newSandbox);
- if (opts.sandboxName) {
- sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
- sb = sandbox.augment(sb, {global: sb});
- }
-
- opts.timeout = timeout;
- script = this.importedScripts.for(Context.CHROME).concat(script);
- let wargs = element.fromJson(args, this.curBrowser.seenEls, sb.window);
- let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
- return evaluatePromise.then(res => element.toJson(res, this.curBrowser.seenEls));
- }
-};
-
-/**
- * Execute pure JavaScript. Used to execute simpletest harness tests,
- * which are like mochitests only injected using Marionette.
- *
- * Scripts are expected to call the {@code finish} global when done.
- */
-GeckoDriver.prototype.executeJSScript = function* (cmd, resp) {
- let {script, args, scriptTimeout} = cmd.parameters;
- scriptTimeout = scriptTimeout || this.timeouts.script;
-
- let opts = {
- filename: cmd.parameters.filename,
- line: cmd.parameters.line,
- async: cmd.parameters.async,
- };
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let wargs = element.fromJson(args, this.curBrowser.seenEls, win);
- let harness = new simpletest.Harness(
- win,
- Context.CHROME,
- this.marionetteLog,
- scriptTimeout,
- function() {},
- this.testName);
-
- let sb = sandbox.createSimpleTest(win, harness);
- // TODO(ato): Not sure this is needed:
- sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
-
- let res = yield evaluate.sandbox(sb, script, wargs, opts);
- resp.body.value = element.toJson(res, this.curBrowser.seenEls);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.executeSimpleTest(script, args, scriptTimeout, opts);
- break;
- }
-};
-
-/**
- * Navigate to given URL.
- *
- * Navigates the current browsing context to the given URL and waits for
- * the document to load or the session's page timeout duration to elapse
- * before returning.
- *
- * The command will return with a failure if there is an error loading
- * the document or the URL is blocked. This can occur if it fails to
- * reach host, the URL is malformed, or if there is a certificate issue
- * to name some examples.
- *
- * The document is considered successfully loaded when the
- * DOMContentLoaded event on the frame element associated with the
- * current window triggers and document.readyState is "complete".
- *
- * In chrome context it will change the current window's location to
- * the supplied URL and wait until document.readyState equals "complete"
- * or the page timeout duration has elapsed.
- *
- * @param {string} url
- * URL to navigate to.
- */
-GeckoDriver.prototype.get = function*(cmd, resp) {
- assert.content(this.context);
-
- let url = cmd.parameters.url;
-
- let get = this.listener.get({url: url, pageTimeout: this.timeouts.pageLoad});
-
- // If a remoteness update interrupts our page load, this will never return
- // We need to re-issue this request to correctly poll for readyState and
- // send errors.
- this.curBrowser.pendingCommands.push(() => {
- let parameters = {
- // TODO(ato): Bug 1242595
- command_id: this.listener.activeMessageId,
- pageTimeout: this.timeouts.pageLoad,
- startTime: new Date().getTime(),
- };
- this.mm.broadcastAsyncMessage(
- "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
- parameters);
- });
-
- yield get;
- browser.getBrowserForTab(this.curBrowser.tab).focus();
-};
-
-/**
- * Get a string representing the current URL.
- *
- * On Desktop this returns a string representation of the URL of the
- * current top level browsing context. This is equivalent to
- * document.location.href.
- *
- * When in the context of the chrome, this returns the canonical URL
- * of the current resource.
- */
-GeckoDriver.prototype.getCurrentUrl = function (cmd) {
- switch (this.context) {
- case Context.CHROME:
- return this.getCurrentWindow().location.href;
-
- case Context.CONTENT:
- let isB2G = this.appName == "B2G";
- return this.listener.getCurrentUrl(isB2G);
- }
-};
-
-/** Gets the current title of the window. */
-GeckoDriver.prototype.getTitle = function* (cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- resp.body.value = win.document.documentElement.getAttribute("title");
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getTitle();
- break;
- }
-};
-
-/** Gets the current type of the window. */
-GeckoDriver.prototype.getWindowType = function (cmd, resp) {
- let win = this.getCurrentWindow();
- resp.body.value = win.document.documentElement.getAttribute("windowtype");
-};
-
-/** Gets the page source of the content document. */
-GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let s = new win.XMLSerializer();
- resp.body.value = s.serializeToString(win.document);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getPageSource();
- break;
- }
-};
-
-/**
- * Cause the browser to traverse one step backward in the joint history
- * of the current browsing context.
- */
-GeckoDriver.prototype.goBack = function* (cmd, resp) {
- assert.content(this.context);
-
- if (!this.curBrowser.tab) {
- // Navigation does not work for non-browser windows
- return;
- }
-
- let contentBrowser = browser.getBrowserForTab(this.curBrowser.tab)
- if (!contentBrowser.webNavigation.canGoBack) {
- return;
- }
-
- let currentURL = yield this.listener.getCurrentUrl();
- let goBack = this.listener.goBack({pageTimeout: this.timeouts.pageLoad});
-
- // If a remoteness update interrupts our page load, this will never return
- // We need to re-issue this request to correctly poll for readyState and
- // send errors.
- this.curBrowser.pendingCommands.push(() => {
- let parameters = {
- // TODO(ato): Bug 1242595
- command_id: this.listener.activeMessageId,
- lastSeenURL: currentURL,
- pageTimeout: this.timeouts.pageLoad,
- startTime: new Date().getTime(),
- };
- this.mm.broadcastAsyncMessage(
- // TODO: combine with
- // "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
- "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
- parameters);
- });
-
- yield goBack;
-};
-
-/**
- * Cause the browser to traverse one step forward in the joint history
- * of the current browsing context.
- */
-GeckoDriver.prototype.goForward = function* (cmd, resp) {
- assert.content(this.context);
-
- if (!this.curBrowser.tab) {
- // Navigation does not work for non-browser windows
- return;
- }
-
- let contentBrowser = browser.getBrowserForTab(this.curBrowser.tab)
- if (!contentBrowser.webNavigation.canGoForward) {
- return;
- }
-
- let currentURL = yield this.listener.getCurrentUrl();
- let goForward = this.listener.goForward({pageTimeout: this.timeouts.pageLoad});
-
- // If a remoteness update interrupts our page load, this will never return
- // We need to re-issue this request to correctly poll for readyState and
- // send errors.
- this.curBrowser.pendingCommands.push(() => {
- let parameters = {
- // TODO(ato): Bug 1242595
- command_id: this.listener.activeMessageId,
- lastSeenURL: currentURL,
- pageTimeout: this.timeouts.pageLoad,
- startTime: new Date().getTime(),
- };
- this.mm.broadcastAsyncMessage(
- // TODO: combine with
- // "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
- "Marionette:pollForReadyState" + this.curBrowser.curFrameId,
- parameters);
- });
-
- yield goForward;
-};
-
-/** Refresh the page. */
-GeckoDriver.prototype.refresh = function*(cmd, resp) {
- assert.content(this.context);
-
- yield this.listener.refresh();
-};
-
-/**
- * Forces an update for the given browser's id.
- */
-GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
- this._browserIds.set(browser.permanentKey, newId);
-};
-
-/**
- * Retrieves a listener id for the given xul browser element. In case
- * the browser is not known, an attempt is made to retrieve the id from
- * a CPOW, and null is returned if this fails.
- */
-GeckoDriver.prototype.getIdForBrowser = function (browser) {
- if (browser === null) {
- return null;
- }
- let permKey = browser.permanentKey;
- if (this._browserIds.has(permKey)) {
- return this._browserIds.get(permKey);
- }
-
- let winId = browser.outerWindowID;
- if (winId) {
- winId = winId.toString();
- this._browserIds.set(permKey, winId);
- return winId;
- }
- return null;
-},
-
-/**
- * Get the current window's handle. On desktop this typically corresponds
- * to the currently selected tab.
- *
- * Return an opaque server-assigned identifier to this window that
- * uniquely identifies it within this Marionette instance. This can
- * be used to switch to this window at a later point.
- *
- * @return {string}
- * Unique window handle.
- */
-GeckoDriver.prototype.getWindowHandle = function (cmd, resp) {
- // curFrameId always holds the current tab.
- if (this.curBrowser.curFrameId) {
- resp.body.value = this.curBrowser.curFrameId;
- return;
- }
-
- for (let i in this.browsers) {
- if (this.curBrowser == this.browsers[i]) {
- resp.body.value = i;
- return;
- }
- }
-};
-
-/**
- * Get a list of top-level browsing contexts. On desktop this typically
- * corresponds to the set of open tabs for browser windows, or the window itself
- * for non-browser chrome windows.
- *
- * Each window handle is assigned by the server and is guaranteed unique,
- * however the return array does not have a specified ordering.
- *
- * @return {Array.<string>}
- * Unique window handles.
- */
-GeckoDriver.prototype.getWindowHandles = function (cmd, resp) {
- return this.windowHandles;
-}
-
-/**
- * Get the current window's handle. This corresponds to a window that
- * may itself contain tabs.
- *
- * Return an opaque server-assigned identifier to this window that
- * uniquely identifies it within this Marionette instance. This can
- * be used to switch to this window at a later point.
- *
- * @return {string}
- * Unique window handle.
- */
-GeckoDriver.prototype.getChromeWindowHandle = function (cmd, resp) {
- for (let i in this.browsers) {
- if (this.curBrowser == this.browsers[i]) {
- resp.body.value = i;
- return;
- }
- }
-};
-
-/**
- * Returns identifiers for each open chrome window for tests interested in
- * managing a set of chrome windows and tabs separately.
- *
- * @return {Array.<string>}
- * Unique window handles.
- */
-GeckoDriver.prototype.getChromeWindowHandles = function (cmd, resp) {
- return this.chromeWindowHandles;
-}
-
-/**
- * Get the current window position.
- *
- * @return {Object.<string, number>}
- * Object with |x| and |y| coordinates.
- */
-GeckoDriver.prototype.getWindowPosition = function (cmd, resp) {
- return this.curBrowser.position;
-};
-
-/**
- * Set the window position of the browser on the OS Window Manager
- *
- * @param {number} x
- * X coordinate of the top/left of the window that it will be
- * moved to.
- * @param {number} y
- * Y coordinate of the top/left of the window that it will be
- * moved to.
- *
- * @return {Object.<string, number>}
- * Object with |x| and |y| coordinates.
- */
-GeckoDriver.prototype.setWindowPosition = function (cmd, resp) {
- assert.firefox()
-
- let {x, y} = cmd.parameters;
- assert.positiveInteger(x);
- assert.positiveInteger(y);
-
- let win = this.getCurrentWindow();
- win.moveTo(x, y);
-
- return this.curBrowser.position;
-};
-
-/**
- * Switch current top-level browsing context by name or server-assigned ID.
- * Searches for windows by name, then ID. Content windows take precedence.
- *
- * @param {string} name
- * Target name or ID of the window to switch to.
- * @param {boolean=} focus
- * A boolean value which determines whether to focus
- * the window. Defaults to true.
- */
-GeckoDriver.prototype.switchToWindow = function* (cmd, resp) {
- let switchTo = cmd.parameters.name;
- let focus = (cmd.parameters.focus !== undefined) ? cmd.parameters.focus : true;
- let found;
-
- let byNameOrId = function (name, windowId) {
- return switchTo === name || switchTo === windowId;
- };
-
- let winEn = Services.wm.getEnumerator(null);
- while (winEn.hasMoreElements()) {
- let win = winEn.getNext();
- let outerId = getOuterWindowId(win);
- let tabBrowser = browser.getTabBrowser(win);
-
- if (byNameOrId(win.name, outerId)) {
- // In case the wanted window is a chrome window, we are done.
- found = {win: win, outerId: outerId, hasTabBrowser: !!tabBrowser};
- break;
-
- } else if (tabBrowser) {
- // Otherwise check if the chrome window has a tab browser, and that it
- // contains a tab with the wanted window handle.
- for (let i = 0; i < tabBrowser.tabs.length; ++i) {
- let contentBrowser = browser.getBrowserForTab(tabBrowser.tabs[i]);
- let contentWindowId = this.getIdForBrowser(contentBrowser);
-
- if (byNameOrId(win.name, contentWindowId)) {
- found = {
- win: win,
- outerId: outerId,
- hasTabBrowser: true,
- tabIndex: i,
- };
- break;
- }
- }
- }
- }
-
- if (found) {
- if (!(found.outerId in this.browsers)) {
- // Initialise Marionette if the current chrome window has not been seen
- // before. Also register the initial tab, if one exists.
- let registerBrowsers, browserListening;
-
- if (found.hasTabBrowser) {
- registerBrowsers = this.registerPromise();
- browserListening = this.listeningPromise();
- }
-
- this.startBrowser(found.win, false /* isNewSession */);
-
- if (registerBrowsers && browserListening) {
- yield registerBrowsers;
- yield browserListening;
- }
-
- } else {
- // Otherwise switch to the known chrome window, and activate the tab
- // if it's a content browser.
- this.curBrowser = this.browsers[found.outerId];
-
- if ("tabIndex" in found) {
- this.curBrowser.switchToTab(found.tabIndex, found.win, focus);
- }
- }
- } else {
- throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
- }
-};
-
-GeckoDriver.prototype.getActiveFrame = function (cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- // no frame means top-level
- resp.body.value = null;
- if (this.curFrame) {
- let elRef = this.curBrowser.seenEls
- .add(this.curFrame.frameElement);
- let el = element.makeWebElement(elRef);
- resp.body.value = el;
- }
- break;
-
- case Context.CONTENT:
- resp.body.value = null;
- if (this.currentFrameElement !== null) {
- let el = element.makeWebElement(this.currentFrameElement);
- resp.body.value = el;
- }
- break;
- }
-};
-
-GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
- let res = yield this.listener.switchToParentFrame();
-};
-
-/**
- * Switch to a given frame within the current window.
- *
- * @param {Object} element
- * A web element reference to the element to switch to.
- * @param {(string|number)} id
- * If element is not defined, then this holds either the id, name,
- * or index of the frame to switch to.
- */
-GeckoDriver.prototype.switchToFrame = function* (cmd, resp) {
- let {id, element, focus} = cmd.parameters;
-
- const otherErrorsExpr = /about:.+(error)|(blocked)\?/;
- const checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-
- let curWindow = this.getCurrentWindow();
-
- let checkLoad = function() {
- let win = this.getCurrentWindow();
- if (win.document.readyState == "complete") {
- return;
- } else if (win.document.readyState == "interactive") {
- let baseURI = win.document.baseURI;
- if (baseURI.startsWith("about:certerror")) {
- throw new InsecureCertificateError();
- } else if (otherErrorsExpr.exec(win.document.baseURI)) {
- throw new UnknownError("Error loading page");
- }
- }
-
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- };
-
- if (this.context == Context.CHROME) {
- let foundFrame = null;
-
- // just focus
- if (typeof id == "undefined" && typeof element == "undefined") {
- this.curFrame = null;
- if (focus) {
- this.mainFrame.focus();
- }
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
-
- // by element
- if (this.curBrowser.seenEls.has(element)) {
- // HTMLIFrameElement
- let wantedFrame = this.curBrowser.seenEls.get(element, {frame: curWindow});
- // Deal with an embedded xul:browser case
- if (wantedFrame.tagName == "xul:browser" || wantedFrame.tagName == "browser") {
- curWindow = wantedFrame.contentWindow;
- this.curFrame = curWindow;
- if (focus) {
- this.curFrame.focus();
- }
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
-
- // Check if the frame is XBL anonymous
- let parent = curWindow.document.getBindingParent(wantedFrame);
- // Shadow nodes also show up in getAnonymousNodes, we should ignore them.
- if (parent && !(parent.shadowRoot && parent.shadowRoot.contains(wantedFrame))) {
- let anonNodes = [...curWindow.document.getAnonymousNodes(parent) || []];
- if (anonNodes.length > 0) {
- let el = wantedFrame;
- while (el) {
- if (anonNodes.indexOf(el) > -1) {
- curWindow = wantedFrame.contentWindow;
- this.curFrame = curWindow;
- if (focus) {
- this.curFrame.focus();
- }
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
- el = el.parentNode;
- }
- }
- }
-
- // else, assume iframe
- let frames = curWindow.document.getElementsByTagName("iframe");
- let numFrames = frames.length;
- for (let i = 0; i < numFrames; i++) {
- if (new XPCNativeWrapper(frames[i]) == new XPCNativeWrapper(wantedFrame)) {
- curWindow = frames[i].contentWindow;
- this.curFrame = curWindow;
- if (focus) {
- this.curFrame.focus();
- }
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
- }
- }
-
- switch (typeof id) {
- case "string" :
- let foundById = null;
- let frames = curWindow.document.getElementsByTagName("iframe");
- let numFrames = frames.length;
- for (let i = 0; i < numFrames; i++) {
- //give precedence to name
- let frame = frames[i];
- if (frame.getAttribute("name") == id) {
- foundFrame = i;
- curWindow = frame.contentWindow;
- break;
- } else if (foundById === null && frame.id == id) {
- foundById = i;
- }
- }
- if (foundFrame === null && foundById !== null) {
- foundFrame = foundById;
- curWindow = frames[foundById].contentWindow;
- }
- break;
- case "number":
- if (typeof curWindow.frames[id] != "undefined") {
- foundFrame = id;
- curWindow = curWindow.frames[foundFrame].frameElement.contentWindow;
- }
- break;
- }
-
- if (foundFrame !== null) {
- this.curFrame = curWindow;
- if (focus) {
- this.curFrame.focus();
- }
- checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
- } else {
- throw new NoSuchFrameError(`Unable to locate frame: ${id}`);
- }
-
- } else if (this.context == Context.CONTENT) {
- if (!id && !element &&
- this.curBrowser.frameManager.currentRemoteFrame !== null) {
- // We're currently using a ChromeMessageSender for a remote frame, so this
- // request indicates we need to switch back to the top-level (parent) frame.
- // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so
- // we send the message to the right listener.
- this.switchToGlobalMessageManager();
- }
- cmd.command_id = cmd.id;
-
- let res = yield this.listener.switchToFrame(cmd.parameters);
- if (res) {
- let {win: winId, frame: frameId} = res;
- this.mm = this.curBrowser.frameManager.getFrameMM(winId, frameId);
-
- let registerBrowsers = this.registerPromise();
- let browserListening = this.listeningPromise();
-
- this.oopFrameId =
- this.curBrowser.frameManager.switchToFrame(winId, frameId);
-
- yield registerBrowsers;
- yield browserListening;
- }
- }
-};
-
-GeckoDriver.prototype.getTimeouts = function (cmd, resp) {
- return this.timeouts;
-};
-
-/**
- * Set timeout for page loading, searching, and scripts.
- *
- * @param {Object.<string, number>}
- * Dictionary of timeout types and their new value, where all timeout
- * types are optional.
- *
- * @throws {InvalidArgumentError}
- * If timeout type key is unknown, or the value provided with it is
- * not an integer.
- */
-GeckoDriver.prototype.setTimeouts = function (cmd, resp) {
- // backwards compatibility with old API
- // that accepted a dictionary {type: <string>, ms: <number>}
- let json = {};
- if (typeof cmd.parameters == "object" &&
- "type" in cmd.parameters &&
- "ms" in cmd.parameters) {
- logger.warn("Using deprecated data structure for setting timeouts");
- json = {[cmd.parameters.type]: parseInt(cmd.parameters.ms)};
- } else {
- json = cmd.parameters;
- }
-
- // merge with existing timeouts
- let merged = Object.assign(this.timeouts.toJSON(), json);
- this.timeouts = session.Timeouts.fromJSON(merged);
-};
-
-/** Single tap. */
-GeckoDriver.prototype.singleTap = function*(cmd, resp) {
- let {id, x, y} = cmd.parameters;
-
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'singleTap' is not yet available in chrome context");
-
- case Context.CONTENT:
- this.addFrameCloseListener("tap");
- yield this.listener.singleTap(id, x, y);
- break;
- }
-};
-
-/**
- * Perform a series of grouped actions at the specified points in time.
- *
- * @param {Array.<?>} actions
- * Array of objects that each represent an action sequence.
- *
- * @throws {UnsupportedOperationError}
- * If the command is made in chrome context.
- */
-GeckoDriver.prototype.performActions = function(cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'performActions' is not yet available in chrome context");
-
- case Context.CONTENT:
- return this.listener.performActions({"actions": cmd.parameters.actions});
- }
-};
-
-/**
- * Release all the keys and pointer buttons that are currently depressed.
- */
-GeckoDriver.prototype.releaseActions = function(cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'releaseActions' is not yet available in chrome context");
-
- case Context.CONTENT:
- return this.listener.releaseActions();
- }
-};
-
-/**
- * An action chain.
- *
- * @param {Object} value
- * A nested array where the inner array represents each event,
- * and the outer array represents a collection of events.
- *
- * @return {number}
- * Last touch ID.
- */
-GeckoDriver.prototype.actionChain = function*(cmd, resp) {
- let {chain, nextId} = cmd.parameters;
-
- switch (this.context) {
- case Context.CHROME:
- // be conservative until this has a use case and is established
- // to work as expected in Fennec
- assert.firefox()
-
- let win = this.getCurrentWindow();
- resp.body.value = yield this.legacyactions.dispatchActions(
- chain, nextId, {frame: win}, this.curBrowser.seenEls);
- break;
-
- case Context.CONTENT:
- this.addFrameCloseListener("action chain");
- resp.body.value = yield this.listener.actionChain(chain, nextId);
- break;
- }
-};
-
-/**
- * A multi-action chain.
- *
- * @param {Object} value
- * A nested array where the inner array represents eache vent,
- * the middle array represents a collection of events for each
- * finger, and the outer array represents all fingers.
- */
-GeckoDriver.prototype.multiAction = function*(cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'multiAction' is not yet available in chrome context");
-
- case Context.CONTENT:
- this.addFrameCloseListener("multi action chain");
- yield this.listener.multiAction(cmd.parameters.value, cmd.parameters.max_length);
- break;
- }
-};
-
-/**
- * Find an element using the indicated search strategy.
- *
- * @param {string} using
- * Indicates which search method to use.
- * @param {string} value
- * Value the client is looking for.
- */
-GeckoDriver.prototype.findElement = function*(cmd, resp) {
- let strategy = cmd.parameters.using;
- let expr = cmd.parameters.value;
- let opts = {
- startNode: cmd.parameters.element,
- timeout: this.timeouts.implicit,
- all: false,
- };
-
- switch (this.context) {
- case Context.CHROME:
- if (!SUPPORTED_STRATEGIES.has(strategy)) {
- throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
- }
-
- let container = {frame: this.getCurrentWindow()};
- if (opts.startNode) {
- opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
- }
- let el = yield element.find(container, strategy, expr, opts);
- let elRef = this.curBrowser.seenEls.add(el);
- let webEl = element.makeWebElement(elRef);
-
- resp.body.value = webEl;
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.findElementContent(
- strategy,
- expr,
- opts);
- break;
- }
-};
-
-/**
- * Find elements using the indicated search strategy.
- *
- * @param {string} using
- * Indicates which search method to use.
- * @param {string} value
- * Value the client is looking for.
- */
-GeckoDriver.prototype.findElements = function*(cmd, resp) {
- let strategy = cmd.parameters.using;
- let expr = cmd.parameters.value;
- let opts = {
- startNode: cmd.parameters.element,
- timeout: this.timeouts.implicit,
- all: true,
- };
-
- switch (this.context) {
- case Context.CHROME:
- if (!SUPPORTED_STRATEGIES.has(strategy)) {
- throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
- }
-
- let container = {frame: this.getCurrentWindow()};
- if (opts.startNode) {
- opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
- }
- let els = yield element.find(container, strategy, expr, opts);
-
- let elRefs = this.curBrowser.seenEls.addAll(els);
- let webEls = elRefs.map(element.makeWebElement);
- resp.body = webEls;
- break;
-
- case Context.CONTENT:
- resp.body = yield this.listener.findElementsContent(
- cmd.parameters.using,
- cmd.parameters.value,
- opts);
- break;
- }
-};
-
-/** Return the active element on the page. */
-GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'getActiveElement' is not yet available in chrome context");
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getActiveElement();
- break;
- }
-};
-
-/**
- * Send click event to element.
- *
- * @param {string} id
- * Reference ID to the element that will be clicked.
- */
-GeckoDriver.prototype.clickElement = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- yield interaction.clickElement(el, this.a11yChecks);
- break;
-
- case Context.CONTENT:
- // We need to protect against the click causing an OOP frame to close.
- // This fires the mozbrowserclose event when it closes so we need to
- // listen for it and then just send an error back. The person making the
- // call should be aware something isnt right and handle accordingly
- this.addFrameCloseListener("click");
- yield this.listener.clickElement(id);
- break;
- }
-};
-
-/**
- * Get a given attribute of an element.
- *
- * @param {string} id
- * Web element reference ID to the element that will be inspected.
- * @param {string} name
- * Name of the attribute which value to retrieve.
- *
- * @return {string}
- * Value of the attribute.
- */
-GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
- let {id, name} = cmd.parameters;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
-
- resp.body.value = el.getAttribute(name);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getElementAttribute(id, name);
- break;
- }
-};
-
-/**
- * Returns the value of a property associated with given element.
- *
- * @param {string} id
- * Web element reference ID to the element that will be inspected.
- * @param {string} name
- * Name of the property which value to retrieve.
- *
- * @return {string}
- * Value of the property.
- */
-GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
- let {id, name} = cmd.parameters;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- resp.body.value = el[name];
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getElementProperty(id, name);
- break;
- }
-};
-
-/**
- * Get the text of an element, if any. Includes the text of all child
- * elements.
- *
- * @param {string} id
- * Reference ID to the element that will be inspected.
- */
-GeckoDriver.prototype.getElementText = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- // for chrome, we look at text nodes, and any node with a "label" field
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- let lines = [];
- this.getVisibleText(el, lines);
- resp.body.value = lines.join("\n");
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getElementText(id);
- break;
- }
-};
-
-/**
- * Get the tag name of the element.
- *
- * @param {string} id
- * Reference ID to the element that will be inspected.
- */
-GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- resp.body.value = el.tagName.toLowerCase();
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getElementTagName(id);
- break;
- }
-};
-
-/**
- * Check if element is displayed.
- *
- * @param {string} id
- * Reference ID to the element that will be inspected.
- */
-GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- resp.body.value = yield interaction.isElementDisplayed(
- el, this.a11yChecks);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.isElementDisplayed(id);
- break;
- }
-};
-
-/**
- * Return the property of the computed style of an element.
- *
- * @param {string} id
- * Reference ID to the element that will be checked.
- * @param {string} propertyName
- * CSS rule that is being requested.
- */
-GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
- let {id, propertyName: prop} = cmd.parameters;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- let sty = win.document.defaultView.getComputedStyle(el, null);
- resp.body.value = sty.getPropertyValue(prop);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getElementValueOfCssProperty(id, prop);
- break;
- }
-};
-
-/**
- * Check if element is enabled.
- *
- * @param {string} id
- * Reference ID to the element that will be checked.
- */
-GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- // Selenium atom doesn't quite work here
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- resp.body.value = yield interaction.isElementEnabled(
- el, this.a11yChecks);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.isElementEnabled(id);
- break;
- }
-},
-
-/**
- * Check if element is selected.
- *
- * @param {string} id
- * Reference ID to the element that will be checked.
- */
-GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- // Selenium atom doesn't quite work here
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- resp.body.value = yield interaction.isElementSelected(
- el, this.a11yChecks);
- break;
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.isElementSelected(id);
- break;
- }
-};
-
-GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- let rect = el.getBoundingClientRect();
- resp.body = {
- x: rect.x + win.pageXOffset,
- y: rect.y + win.pageYOffset,
- width: rect.width,
- height: rect.height
- };
- break;
-
- case Context.CONTENT:
- resp.body = yield this.listener.getElementRect(id);
- break;
- }
-};
-
-/**
- * Send key presses to element after focusing on it.
- *
- * @param {string} id
- * Reference ID to the element that will be checked.
- * @param {string} value
- * Value to send to the element.
- */
-GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
- let {id, value} = cmd.parameters;
- assert.defined(value, `Expected character sequence: ${value}`);
-
- switch (this.context) {
- case Context.CHROME:
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- yield interaction.sendKeysToElement(
- el, value, true, this.a11yChecks);
- break;
-
- case Context.CONTENT:
- yield this.listener.sendKeysToElement(id, value);
- break;
- }
-};
-
-/** Sets the test name. The test name is used for logging purposes. */
-GeckoDriver.prototype.setTestName = function*(cmd, resp) {
- let val = cmd.parameters.value;
- this.testName = val;
- yield this.listener.setTestName({value: val});
-};
-
-/**
- * Clear the text of an element.
- *
- * @param {string} id
- * Reference ID to the element that will be cleared.
- */
-GeckoDriver.prototype.clearElement = function*(cmd, resp) {
- let id = cmd.parameters.id;
-
- switch (this.context) {
- case Context.CHROME:
- // the selenium atom doesn't work here
- let win = this.getCurrentWindow();
- let el = this.curBrowser.seenEls.get(id, {frame: win});
- if (el.nodeName == "textbox") {
- el.value = "";
- } else if (el.nodeName == "checkbox") {
- el.checked = false;
- }
- break;
-
- case Context.CONTENT:
- yield this.listener.clearElement(id);
- break;
- }
-};
-
-/**
- * Switch to shadow root of the given host element.
- *
- * @param {string} id element id.
- */
-GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
- assert.content(this.context)
-
- let id;
- if (cmd.parameters) { id = cmd.parameters.id; }
- yield this.listener.switchToShadowRoot(id);
-};
-
-/** Add a cookie to the document. */
-GeckoDriver.prototype.addCookie = function*(cmd, resp) {
- assert.content(this.context)
-
- let cb = msg => {
- this.mm.removeMessageListener("Marionette:addCookie", cb);
- let cookie = msg.json;
- Services.cookies.add(
- cookie.domain,
- cookie.path,
- cookie.name,
- cookie.value,
- cookie.secure,
- cookie.httpOnly,
- cookie.session,
- cookie.expiry,
- {}); // originAttributes
- return true;
- };
-
- this.mm.addMessageListener("Marionette:addCookie", cb);
- yield this.listener.addCookie(cmd.parameters.cookie);
-};
-
-/**
- * Get all the cookies for the current domain.
- *
- * This is the equivalent of calling {@code document.cookie} and parsing
- * the result.
- */
-GeckoDriver.prototype.getCookies = function*(cmd, resp) {
- assert.content(this.context)
-
- resp.body = yield this.listener.getCookies();
-};
-
-/** Delete all cookies that are visible to a document. */
-GeckoDriver.prototype.deleteAllCookies = function*(cmd, resp) {
- assert.content(this.context)
-
- let cb = msg => {
- let cookie = msg.json;
- cookieManager.remove(
- cookie.host,
- cookie.name,
- cookie.path,
- false,
- cookie.originAttributes);
- return true;
- };
-
- this.mm.addMessageListener("Marionette:deleteCookie", cb);
- yield this.listener.deleteAllCookies();
- this.mm.removeMessageListener("Marionette:deleteCookie", cb);
-};
-
-/** Delete a cookie by name. */
-GeckoDriver.prototype.deleteCookie = function*(cmd, resp) {
- assert.content(this.context)
-
- let cb = msg => {
- this.mm.removeMessageListener("Marionette:deleteCookie", cb);
- let cookie = msg.json;
- cookieManager.remove(
- cookie.host,
- cookie.name,
- cookie.path,
- false,
- cookie.originAttributes);
- return true;
- };
-
- this.mm.addMessageListener("Marionette:deleteCookie", cb);
- yield this.listener.deleteCookie(cmd.parameters.name);
-};
-
-/**
- * Close the currently selected tab/window.
- *
- * With multiple open tabs present the currently selected tab will be closed.
- * Otherwise the window itself will be closed. If it is the last window
- * currently open, the window will not be closed to prevent a shutdown of the
- * application. Instead the returned list of window handles is empty.
- *
- * @return {Array.<string>}
- * Unique window handles of remaining windows.
- */
-GeckoDriver.prototype.close = function (cmd, resp) {
- let nwins = 0;
- let winEn = Services.wm.getEnumerator(null);
-
- while (winEn.hasMoreElements()) {
- let win = winEn.getNext();
-
- // For browser windows count the tabs. Otherwise take the window itself.
- let tabbrowser = browser.getTabBrowser(win);
- if (tabbrowser) {
- nwins += tabbrowser.tabs.length;
- } else {
- nwins++;
- }
- }
-
- // If there is only 1 window left, do not close it. Instead return a faked
- // empty array of window handles. This will instruct geckodriver to terminate
- // the application.
- if (nwins == 1) {
- return [];
- }
-
- if (this.mm != globalMessageManager) {
- this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
- }
-
- return this.curBrowser.closeTab().then(() => this.windowHandles);
-};
-
-/**
- * Close the currently selected chrome window.
- *
- * If it is the last window currently open, the chrome window will not be
- * closed to prevent a shutdown of the application. Instead the returned
- * list of chrome window handles is empty.
- *
- * @return {Array.<string>}
- * Unique chrome window handles of remaining chrome windows.
- */
-GeckoDriver.prototype.closeChromeWindow = function (cmd, resp) {
- assert.firefox();
-
- // Get the total number of windows
- let nwins = 0;
- let winEn = Services.wm.getEnumerator(null);
-
- while (winEn.hasMoreElements()) {
- nwins++;
- winEn.getNext();
- }
-
- // If there is only 1 window left, do not close it. Instead return a faked
- // empty array of window handles. This will instruct geckodriver to terminate
- // the application.
- if (nwins == 1) {
- return [];
- }
-
- // reset frame to the top-most frame
- this.curFrame = null;
-
- if (this.mm != globalMessageManager) {
- this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
- }
-
- return this.curBrowser.closeWindow().then(() => this.chromeWindowHandles);
-};
-
-/** Delete Marionette session. */
-GeckoDriver.prototype.deleteSession = function (cmd, resp) {
- if (this.curBrowser !== null) {
- // frame scripts can be safely reused
- Preferences.set(CONTENT_LISTENER_PREF, false);
-
- // delete session in each frame in each browser
- for (let win in this.browsers) {
- let browser = this.browsers[win];
- for (let i in browser.knownFrames) {
- globalMessageManager.broadcastAsyncMessage(
- "Marionette:deleteSession" + browser.knownFrames[i], {});
- }
- }
-
- let winEn = Services.wm.getEnumerator(null);
- while (winEn.hasMoreElements()) {
- let win = winEn.getNext();
- if (win.messageManager) {
- win.messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
- } else {
- logger.error(
- `Could not remove listener from page ${win.location.href}`);
- }
- }
-
- this.curBrowser.frameManager.removeMessageManagerListeners(
- globalMessageManager);
- }
-
- this.switchToGlobalMessageManager();
-
- // reset frame to the top-most frame
- this.curFrame = null;
- if (this.mainFrame) {
- try {
- this.mainFrame.focus();
- } catch (e) {
- this.mainFrame = null;
- }
- }
-
- if (this.observing !== null) {
- for (let topic in this.observing) {
- Services.obs.removeObserver(this.observing[topic], topic);
- }
- this.observing = null;
- }
-
- this.sandboxes.clear();
- cert.uninstallOverride();
-
- this.sessionId = null;
- this.capabilities = new session.Capabilities();
-};
-
-/** Returns the current status of the Application Cache. */
-GeckoDriver.prototype.getAppCacheStatus = function* (cmd, resp) {
- switch (this.context) {
- case Context.CHROME:
- throw new UnsupportedOperationError(
- "Command 'getAppCacheStatus' is not yet available in chrome context");
-
- case Context.CONTENT:
- resp.body.value = yield this.listener.getAppCacheStatus();
- break;
- }
-};
-
-/**
- * Import script to the JS evaluation runtime.
- *
- * Imported scripts are exposed in the contexts of all subsequent
- * calls to {@code executeScript}, {@code executeAsyncScript}, and
- * {@code executeJSScript} by prepending them to the evaluated script.
- *
- * Scripts can be cleared with the {@code clearImportedScripts} command.
- *
- * @param {string} script
- * Script to include. If the script is byte-by-byte equal to an
- * existing imported script, it is not imported.
- */
-GeckoDriver.prototype.importScript = function*(cmd, resp) {
- let script = cmd.parameters.script;
- this.importedScripts.for(this.context).add(script);
-};
-
-/**
- * Clear all scripts that are imported into the JS evaluation runtime.
- *
- * Scripts can be imported using the {@code importScript} command.
- */
-GeckoDriver.prototype.clearImportedScripts = function*(cmd, resp) {
- this.importedScripts.for(this.context).clear();
-};
-
-/**
- * Takes a screenshot of a web element, current frame, or viewport.
- *
- * The screen capture is returned as a lossless PNG image encoded as
- * a base 64 string.
- *
- * If called in the content context, the <code>id</code> argument is not null
- * and refers to a present and visible web element's ID, the capture area
- * will be limited to the bounding box of that element. Otherwise, the
- * capture area will be the bounding box of the current frame.
- *
- * If called in the chrome context, the screenshot will always represent the
- * entire viewport.
- *
- * @param {string=} id
- * Optional web element reference to take a screenshot of.
- * If undefined, a screenshot will be taken of the document element.
- * @param {Array.<string>=} highlights
- * List of web elements to highlight.
- * @param {boolean} full
- * True to take a screenshot of the entire document element. Is not
- * considered if {@code id} is not defined. Defaults to true.
- * @param {boolean=} hash
- * True if the user requests a hash of the image data.
- * @param {boolean=} scroll
- * Scroll to element if |id| is provided. If undefined, it will
- * scroll to the element.
- *
- * @return {string}
- * If {@code hash} is false, PNG image encoded as base64 encoded string. If
- * 'hash' is True, hex digest of the SHA-256 hash of the base64 encoded
- * string.
- */
-GeckoDriver.prototype.takeScreenshot = function (cmd, resp) {
- let {id, highlights, full, hash, scroll} = cmd.parameters;
- highlights = highlights || [];
- let format = hash ? capture.Format.Hash : capture.Format.Base64;
-
- switch (this.context) {
- case Context.CHROME:
- let container = {frame: this.getCurrentWindow().document.defaultView};
- if (!container.frame) {
- throw new NoSuchWindowError("Unable to locate window");
- }
-
- let highlightEls = highlights.map(
- ref => this.curBrowser.seenEls.get(ref, container));
-
- // viewport
- let canvas;
- if (!id && !full) {
- canvas = capture.viewport(container.frame, highlightEls);
-
- // element or full document element
- } else {
- let node;
- if (id) {
- node = this.curBrowser.seenEls.get(id, container);
- } else {
- node = container.frame.document.documentElement;
- }
-
- canvas = capture.element(node, highlightEls);
- }
-
- switch (format) {
- case capture.Format.Hash:
- return capture.toHash(canvas);
-
- case capture.Format.Base64:
- return capture.toBase64(canvas);
- }
- break;
-
- case Context.CONTENT:
- return this.listener.takeScreenshot(format, cmd.parameters);
- }
-};
-
-/**
- * Get the current browser orientation.
- *
- * Will return one of the valid primary orientation values
- * portrait-primary, landscape-primary, portrait-secondary, or
- * landscape-secondary.
- */
-GeckoDriver.prototype.getScreenOrientation = function (cmd, resp) {
- assert.fennec();
-
- resp.body.value = this.getCurrentWindow().screen.mozOrientation;
-};
-
-/**
- * Set the current browser orientation.
- *
- * The supplied orientation should be given as one of the valid
- * orientation values. If the orientation is unknown, an error will
- * be raised.
- *
- * Valid orientations are "portrait" and "landscape", which fall
- * back to "portrait-primary" and "landscape-primary" respectively,
- * and "portrait-secondary" as well as "landscape-secondary".
- */
-GeckoDriver.prototype.setScreenOrientation = function (cmd, resp) {
- assert.fennec();
-
- const ors = [
- "portrait", "landscape",
- "portrait-primary", "landscape-primary",
- "portrait-secondary", "landscape-secondary",
- ];
-
- let or = String(cmd.parameters.orientation);
- assert.string(or);
- let mozOr = or.toLowerCase();
- if (!ors.includes(mozOr)) {
- throw new InvalidArgumentError(`Unknown screen orientation: ${or}`);
- }
-
- let win = this.getCurrentWindow();
- if (!win.screen.mozLockOrientation(mozOr)) {
- throw new WebDriverError(`Unable to set screen orientation: ${or}`);
- }
-};
-
-/**
- * Get the size of the browser window currently in focus.
- *
- * Will return the current browser window size in pixels. Refers to
- * window outerWidth and outerHeight values, which include scroll bars,
- * title bars, etc.
- */
-GeckoDriver.prototype.getWindowSize = function (cmd, resp) {
- let win = this.getCurrentWindow();
- resp.body.width = win.outerWidth;
- resp.body.height = win.outerHeight;
-};
-
-/**
- * Set the size of the browser window currently in focus.
- *
- * Not supported on B2G. The supplied width and height values refer to
- * the window outerWidth and outerHeight values, which include scroll
- * bars, title bars, etc.
- */
-GeckoDriver.prototype.setWindowSize = function (cmd, resp) {
- assert.firefox()
-
- let {width, height} = cmd.parameters;
- let win = this.getCurrentWindow();
- win.resizeTo(width, height);
- this.getWindowSize(cmd, resp);
-};
-
-/**
- * Maximizes the user agent window as if the user pressed the maximise
- * button.
- *
- * Not Supported on B2G or Fennec.
- */
-GeckoDriver.prototype.maximizeWindow = function (cmd, resp) {
- assert.firefox()
-
- let win = this.getCurrentWindow();
- win.maximize()
-};
-
-/**
- * Dismisses a currently displayed tab modal, or returns no such alert if
- * no modal is displayed.
- */
-GeckoDriver.prototype.dismissDialog = function (cmd, resp) {
- this._checkIfAlertIsPresent();
-
- let {button0, button1} = this.dialog.ui;
- (button1 ? button1 : button0).click();
- this.dialog = null;
-};
-
-/**
- * Accepts a currently displayed tab modal, or returns no such alert if
- * no modal is displayed.
- */
-GeckoDriver.prototype.acceptDialog = function (cmd, resp) {
- this._checkIfAlertIsPresent();
-
- let {button0} = this.dialog.ui;
- button0.click();
- this.dialog = null;
-};
-
-/**
- * Returns the message shown in a currently displayed modal, or returns a no such
- * alert error if no modal is currently displayed.
- */
-GeckoDriver.prototype.getTextFromDialog = function (cmd, resp) {
- this._checkIfAlertIsPresent();
-
- let {infoBody} = this.dialog.ui;
- resp.body.value = infoBody.textContent;
-};
-
-/**
- * Sends keys to the input field of a currently displayed modal, or
- * returns a no such alert error if no modal is currently displayed. If
- * a tab modal is currently displayed but has no means for text input,
- * an element not visible error is returned.
- */
-GeckoDriver.prototype.sendKeysToDialog = function (cmd, resp) {
- this._checkIfAlertIsPresent();
-
- // see toolkit/components/prompts/content/commonDialog.js
- let {loginContainer, loginTextbox} = this.dialog.ui;
- if (loginContainer.hidden) {
- throw new ElementNotInteractableError(
- "This prompt does not accept text input");
- }
-
- let win = this.dialog.window ? this.dialog.window : this.getCurrentWindow();
- event.sendKeysToElement(
- cmd.parameters.value,
- loginTextbox,
- {ignoreVisibility: true},
- win);
-};
-
-GeckoDriver.prototype._checkIfAlertIsPresent = function() {
- if (!this.dialog || !this.dialog.ui) {
- throw new NoAlertOpenError(
- "No tab modal was open when attempting to get the dialog text");
- }
-};
-
-/**
- * Enables or disables accepting new socket connections.
- *
- * By calling this method with `false` the server will not accept any further
- * connections, but existing connections will not be forcible closed. Use `true`
- * to re-enable accepting connections.
- *
- * Please note that when closing the connection via the client you can end-up in
- * a non-recoverable state if it hasn't been enabled before.
- *
- * This method is used for custom in application shutdowns via marionette.quit()
- * or marionette.restart(), like File -> Quit.
- *
- * @param {boolean} state
- * True if the server should accept new socket connections.
- */
-GeckoDriver.prototype.acceptConnections = function (cmd, resp) {
- assert.boolean(cmd.parameters.value);
- this._server.acceptConnections = cmd.parameters.value;
-}
-
-/**
- * Quits Firefox with the provided flags and tears down the current
- * session.
- */
-GeckoDriver.prototype.quitApplication = function (cmd, resp) {
- assert.firefox("Bug 1298921 - In app initiated quit not yet available beside Firefox")
-
- let flags = Ci.nsIAppStartup.eAttemptQuit;
- for (let k of cmd.parameters.flags || []) {
- flags |= Ci.nsIAppStartup[k];
- }
-
- this._server.acceptConnections = false;
- resp.send();
-
- this.deleteSession();
- Services.startup.quit(flags);
-};
-
-GeckoDriver.prototype.installAddon = function (cmd, resp) {
- assert.firefox()
-
- let path = cmd.parameters.path;
- let temp = cmd.parameters.temporary || false;
- if (typeof path == "undefined" || typeof path != "string" ||
- typeof temp != "boolean") {
- throw InvalidArgumentError();
- }
-
- return addon.install(path, temp);
-};
-
-GeckoDriver.prototype.uninstallAddon = function (cmd, resp) {
- assert.firefox()
-
- let id = cmd.parameters.id;
- if (typeof id == "undefined" || typeof id != "string") {
- throw new InvalidArgumentError();
- }
-
- return addon.uninstall(id);
-};
-
-/**
- * Helper function to convert an outerWindowID into a UID that Marionette
- * tracks.
- */
-GeckoDriver.prototype.generateFrameId = function (id) {
- let uid = id + (this.appName == "B2G" ? "-b2g" : "");
- return uid;
-};
-
-/** Receives all messages from content messageManager. */
-GeckoDriver.prototype.receiveMessage = function (message) {
- switch (message.name) {
- case "Marionette:ok":
- case "Marionette:done":
- case "Marionette:error":
- // check if we need to remove the mozbrowserclose listener
- if (this.mozBrowserClose !== null) {
- let win = this.getCurrentWindow();
- win.removeEventListener("mozbrowserclose", this.mozBrowserClose, true);
- this.mozBrowserClose = null;
- }
- break;
-
- case "Marionette:log":
- // log server-side messages
- logger.info(message.json.message);
- break;
-
- case "Marionette:shareData":
- // log messages from tests
- if (message.json.log) {
- this.marionetteLog.addAll(message.json.log);
- }
- break;
-
- case "Marionette:switchToModalOrigin":
- this.curBrowser.frameManager.switchToModalOrigin(message);
- this.mm = this.curBrowser.frameManager
- .currentRemoteFrame.messageManager.get();
- break;
-
- case "Marionette:switchedToFrame":
- if (message.json.restorePrevious) {
- this.currentFrameElement = this.previousFrameElement;
- } else {
- // we don't arbitrarily save previousFrameElement, since
- // we allow frame switching after modals appear, which would
- // override this value and we'd lose our reference
- if (message.json.storePrevious) {
- this.previousFrameElement = this.currentFrameElement;
- }
- this.currentFrameElement = message.json.frameValue;
- }
- break;
-
- case "Marionette:getVisibleCookies":
- let [currentPath, host] = message.json;
- let isForCurrentPath = path => currentPath.indexOf(path) != -1;
- let results = [];
-
- let en = cookieManager.getCookiesFromHost(host, {});
- while (en.hasMoreElements()) {
- let cookie = en.getNext().QueryInterface(Ci.nsICookie2);
- // take the hostname and progressively shorten
- let hostname = host;
- do {
- if ((cookie.host == "." + hostname || cookie.host == hostname) &&
- isForCurrentPath(cookie.path)) {
- results.push({
- "name": cookie.name,
- "value": cookie.value,
- "path": cookie.path,
- "host": cookie.host,
- "secure": cookie.isSecure,
- "expiry": cookie.expires,
- "httpOnly": cookie.isHttpOnly,
- "originAttributes": cookie.originAttributes
- });
- break;
- }
- hostname = hostname.replace(/^.*?\./, "");
- } while (hostname.indexOf(".") != -1);
- }
- return results;
-
- case "Marionette:emitTouchEvent":
- globalMessageManager.broadcastAsyncMessage(
- "MarionetteMainListener:emitTouchEvent", message.json);
- break;
-
- case "Marionette:register":
- let wid = message.json.value;
- let be = message.target;
- let rv = this.registerBrowser(wid, be);
- return rv;
-
- case "Marionette:listenersAttached":
- if (message.json.listenerId === this.curBrowser.curFrameId) {
- // If remoteness gets updated we need to call newSession. In the case
- // of desktop this just sets up a small amount of state that doesn't
- // change over the course of a session.
- this.sendAsync("newSession", this.capabilities);
- this.curBrowser.flushPendingCommands();
- }
- break;
- }
-};
-
-GeckoDriver.prototype.responseCompleted = function () {
- if (this.curBrowser !== null) {
- this.curBrowser.pendingCommands = [];
- }
-};
-
-/**
- * Retrieve the localized string for the specified entity id.
- *
- * Example:
- * localizeEntity(["chrome://global/locale/about.dtd"], "about.version")
- *
- * @param {Array.<string>} urls
- * Array of .dtd URLs.
- * @param {string} id
- * The ID of the entity to retrieve the localized string for.
- *
- * @return {string}
- * The localized string for the requested entity.
- */
-GeckoDriver.prototype.localizeEntity = function (cmd, resp) {
- let {urls, id} = cmd.parameters;
-
- if (!Array.isArray(urls)) {
- throw new InvalidArgumentError("Value of `urls` should be of type 'Array'");
- }
- if (typeof id != "string") {
- throw new InvalidArgumentError("Value of `id` should be of type 'string'");
- }
-
- resp.body.value = l10n.localizeEntity(urls, id);
-}
-
-/**
- * Retrieve the localized string for the specified property id.
- *
- * Example:
- * localizeProperty(["chrome://global/locale/findbar.properties"], "FastFind")
- *
- * @param {Array.<string>} urls
- * Array of .properties URLs.
- * @param {string} id
- * The ID of the property to retrieve the localized string for.
- *
- * @return {string}
- * The localized string for the requested property.
- */
-GeckoDriver.prototype.localizeProperty = function (cmd, resp) {
- let {urls, id} = cmd.parameters;
-
- if (!Array.isArray(urls)) {
- throw new InvalidArgumentError("Value of `urls` should be of type 'Array'");
- }
- if (typeof id != "string") {
- throw new InvalidArgumentError("Value of `id` should be of type 'string'");
- }
-
- resp.body.value = l10n.localizeProperty(urls, id);
-}
-
-GeckoDriver.prototype.commands = {
- "getMarionetteID": GeckoDriver.prototype.getMarionetteID,
- "sayHello": GeckoDriver.prototype.sayHello,
- "newSession": GeckoDriver.prototype.newSession,
- "getSessionCapabilities": GeckoDriver.prototype.getSessionCapabilities,
- "log": GeckoDriver.prototype.log,
- "getLogs": GeckoDriver.prototype.getLogs,
- "setContext": GeckoDriver.prototype.setContext,
- "getContext": GeckoDriver.prototype.getContext,
- "executeScript": GeckoDriver.prototype.executeScript,
- "getTimeouts": GeckoDriver.prototype.getTimeouts,
- "timeouts": GeckoDriver.prototype.setTimeouts, // deprecated until Firefox 55
- "setTimeouts": GeckoDriver.prototype.setTimeouts,
- "singleTap": GeckoDriver.prototype.singleTap,
- "performActions": GeckoDriver.prototype.performActions,
- "releaseActions": GeckoDriver.prototype.releaseActions,
- "actionChain": GeckoDriver.prototype.actionChain, // deprecated
- "multiAction": GeckoDriver.prototype.multiAction, // deprecated
- "executeAsyncScript": GeckoDriver.prototype.executeAsyncScript,
- "executeJSScript": GeckoDriver.prototype.executeJSScript,
- "findElement": GeckoDriver.prototype.findElement,
- "findElements": GeckoDriver.prototype.findElements,
- "clickElement": GeckoDriver.prototype.clickElement,
- "getElementAttribute": GeckoDriver.prototype.getElementAttribute,
- "getElementProperty": GeckoDriver.prototype.getElementProperty,
- "getElementText": GeckoDriver.prototype.getElementText,
- "getElementTagName": GeckoDriver.prototype.getElementTagName,
- "isElementDisplayed": GeckoDriver.prototype.isElementDisplayed,
- "getElementValueOfCssProperty": GeckoDriver.prototype.getElementValueOfCssProperty,
- "getElementRect": GeckoDriver.prototype.getElementRect,
- "isElementEnabled": GeckoDriver.prototype.isElementEnabled,
- "isElementSelected": GeckoDriver.prototype.isElementSelected,
- "sendKeysToElement": GeckoDriver.prototype.sendKeysToElement,
- "clearElement": GeckoDriver.prototype.clearElement,
- "getTitle": GeckoDriver.prototype.getTitle,
- "getWindowType": GeckoDriver.prototype.getWindowType,
- "getPageSource": GeckoDriver.prototype.getPageSource,
- "get": GeckoDriver.prototype.get,
- "getCurrentUrl": GeckoDriver.prototype.getCurrentUrl,
- "goBack": GeckoDriver.prototype.goBack,
- "goForward": GeckoDriver.prototype.goForward,
- "refresh": GeckoDriver.prototype.refresh,
- "getWindowHandle": GeckoDriver.prototype.getWindowHandle,
- "getChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
- "getCurrentChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
- "getWindowHandles": GeckoDriver.prototype.getWindowHandles,
- "getChromeWindowHandles": GeckoDriver.prototype.getChromeWindowHandles,
- "getWindowPosition": GeckoDriver.prototype.getWindowPosition,
- "setWindowPosition": GeckoDriver.prototype.setWindowPosition,
- "getActiveFrame": GeckoDriver.prototype.getActiveFrame,
- "switchToFrame": GeckoDriver.prototype.switchToFrame,
- "switchToParentFrame": GeckoDriver.prototype.switchToParentFrame,
- "switchToWindow": GeckoDriver.prototype.switchToWindow,
- "switchToShadowRoot": GeckoDriver.prototype.switchToShadowRoot,
- "deleteSession": GeckoDriver.prototype.deleteSession,
- "importScript": GeckoDriver.prototype.importScript,
- "clearImportedScripts": GeckoDriver.prototype.clearImportedScripts,
- "getAppCacheStatus": GeckoDriver.prototype.getAppCacheStatus,
- "close": GeckoDriver.prototype.close,
- "closeChromeWindow": GeckoDriver.prototype.closeChromeWindow,
- "setTestName": GeckoDriver.prototype.setTestName,
- "takeScreenshot": GeckoDriver.prototype.takeScreenshot,
- "addCookie": GeckoDriver.prototype.addCookie,
- "getCookies": GeckoDriver.prototype.getCookies,
- "deleteAllCookies": GeckoDriver.prototype.deleteAllCookies,
- "deleteCookie": GeckoDriver.prototype.deleteCookie,
- "getActiveElement": GeckoDriver.prototype.getActiveElement,
- "getScreenOrientation": GeckoDriver.prototype.getScreenOrientation,
- "setScreenOrientation": GeckoDriver.prototype.setScreenOrientation,
- "getWindowSize": GeckoDriver.prototype.getWindowSize,
- "setWindowSize": GeckoDriver.prototype.setWindowSize,
- "maximizeWindow": GeckoDriver.prototype.maximizeWindow,
- "dismissDialog": GeckoDriver.prototype.dismissDialog,
- "acceptDialog": GeckoDriver.prototype.acceptDialog,
- "getTextFromDialog": GeckoDriver.prototype.getTextFromDialog,
- "sendKeysToDialog": GeckoDriver.prototype.sendKeysToDialog,
- "acceptConnections": GeckoDriver.prototype.acceptConnections,
- "quitApplication": GeckoDriver.prototype.quitApplication,
-
- "localization:l10n:localizeEntity": GeckoDriver.prototype.localizeEntity,
- "localization:l10n:localizeProperty": GeckoDriver.prototype.localizeProperty,
-
- "addon:install": GeckoDriver.prototype.installAddon,
- "addon:uninstall": GeckoDriver.prototype.uninstallAddon,
-};
-
-function copy (obj) {
- if (Array.isArray(obj)) {
- return obj.slice();
- } else if (typeof obj == "object") {
- return Object.assign({}, obj);
- }
- return obj;
-}
-
-/**
- * Get the outer window ID for the specified window.
- *
- * @param {nsIDOMWindow} win
- * Window whose browser we need to access.
- *
- * @return {string}
- * Returns the unique window ID.
- */
-function getOuterWindowId(win) {
- let id = win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .outerWindowID;
-
- return id.toString();
-}
diff --git a/testing/marionette/element.js b/testing/marionette/element.js
deleted file mode 100644
index 9687fb27d4..0000000000
--- a/testing/marionette/element.js
+++ /dev/null
@@ -1,1171 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/atom.js");
-Cu.import("chrome://marionette/content/error.js");
-
-const logger = Log.repository.getLogger("Marionette");
-
-/**
- * This module provides shared functionality for dealing with DOM-
- * and web elements in Marionette.
- *
- * A web element is an abstraction used to identify an element when it
- * is transported across the protocol, between remote- and local ends.
- *
- * Each element has an associated web element reference (a UUID) that
- * uniquely identifies the the element across all browsing contexts. The
- * web element reference for every element representing the same element
- * is the same.
- *
- * The @code{element.Store} provides a mapping between web element
- * references and DOM elements for each browsing context. It also provides
- * functionality for looking up and retrieving elements.
- */
-
-this.EXPORTED_SYMBOLS = ["element"];
-
-const DOCUMENT_POSITION_DISCONNECTED = 1;
-const XMLNS = "http://www.w3.org/1999/xhtml";
-
-const uuidGen = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
-
-this.element = {};
-
-element.Key = "element-6066-11e4-a52e-4f735466cecf";
-element.LegacyKey = "ELEMENT";
-
-element.Strategy = {
- ClassName: "class name",
- Selector: "css selector",
- ID: "id",
- Name: "name",
- LinkText: "link text",
- PartialLinkText: "partial link text",
- TagName: "tag name",
- XPath: "xpath",
- Anon: "anon",
- AnonAttribute: "anon attribute",
-};
-
-/**
- * Stores known/seen elements and their associated web element
- * references.
- *
- * Elements are added by calling |add(el)| or |addAll(elements)|, and
- * may be queried by their web element reference using |get(element)|.
- */
-element.Store = class {
- constructor() {
- this.els = {};
- this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- }
-
- clear() {
- this.els = {};
- }
-
- /**
- * Make a collection of elements seen.
- *
- * The oder of the returned web element references is guaranteed to
- * match that of the collection passed in.
- *
- * @param {NodeList} els
- * Sequence of elements to add to set of seen elements.
- *
- * @return {Array.<WebElement>}
- * List of the web element references associated with each element
- * from |els|.
- */
- addAll(els) {
- let add = this.add.bind(this);
- return [...els].map(add);
- }
-
- /**
- * Make an element seen.
- *
- * @param {nsIDOMElement} el
- * Element to add to set of seen elements.
- *
- * @return {string}
- * Web element reference associated with element.
- */
- add(el) {
- for (let i in this.els) {
- let foundEl;
- try {
- foundEl = this.els[i].get();
- } catch (e) {}
-
- if (foundEl) {
- if (new XPCNativeWrapper(foundEl) == new XPCNativeWrapper(el)) {
- return i;
- }
-
- // cleanup reference to gc'd element
- } else {
- delete this.els[i];
- }
- }
-
- let id = element.generateUUID();
- this.els[id] = Cu.getWeakReference(el);
- return id;
- }
-
- /**
- * Determine if the provided web element reference has been seen
- * before/is in the element store.
- *
- * @param {string} uuid
- * Element's associated web element reference.
- *
- * @return {boolean}
- * True if element is in the store, false otherwise.
- */
- has(uuid) {
- return Object.keys(this.els).includes(uuid);
- }
-
- /**
- * Retrieve a DOM element by its unique web element reference/UUID.
- *
- * @param {string} uuid
- * Web element reference, or UUID.
- * @param {(nsIDOMWindow|ShadowRoot)} container
- * Window and an optional shadow root that contains the element.
- *
- * @returns {nsIDOMElement}
- * Element associated with reference.
- *
- * @throws {JavaScriptError}
- * If the provided reference is unknown.
- * @throws {StaleElementReferenceError}
- * If element has gone stale, indicating it is no longer attached to
- * the DOM provided in the container.
- */
- get(uuid, container) {
- let el = this.els[uuid];
- if (!el) {
- throw new JavaScriptError(`Element reference not seen before: ${uuid}`);
- }
-
- try {
- el = el.get();
- } catch (e) {
- el = null;
- delete this.els[id];
- }
-
- // use XPCNativeWrapper to compare elements (see bug 834266)
- let wrappedFrame = new XPCNativeWrapper(container.frame);
- let wrappedShadowRoot;
- if (container.shadowRoot) {
- wrappedShadowRoot = new XPCNativeWrapper(container.shadowRoot);
- }
- let wrappedEl = new XPCNativeWrapper(el);
- let wrappedContainer = {
- frame: wrappedFrame,
- shadowRoot: wrappedShadowRoot,
- };
- if (!el ||
- !(wrappedEl.ownerDocument == wrappedFrame.document) ||
- element.isDisconnected(wrappedEl, wrappedContainer)) {
- throw new StaleElementReferenceError(
- error.pprint`The element reference of ${el} stale: ` +
- "either the element is no longer attached to the DOM " +
- "or the page has been refreshed");
- }
-
- return el;
- }
-};
-
-/**
- * Find a single element or a collection of elements starting at the
- * document root or a given node.
- *
- * If |timeout| is above 0, an implicit search technique is used.
- * This will wait for the duration of |timeout| for the element
- * to appear in the DOM.
- *
- * See the |element.Strategy| enum for a full list of supported
- * search strategies that can be passed to |strategy|.
- *
- * Available flags for |opts|:
- *
- * |all|
- * If true, a multi-element search selector is used and a sequence
- * of elements will be returned. Otherwise a single element.
- *
- * |timeout|
- * Duration to wait before timing out the search. If |all| is
- * false, a NoSuchElementError is thrown if unable to find
- * the element within the timeout duration.
- *
- * |startNode|
- * Element to use as the root of the search.
- *
- * @param {Object.<string, Window>} container
- * Window object and an optional shadow root that contains the
- * root shadow DOM element.
- * @param {string} strategy
- * Search strategy whereby to locate the element(s).
- * @param {string} selector
- * Selector search pattern. The selector must be compatible with
- * the chosen search |strategy|.
- * @param {Object.<string, ?>} opts
- * Options.
- *
- * @return {Promise: (nsIDOMElement|Array<nsIDOMElement>)}
- * Single element or a sequence of elements.
- *
- * @throws InvalidSelectorError
- * If |strategy| is unknown.
- * @throws InvalidSelectorError
- * If |selector| is malformed.
- * @throws NoSuchElementError
- * If a single element is requested, this error will throw if the
- * element is not found.
- */
-element.find = function (container, strategy, selector, opts = {}) {
- opts.all = !!opts.all;
- opts.timeout = opts.timeout || 0;
-
- let searchFn;
- if (opts.all) {
- searchFn = findElements.bind(this);
- } else {
- searchFn = findElement.bind(this);
- }
-
- return new Promise((resolve, reject) => {
- let findElements = implicitlyWaitFor(
- () => find_(container, strategy, selector, searchFn, opts),
- opts.timeout);
-
- findElements.then(foundEls => {
- // the following code ought to be moved into findElement
- // and findElements when bug 1254486 is addressed
- if (!opts.all && (!foundEls || foundEls.length == 0)) {
- let msg;
- switch (strategy) {
- case element.Strategy.AnonAttribute:
- msg = "Unable to locate anonymous element: " + JSON.stringify(selector);
- break;
-
- default:
- msg = "Unable to locate element: " + selector;
- }
-
- reject(new NoSuchElementError(msg));
- }
-
- if (opts.all) {
- resolve(foundEls);
- }
- resolve(foundEls[0]);
- }, reject);
- });
-};
-
-function find_(container, strategy, selector, searchFn, opts) {
- let rootNode = container.shadowRoot || container.frame.document;
- let startNode;
-
- if (opts.startNode) {
- startNode = opts.startNode;
- } else {
- switch (strategy) {
- // For anonymous nodes the start node needs to be of type DOMElement, which
- // will refer to :root in case of a DOMDocument.
- case element.Strategy.Anon:
- case element.Strategy.AnonAttribute:
- if (rootNode instanceof Ci.nsIDOMDocument) {
- startNode = rootNode.documentElement;
- }
- break;
-
- default:
- startNode = rootNode;
- }
- }
-
- let res;
- try {
- res = searchFn(strategy, selector, rootNode, startNode);
- } catch (e) {
- throw new InvalidSelectorError(
- `Given ${strategy} expression "${selector}" is invalid: ${e}`);
- }
-
- if (res) {
- if (opts.all) {
- return res;
- }
- return [res];
- }
- return [];
-}
-
-/**
- * Find a single element by XPath expression.
- *
- * @param {DOMElement} root
- * Document root
- * @param {DOMElement} startNode
- * Where in the DOM hiearchy to begin searching.
- * @param {string} expr
- * XPath search expression.
- *
- * @return {DOMElement}
- * First element matching expression.
- */
-element.findByXPath = function (root, startNode, expr) {
- let iter = root.evaluate(expr, startNode, null,
- Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
- return iter.singleNodeValue;
-};
-
-/**
- * Find elements by XPath expression.
- *
- * @param {DOMElement} root
- * Document root.
- * @param {DOMElement} startNode
- * Where in the DOM hierarchy to begin searching.
- * @param {string} expr
- * XPath search expression.
- *
- * @return {Array.<DOMElement>}
- * Sequence of found elements matching expression.
- */
-element.findByXPathAll = function (root, startNode, expr) {
- let rv = [];
- let iter = root.evaluate(expr, startNode, null,
- Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
- let el = iter.iterateNext();
- while (el) {
- rv.push(el);
- el = iter.iterateNext();
- }
- return rv;
-};
-
-/**
- * Find all hyperlinks dscendant of |node| which link text is |s|.
- *
- * @param {DOMElement} node
- * Where in the DOM hierarchy to being searching.
- * @param {string} s
- * Link text to search for.
- *
- * @return {Array.<DOMAnchorElement>}
- * Sequence of link elements which text is |s|.
- */
-element.findByLinkText = function (node, s) {
- return filterLinks(node, link => link.text.trim() === s);
-};
-
-/**
- * Find all hyperlinks descendant of |node| which link text contains |s|.
- *
- * @param {DOMElement} node
- * Where in the DOM hierachy to begin searching.
- * @param {string} s
- * Link text to search for.
- *
- * @return {Array.<DOMAnchorElement>}
- * Sequence of link elements which text containins |s|.
- */
-element.findByPartialLinkText = function (node, s) {
- return filterLinks(node, link => link.text.indexOf(s) != -1);
-};
-
-/**
- * Filters all hyperlinks that are descendant of |node| by |predicate|.
- *
- * @param {DOMElement} node
- * Where in the DOM hierarchy to begin searching.
- * @param {function(DOMAnchorElement): boolean} predicate
- * Function that determines if given link should be included in
- * return value or filtered away.
- *
- * @return {Array.<DOMAnchorElement>}
- * Sequence of link elements matching |predicate|.
- */
-function filterLinks(node, predicate) {
- let rv = [];
- for (let link of node.getElementsByTagName("a")) {
- if (predicate(link)) {
- rv.push(link);
- }
- }
- return rv;
-}
-
-/**
- * Finds a single element.
- *
- * @param {element.Strategy} using
- * Selector strategy to use.
- * @param {string} value
- * Selector expression.
- * @param {DOMElement} rootNode
- * Document root.
- * @param {DOMElement=} startNode
- * Optional node from which to start searching.
- *
- * @return {DOMElement}
- * Found elements.
- *
- * @throws {InvalidSelectorError}
- * If strategy |using| is not recognised.
- * @throws {Error}
- * If selector expression |value| is malformed.
- */
-function findElement(using, value, rootNode, startNode) {
- switch (using) {
- case element.Strategy.ID:
- if (startNode.getElementById) {
- return startNode.getElementById(value);
- }
- return element.findByXPath(rootNode, startNode, `.//*[@id="${value}"]`);
-
- case element.Strategy.Name:
- if (startNode.getElementsByName) {
- return startNode.getElementsByName(value)[0];
- }
- return element.findByXPath(rootNode, startNode, `.//*[@name="${value}"]`);
-
- case element.Strategy.ClassName:
- // works for >= Firefox 3
- return startNode.getElementsByClassName(value)[0];
-
- case element.Strategy.TagName:
- // works for all elements
- return startNode.getElementsByTagName(value)[0];
-
- case element.Strategy.XPath:
- return element.findByXPath(rootNode, startNode, value);
-
- case element.Strategy.LinkText:
- for (let link of startNode.getElementsByTagName("a")) {
- if (link.text.trim() === value) {
- return link;
- }
- }
- break;
-
- case element.Strategy.PartialLinkText:
- for (let link of startNode.getElementsByTagName("a")) {
- if (link.text.indexOf(value) != -1) {
- return link;
- }
- }
- break;
-
- case element.Strategy.Selector:
- try {
- return startNode.querySelector(value);
- } catch (e) {
- throw new InvalidSelectorError(`${e.message}: "${value}"`);
- }
- break;
-
- case element.Strategy.Anon:
- return rootNode.getAnonymousNodes(startNode);
-
- case element.Strategy.AnonAttribute:
- let attr = Object.keys(value)[0];
- return rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]);
-
- default:
- throw new InvalidSelectorError(`No such strategy: ${using}`);
- }
-}
-
-/**
- * Find multiple elements.
- *
- * @param {element.Strategy} using
- * Selector strategy to use.
- * @param {string} value
- * Selector expression.
- * @param {DOMElement} rootNode
- * Document root.
- * @param {DOMElement=} startNode
- * Optional node from which to start searching.
- *
- * @return {DOMElement}
- * Found elements.
- *
- * @throws {InvalidSelectorError}
- * If strategy |using| is not recognised.
- * @throws {Error}
- * If selector expression |value| is malformed.
- */
-function findElements(using, value, rootNode, startNode) {
- switch (using) {
- case element.Strategy.ID:
- value = `.//*[@id="${value}"]`;
-
- // fall through
- case element.Strategy.XPath:
- return element.findByXPathAll(rootNode, startNode, value);
-
- case element.Strategy.Name:
- if (startNode.getElementsByName) {
- return startNode.getElementsByName(value);
- }
- return element.findByXPathAll(rootNode, startNode, `.//*[@name="${value}"]`);
-
- case element.Strategy.ClassName:
- return startNode.getElementsByClassName(value);
-
- case element.Strategy.TagName:
- return startNode.getElementsByTagName(value);
-
- case element.Strategy.LinkText:
- return element.findByLinkText(startNode, value);
-
- case element.Strategy.PartialLinkText:
- return element.findByPartialLinkText(startNode, value);
-
- case element.Strategy.Selector:
- return startNode.querySelectorAll(value);
-
- case element.Strategy.Anon:
- return rootNode.getAnonymousNodes(startNode);
-
- case element.Strategy.AnonAttribute:
- let attr = Object.keys(value)[0];
- let el = rootNode.getAnonymousElementByAttribute(startNode, attr, value[attr]);
- if (el) {
- return [el];
- }
- return [];
-
- default:
- throw new InvalidSelectorError(`No such strategy: ${using}`);
- }
-}
-
-/**
- * Runs function off the main thread until its return value is truthy
- * or the provided timeout is reached. The function is guaranteed to be
- * run at least once, irregardless of the timeout.
- *
- * A truthy return value constitutes a truthful boolean, positive number,
- * object, or non-empty array.
- *
- * The |func| is evaluated every |interval| for as long as its runtime
- * duration does not exceed |interval|. If the runtime evaluation duration
- * of |func| is greater than |interval|, evaluations of |func| are queued.
- *
- * @param {function(): ?} func
- * Function to run off the main thread.
- * @param {number} timeout
- * Desired timeout. If 0 or less than the runtime evaluation time
- * of |func|, |func| is guaranteed to run at least once.
- * @param {number=} interval
- * Duration between each poll of |func| in milliseconds. Defaults to
- * 100 milliseconds.
- *
- * @return {Promise}
- * Yields the return value from |func|. The promise is rejected if
- * |func| throws.
- */
-function implicitlyWaitFor(func, timeout, interval = 100) {
- let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-
- return new Promise((resolve, reject) => {
- let startTime = new Date().getTime();
- let endTime = startTime + timeout;
-
- let elementSearch = function() {
- let res;
- try {
- res = func();
- } catch (e) {
- reject(e);
- }
-
- if (
- // collections that might contain web elements
- // should be checked until they are not empty
- (element.isCollection(res) && res.length > 0)
-
- // !![] (ensuring boolean type on empty array) always returns true
- // and we can only use it on non-collections
- || (!element.isCollection(res) && !!res)
-
- // return immediately if timeout is 0,
- // allowing |func| to be evaluted at least once
- || startTime == endTime
-
- // return if timeout has elapsed
- || new Date().getTime() >= endTime
- ) {
- resolve(res);
- }
- };
-
- // the repeating slack timer waits |interval|
- // before invoking |elementSearch|
- elementSearch();
-
- timer.init(elementSearch, interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
-
- // cancel timer and propagate result
- }).then(res => {
- timer.cancel();
- return res;
- }, err => {
- timer.cancel();
- throw err;
- });
-}
-
-/** Determines if |obj| is an HTML or JS collection. */
-element.isCollection = function (seq) {
- switch (Object.prototype.toString.call(seq)) {
- case "[object Arguments]":
- case "[object Array]":
- case "[object FileList]":
- case "[object HTMLAllCollection]":
- case "[object HTMLCollection]":
- case "[object HTMLFormControlsCollection]":
- case "[object HTMLOptionsCollection]":
- case "[object NodeList]":
- return true;
-
- default:
- return false;
- }
-};
-
-element.makeWebElement = function (uuid) {
- return {
- [element.Key]: uuid,
- [element.LegacyKey]: uuid,
- };
-};
-
-/**
- * Checks if |ref| has either |element.Key| or |element.LegacyKey| as properties.
- *
- * @param {?} ref
- * Object that represents a web element reference.
- * @return {boolean}
- * True if |ref| has either expected property.
- */
-element.isWebElementReference = function (ref) {
- let properties = Object.getOwnPropertyNames(ref);
- return properties.includes(element.Key) || properties.includes(element.LegacyKey);
-};
-
-element.generateUUID = function() {
- let uuid = uuidGen.generateUUID().toString();
- return uuid.substring(1, uuid.length - 1);
-};
-
-/**
- * Convert any web elements in arbitrary objects to DOM elements by
- * looking them up in the seen element store.
- *
- * @param {?} obj
- * Arbitrary object containing web elements.
- * @param {element.Store} seenEls
- * Element store to use for lookup of web element references.
- * @param {Window} win
- * Window.
- * @param {ShadowRoot} shadowRoot
- * Shadow root.
- *
- * @return {?}
- * Same object as provided by |obj| with the web elements replaced
- * by DOM elements.
- */
-element.fromJson = function (
- obj, seenEls, win, shadowRoot = undefined) {
- switch (typeof obj) {
- case "boolean":
- case "number":
- case "string":
- return obj;
-
- case "object":
- if (obj === null) {
- return obj;
- }
-
- // arrays
- else if (Array.isArray(obj)) {
- return obj.map(e => element.fromJson(e, seenEls, win, shadowRoot));
- }
-
- // web elements
- else if (Object.keys(obj).includes(element.Key) ||
- Object.keys(obj).includes(element.LegacyKey)) {
- let uuid = obj[element.Key] || obj[element.LegacyKey];
- let el = seenEls.get(uuid, {frame: win, shadowRoot: shadowRoot});
- if (!el) {
- throw new WebDriverError(`Unknown element: ${uuid}`);
- }
- return el;
- }
-
- // arbitrary objects
- else {
- let rv = {};
- for (let prop in obj) {
- rv[prop] = element.fromJson(obj[prop], seenEls, win, shadowRoot);
- }
- return rv;
- }
- }
-};
-
-/**
- * Convert arbitrary objects to JSON-safe primitives that can be
- * transported over the Marionette protocol.
- *
- * Any DOM elements are converted to web elements by looking them up
- * and/or adding them to the element store provided.
- *
- * @param {?} obj
- * Object to be marshaled.
- * @param {element.Store} seenEls
- * Element store to use for lookup of web element references.
- *
- * @return {?}
- * Same object as provided by |obj| with the elements replaced by
- * web elements.
- */
-element.toJson = function (obj, seenEls) {
- let t = Object.prototype.toString.call(obj);
-
- // null
- if (t == "[object Undefined]" || t == "[object Null]") {
- return null;
- }
-
- // literals
- else if (t == "[object Boolean]" || t == "[object Number]" || t == "[object String]") {
- return obj;
- }
-
- // Array, NodeList, HTMLCollection, et al.
- else if (element.isCollection(obj)) {
- return [...obj].map(el => element.toJson(el, seenEls));
- }
-
- // HTMLElement
- else if ("nodeType" in obj && obj.nodeType == 1) {
- let uuid = seenEls.add(obj);
- return element.makeWebElement(uuid);
- }
-
- // arbitrary objects + files
- else {
- let rv = {};
- for (let prop in obj) {
- try {
- rv[prop] = element.toJson(obj[prop], seenEls);
- } catch (e if (e.result == Cr.NS_ERROR_NOT_IMPLEMENTED)) {
- logger.debug(`Skipping ${prop}: ${e.message}`);
- }
- }
- return rv;
- }
-};
-
-/**
- * Check if the element is detached from the current frame as well as
- * the optional shadow root (when inside a Shadow DOM context).
- *
- * @param {nsIDOMElement} el
- * Element to be checked.
- * @param {Container} container
- * Container with |frame|, which is the window object that contains
- * the element, and an optional |shadowRoot|.
- *
- * @return {boolean}
- * Flag indicating that the element is disconnected.
- */
-element.isDisconnected = function (el, container = {}) {
- const {frame, shadowRoot} = container;
- assert.defined(frame);
-
- // shadow dom
- if (frame.ShadowRoot && shadowRoot) {
- if (el.compareDocumentPosition(shadowRoot) &
- DOCUMENT_POSITION_DISCONNECTED) {
- return true;
- }
-
- // looking for next possible ShadowRoot ancestor
- let parent = shadowRoot.host;
- while (parent && !(parent instanceof frame.ShadowRoot)) {
- parent = parent.parentNode;
- }
- return element.isDisconnected(
- shadowRoot.host,
- {frame: frame, shadowRoot: parent});
-
- // outside shadow dom
- } else {
- let docEl = frame.document.documentElement;
- return el.compareDocumentPosition(docEl) &
- DOCUMENT_POSITION_DISCONNECTED;
- }
-};
-
-/**
- * This function generates a pair of coordinates relative to the viewport
- * given a target element and coordinates relative to that element's
- * top-left corner.
- *
- * @param {Node} node
- * Target node.
- * @param {number=} xOffset
- * Horizontal offset relative to target's top-left corner.
- * Defaults to the centre of the target's bounding box.
- * @param {number=} yOffset
- * Vertical offset relative to target's top-left corner. Defaults to
- * the centre of the target's bounding box.
- *
- * @return {Object.<string, number>}
- * X- and Y coordinates.
- *
- * @throws TypeError
- * If |xOffset| or |yOffset| are not numbers.
- */
-element.coordinates = function (
- node, xOffset = undefined, yOffset = undefined) {
-
- let box = node.getBoundingClientRect();
-
- if (typeof xOffset == "undefined" || xOffset === null) {
- xOffset = box.width / 2.0;
- }
- if (typeof yOffset == "undefined" || yOffset === null) {
- yOffset = box.height / 2.0;
- }
-
- if (typeof yOffset != "number" || typeof xOffset != "number") {
- throw new TypeError("Offset must be a number");
- }
-
- return {
- x: box.left + xOffset,
- y: box.top + yOffset,
- };
-};
-
-/**
- * This function returns true if the node is in the viewport.
- *
- * @param {Element} el
- * Target element.
- * @param {number=} x
- * Horizontal offset relative to target. Defaults to the centre of
- * the target's bounding box.
- * @param {number=} y
- * Vertical offset relative to target. Defaults to the centre of
- * the target's bounding box.
- *
- * @return {boolean}
- * True if if |el| is in viewport, false otherwise.
- */
-element.inViewport = function (el, x = undefined, y = undefined) {
- let win = el.ownerDocument.defaultView;
- let c = element.coordinates(el, x, y);
- let vp = {
- top: win.pageYOffset,
- left: win.pageXOffset,
- bottom: (win.pageYOffset + win.innerHeight),
- right: (win.pageXOffset + win.innerWidth)
- };
-
- return (vp.left <= c.x + win.pageXOffset &&
- c.x + win.pageXOffset <= vp.right &&
- vp.top <= c.y + win.pageYOffset &&
- c.y + win.pageYOffset <= vp.bottom);
-};
-
-/**
- * Gets the element's container element.
- *
- * An element container is defined by the WebDriver
- * specification to be an <option> element in a valid element context
- * (https://html.spec.whatwg.org/#concept-element-contexts), meaning
- * that it has an ancestral element that is either <datalist> or <select>.
- *
- * If the element does not have a valid context, its container element
- * is itself.
- *
- * @param {Element} el
- * Element to get the container of.
- *
- * @return {Element}
- * Container element of |el|.
- */
-element.getContainer = function (el) {
- if (el.localName != "option") {
- return el;
- }
-
- function validContext(ctx) {
- return ctx.localName == "datalist" || ctx.localName == "select";
- }
-
- // does <option> have a valid context,
- // meaning is it a child of <datalist> or <select>?
- let parent = el;
- while (parent.parentNode && !validContext(parent)) {
- parent = parent.parentNode;
- }
-
- if (!validContext(parent)) {
- return el;
- }
- return parent;
-};
-
-/**
- * An element is in view if it is a member of its own pointer-interactable
- * paint tree.
- *
- * This means an element is considered to be in view, but not necessarily
- * pointer-interactable, if it is found somewhere in the
- * |elementsFromPoint| list at |el|'s in-view centre coordinates.
- *
- * Before running the check, we change |el|'s pointerEvents style property
- * to "auto", since elements without pointer events enabled do not turn
- * up in the paint tree we get from document.elementsFromPoint. This is
- * a specialisation that is only relevant when checking if the element is
- * in view.
- *
- * @param {Element} el
- * Element to check if is in view.
- *
- * @return {boolean}
- * True if |el| is inside the viewport, or false otherwise.
- */
-element.isInView = function (el) {
- let originalPointerEvents = el.style.pointerEvents;
- try {
- el.style.pointerEvents = "auto";
- const tree = element.getPointerInteractablePaintTree(el);
- return tree.includes(el);
- } finally {
- el.style.pointerEvents = originalPointerEvents;
- }
-};
-
-/**
- * This function throws the visibility of the element error if the element is
- * not displayed or the given coordinates are not within the viewport.
- *
- * @param {Element} el
- * Element to check if visible.
- * @param {number=} x
- * Horizontal offset relative to target. Defaults to the centre of
- * the target's bounding box.
- * @param {number=} y
- * Vertical offset relative to target. Defaults to the centre of
- * the target's bounding box.
- *
- * @return {boolean}
- * True if visible, false otherwise.
- */
-element.isVisible = function (el, x = undefined, y = undefined) {
- let win = el.ownerDocument.defaultView;
-
- // Bug 1094246: webdriver's isShown doesn't work with content xul
- if (!element.isXULElement(el) && !atom.isElementDisplayed(el, win)) {
- return false;
- }
-
- if (el.tagName.toLowerCase() == "body") {
- return true;
- }
-
- if (!element.inViewport(el, x, y)) {
- element.scrollIntoView(el);
- if (!element.inViewport(el)) {
- return false;
- }
- }
- return true;
-};
-
-/**
- * A pointer-interactable element is defined to be the first
- * non-transparent element, defined by the paint order found at the centre
- * point of its rectangle that is inside the viewport, excluding the size
- * of any rendered scrollbars.
- *
- * @param {DOMElement} el
- * Element determine if is pointer-interactable.
- *
- * @return {boolean}
- * True if interactable, false otherwise.
- */
-element.isPointerInteractable = function (el) {
- let tree = element.getPointerInteractablePaintTree(el);
- return tree[0] === el;
-};
-
-/**
- * Calculate the in-view centre point of the area of the given DOM client
- * rectangle that is inside the viewport.
- *
- * @param {DOMRect} rect
- * Element off a DOMRect sequence produced by calling |getClientRects|
- * on a |DOMElement|.
- * @param {nsIDOMWindow} win
- * Current browsing context.
- *
- * @return {Map.<string, number>}
- * X and Y coordinates that denotes the in-view centre point of |rect|.
- */
-element.getInViewCentrePoint = function (rect, win) {
- const {max, min} = Math;
-
- let x = {
- left: max(0, min(rect.x, rect.x + rect.width)),
- right: min(win.innerWidth, max(rect.x, rect.x + rect.width)),
- };
- let y = {
- top: max(0, min(rect.y, rect.y + rect.height)),
- bottom: min(win.innerHeight, max(rect.y, rect.y + rect.height)),
- };
-
- return {
- x: (x.left + x.right) / 2,
- y: (y.top + y.bottom) / 2,
- };
-};
-
-/**
- * Produces a pointer-interactable elements tree from a given element.
- *
- * The tree is defined by the paint order found at the centre point of
- * the element's rectangle that is inside the viewport, excluding the size
- * of any rendered scrollbars.
- *
- * @param {DOMElement} el
- * Element to determine if is pointer-interactable.
- *
- * @return {Array.<DOMElement>}
- * Sequence of elements in paint order.
- */
-element.getPointerInteractablePaintTree = function (el) {
- const doc = el.ownerDocument;
- const win = doc.defaultView;
-
- // pointer-interactable elements tree, step 1
- if (element.isDisconnected(el, {frame: win})) {
- return [];
- }
-
- // steps 2-3
- let rects = el.getClientRects();
- if (rects.length == 0) {
- return [];
- }
-
- // step 4
- let centre = element.getInViewCentrePoint(rects[0], win);
-
- // step 5
- return doc.elementsFromPoint(centre.x, centre.y);
-};
-
-// TODO(ato): Not implemented.
-// In fact, it's not defined in the spec.
-element.isKeyboardInteractable = function (el) {
- return true;
-};
-
-/**
- * Attempts to scroll into view |el|.
- *
- * @param {DOMElement} el
- * Element to scroll into view.
- */
-element.scrollIntoView = function (el) {
- if (el.scrollIntoView) {
- el.scrollIntoView({block: "end", inline: "nearest", behavior: "instant"});
- }
-};
-
-element.isXULElement = function (el) {
- let ns = atom.getElementAttribute(el, "namespaceURI");
- return ns.indexOf("there.is.only.xul") >= 0;
-};
-
-const boolEls = {
- audio: ["autoplay", "controls", "loop", "muted"],
- button: ["autofocus", "disabled", "formnovalidate"],
- details: ["open"],
- dialog: ["open"],
- fieldset: ["disabled"],
- form: ["novalidate"],
- iframe: ["allowfullscreen"],
- img: ["ismap"],
- input: ["autofocus", "checked", "disabled", "formnovalidate", "multiple", "readonly", "required"],
- keygen: ["autofocus", "disabled"],
- menuitem: ["checked", "default", "disabled"],
- object: ["typemustmatch"],
- ol: ["reversed"],
- optgroup: ["disabled"],
- option: ["disabled", "selected"],
- script: ["async", "defer"],
- select: ["autofocus", "disabled", "multiple", "required"],
- textarea: ["autofocus", "disabled", "readonly", "required"],
- track: ["default"],
- video: ["autoplay", "controls", "loop", "muted"],
-};
-
-/**
- * Tests if the attribute is a boolean attribute on element.
- *
- * @param {DOMElement} el
- * Element to test if |attr| is a boolean attribute on.
- * @param {string} attr
- * Attribute to test is a boolean attribute.
- *
- * @return {boolean}
- * True if the attribute is boolean, false otherwise.
- */
-element.isBooleanAttribute = function (el, attr) {
- if (el.namespaceURI !== XMLNS) {
- return false;
- }
-
- // global boolean attributes that apply to all HTML elements,
- // except for custom elements
- if ((attr == "hidden" || attr == "itemscope") && !el.localName.includes("-")) {
- return true;
- }
-
- if (!boolEls.hasOwnProperty(el.localName)) {
- return false;
- }
- return boolEls[el.localName].includes(attr)
-};
diff --git a/testing/marionette/error.js b/testing/marionette/error.js
deleted file mode 100644
index c36dace256..0000000000
--- a/testing/marionette/error.js
+++ /dev/null
@@ -1,500 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {interfaces: Ci, utils: Cu} = Components;
-
-const ERRORS = new Set([
- "ElementClickInterceptedError",
- "ElementNotAccessibleError",
- "ElementNotInteractableError",
- "InsecureCertificateError",
- "InvalidArgumentError",
- "InvalidElementStateError",
- "InvalidSelectorError",
- "InvalidSessionIDError",
- "JavaScriptError",
- "MoveTargetOutOfBoundsError",
- "NoAlertOpenError",
- "NoSuchElementError",
- "NoSuchFrameError",
- "NoSuchWindowError",
- "ScriptTimeoutError",
- "SessionNotCreatedError",
- "StaleElementReferenceError",
- "TimeoutError",
- "UnableToSetCookieError",
- "UnknownCommandError",
- "UnknownError",
- "UnsupportedOperationError",
- "WebDriverError",
-]);
-
-const BUILTIN_ERRORS = new Set([
- "Error",
- "EvalError",
- "InternalError",
- "RangeError",
- "ReferenceError",
- "SyntaxError",
- "TypeError",
- "URIError",
-]);
-
-this.EXPORTED_SYMBOLS = ["error"].concat(Array.from(ERRORS));
-
-this.error = {};
-
-/**
- * Checks if obj is an instance of the Error prototype in a safe manner.
- * Prefer using this over using instanceof since the Error prototype
- * isn't unique across browsers, and XPCOM nsIException's are special
- * snowflakes.
- *
- * @param {*} val
- * Any value that should be undergo the test for errorness.
- * @return {boolean}
- * True if error, false otherwise.
- */
-error.isError = function (val) {
- if (val === null || typeof val != "object") {
- return false;
- } else if (val instanceof Ci.nsIException) {
- return true;
- } else {
- // DOMRectList errors on string comparison
- try {
- let proto = Object.getPrototypeOf(val);
- return BUILTIN_ERRORS.has(proto.toString());
- } catch (e) {
- return false;
- }
- }
-};
-
-/**
- * Checks if obj is an object in the WebDriverError prototypal chain.
- */
-error.isWebDriverError = function (obj) {
- return error.isError(obj) &&
- ("name" in obj && ERRORS.has(obj.name));
-};
-
-/**
- * Wraps any error as a WebDriverError. If the given error is already in
- * the WebDriverError prototype chain, this function returns it
- * unmodified.
- */
-error.wrap = function (err) {
- if (error.isWebDriverError(err)) {
- return err;
- }
- return new WebDriverError(err);
-};
-
-/**
- * Unhandled error reporter. Dumps the error and its stacktrace to console,
- * and reports error to the Browser Console.
- */
-error.report = function (err) {
- let msg = "Marionette threw an error: " + error.stringify(err);
- dump(msg + "\n");
- if (Cu.reportError) {
- Cu.reportError(msg);
- }
-};
-
-/**
- * Prettifies an instance of Error and its stacktrace to a string.
- */
-error.stringify = function (err) {
- try {
- let s = err.toString();
- if ("stack" in err) {
- s += "\n" + err.stack;
- }
- return s;
- } catch (e) {
- return "<unprintable error>";
- }
-};
-
-/**
- * Pretty-print values passed to template strings.
- *
- * Usage:
- *
- * let bool = {value: true};
- * error.pprint`Expected boolean, got ${bool}`;
- * => 'Expected boolean, got [object Object] {"value": true}'
- *
- * let htmlElement = document.querySelector("input#foo");
- * error.pprint`Expected element ${htmlElement}`;
- * => 'Expected element <input id="foo" class="bar baz">'
- */
-error.pprint = function (ss, ...values) {
- function prettyObject (obj) {
- let proto = Object.prototype.toString.call(obj);
- let s = "";
- try {
- s = JSON.stringify(obj);
- } catch (e if e instanceof TypeError) {
- s = `<${e.message}>`;
- }
- return proto + " " + s;
- }
-
- function prettyElement (el) {
- let ident = [];
- if (el.id) {
- ident.push(`id="${el.id}"`);
- }
- if (el.classList.length > 0) {
- ident.push(`class="${el.className}"`);
- }
-
- let idents = "";
- if (ident.length > 0) {
- idents = " " + ident.join(" ");
- }
-
- return `<${el.localName}${idents}>`;
- }
-
- let res = [];
- for (let i = 0; i < ss.length; i++) {
- res.push(ss[i]);
- if (i < values.length) {
- let val = values[i];
- let typ = Object.prototype.toString.call(val);
- let s;
- try {
- if (val && val.nodeType === 1) {
- s = prettyElement(val);
- } else {
- s = prettyObject(val);
- }
- } catch (e) {
- s = typeof val;
- }
- res.push(s);
- }
- }
- return res.join("");
-};
-
-/**
- * WebDriverError is the prototypal parent of all WebDriver errors.
- * It should not be used directly, as it does not correspond to a real
- * error in the specification.
- */
-class WebDriverError extends Error {
- /**
- * @param {(string|Error)=} x
- * Optional string describing error situation or Error instance
- * to propagate.
- */
- constructor (x) {
- super(x);
- this.name = this.constructor.name;
- this.status = "webdriver error";
-
- // Error's ctor does not preserve x' stack
- if (error.isError(x)) {
- this.stack = x.stack;
- }
- }
-
- toJSON () {
- return {
- error: this.status,
- message: this.message || "",
- stacktrace: this.stack || "",
- }
- }
-
- static fromJSON (json) {
- if (typeof json.error == "undefined") {
- let s = JSON.stringify(json);
- throw new TypeError("Undeserialisable error type: " + s);
- }
- if (!STATUSES.has(json.error)) {
- throw new TypeError("Not of WebDriverError descent: " + json.error);
- }
-
- let cls = STATUSES.get(json.error);
- let err = new cls();
- if ("message" in json) {
- err.message = json.message;
- }
- if ("stacktrace" in json) {
- err.stack = json.stacktrace;
- }
- return err;
- }
-}
-
-class ElementNotAccessibleError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "element not accessible";
- }
-}
-
-/**
- * An element click could not be completed because the element receiving
- * the events is obscuring the element that was requested clicked.
- *
- * @param {Element=} obscuredEl
- * Element obscuring the element receiving the click. Providing this
- * is not required, but will produce a nicer error message.
- * @param {Map.<string, number>} coords
- * Original click location. Providing this is not required, but
- * will produce a nicer error message.
- */
-class ElementClickInterceptedError extends WebDriverError {
- constructor (obscuredEl = undefined, coords = undefined) {
- let msg = "";
- if (obscuredEl && coords) {
- const doc = obscuredEl.ownerDocument;
- const overlayingEl = doc.elementFromPoint(coords.x, coords.y);
-
- switch (obscuredEl.style.pointerEvents) {
- case "none":
- msg = error.pprint`Element ${obscuredEl} is not clickable ` +
- `at point (${coords.x},${coords.y}) ` +
- `because it does not have pointer events enabled, ` +
- error.pprint`and element ${overlayingEl} ` +
- `would receive the click instead`;
- break;
-
- default:
- msg = error.pprint`Element ${obscuredEl} is not clickable ` +
- `at point (${coords.x},${coords.y}) ` +
- error.pprint`because another element ${overlayingEl} ` +
- `obscures it`;
- break;
- }
- }
-
- super(msg);
- this.status = "element click intercepted";
- }
-}
-
-class ElementNotInteractableError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "element not interactable";
- }
-}
-
-class InsecureCertificateError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "insecure certificate";
- }
-}
-
-class InvalidArgumentError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "invalid argument";
- }
-}
-
-class InvalidElementStateError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "invalid element state";
- }
-}
-
-class InvalidSelectorError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "invalid selector";
- }
-}
-
-class InvalidSessionIDError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "invalid session id";
- }
-}
-
-/**
- * Creates a richly annotated error for an error situation that occurred
- * whilst evaluating injected scripts.
- */
-class JavaScriptError extends WebDriverError {
- /**
- * @param {(string|Error)} x
- * An Error object instance or a string describing the error
- * situation.
- * @param {string=} fnName
- * Name of the function to use in the stack trace message.
- * @param {string=} file
- * Filename of the test file on the client.
- * @param {number=} line
- * Line number of |file|.
- * @param {string=} script
- * Script being executed, in text form.
- */
- constructor (
- x,
- fnName = undefined,
- file = undefined,
- line = undefined,
- script = undefined) {
- let msg = String(x);
- let trace = "";
-
- if (fnName) {
- trace += fnName;
- if (file) {
- trace += ` @${file}`;
- if (line) {
- trace += `, line ${line}`;
- }
- }
- }
-
- if (error.isError(x)) {
- let jsStack = x.stack.split("\n");
- let match = jsStack[0].match(/:(\d+):\d+$/);
- let jsLine = match ? parseInt(match[1]) : 0;
- if (script) {
- let src = script.split("\n")[jsLine];
- trace += "\n" +
- `inline javascript, line ${jsLine}\n` +
- `src: "${src}"`;
- }
- trace += "\nStack:\n" + x.stack;
- }
-
- super(msg);
- this.status = "javascript error";
- this.stack = trace;
- }
-}
-
-class MoveTargetOutOfBoundsError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "move target out of bounds";
- }
-}
-
-class NoAlertOpenError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "no such alert";
- }
-}
-
-class NoSuchElementError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "no such element";
- }
-}
-
-class NoSuchFrameError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "no such frame";
- }
-}
-
-class NoSuchWindowError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "no such window";
- }
-}
-
-class ScriptTimeoutError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "script timeout";
- }
-}
-
-class SessionNotCreatedError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "session not created";
- }
-}
-
-class StaleElementReferenceError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "stale element reference";
- }
-}
-
-class TimeoutError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "timeout";
- }
-}
-
-class UnableToSetCookieError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "unable to set cookie";
- }
-}
-
-class UnknownCommandError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "unknown command";
- }
-}
-
-class UnknownError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "unknown error";
- }
-}
-
-class UnsupportedOperationError extends WebDriverError {
- constructor (message) {
- super(message);
- this.status = "unsupported operation";
- }
-}
-
-const STATUSES = new Map([
- ["element not accessible", ElementNotAccessibleError],
- ["element not interactable", ElementNotInteractableError],
- ["element click intercepted", ElementClickInterceptedError],
- ["insecure certificate", InsecureCertificateError],
- ["invalid argument", InvalidArgumentError],
- ["invalid element state", InvalidElementStateError],
- ["invalid selector", InvalidSelectorError],
- ["invalid session id", InvalidSessionIDError],
- ["javascript error", JavaScriptError],
- ["move target out of bounds", MoveTargetOutOfBoundsError],
- ["no alert open", NoAlertOpenError],
- ["no such element", NoSuchElementError],
- ["no such frame", NoSuchFrameError],
- ["no such window", NoSuchWindowError],
- ["script timeout", ScriptTimeoutError],
- ["session not created", SessionNotCreatedError],
- ["stale element reference", StaleElementReferenceError],
- ["timeout", TimeoutError],
- ["unable to set cookie", UnableToSetCookieError],
- ["unknown command", UnknownCommandError],
- ["unknown error", UnknownError],
- ["unsupported operation", UnsupportedOperationError],
- ["webdriver error", WebDriverError],
-]);
diff --git a/testing/marionette/evaluate.js b/testing/marionette/evaluate.js
deleted file mode 100644
index 38a80eb394..0000000000
--- a/testing/marionette/evaluate.js
+++ /dev/null
@@ -1,494 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/NetUtil.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-Cu.import("chrome://marionette/content/error.js");
-
-const logger = Log.repository.getLogger("Marionette");
-
-this.EXPORTED_SYMBOLS = ["evaluate", "sandbox", "Sandboxes"];
-
-const ARGUMENTS = "__webDriverArguments";
-const CALLBACK = "__webDriverCallback";
-const COMPLETE = "__webDriverComplete";
-const DEFAULT_TIMEOUT = 10000; // ms
-const FINISH = "finish";
-const MARIONETTE_SCRIPT_FINISHED = "marionetteScriptFinished";
-const ELEMENT_KEY = "element";
-const W3C_ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf";
-
-this.evaluate = {};
-
-/**
- * Evaluate a script in given sandbox.
- *
- * If the option {@code directInject} is not specified, the script will
- * be executed as a function with the {@code args} argument applied.
- *
- * The arguments provided by the {@code args} argument are exposed through
- * the {@code arguments} object available in the script context, and if
- * the script is executed asynchronously with the {@code async}
- * option, an additional last argument that is synonymous to the
- * {@code marionetteScriptFinished} global is appended, and can be
- * accessed through {@code arguments[arguments.length - 1]}.
- *
- * The {@code timeout} option specifies the duration for how long the
- * script should be allowed to run before it is interrupted and aborted.
- * An interrupted script will cause a ScriptTimeoutError to occur.
- *
- * The {@code async} option indicates that the script will not return
- * until the {@code marionetteScriptFinished} global callback is invoked,
- * which is analogous to the last argument of the {@code arguments}
- * object.
- *
- * The option {@code directInject} causes the script to be evaluated
- * without being wrapped in a function and the provided arguments will
- * be disregarded. This will cause such things as root scope return
- * statements to throw errors because they are not used inside a function.
- *
- * The {@code filename} option is used in error messages to provide
- * information on the origin script file in the local end.
- *
- * The {@code line} option is used in error messages, along with
- * {@code filename}, to provide the line number in the origin script
- * file on the local end.
- *
- * @param {nsISandbox) sb
- * The sandbox the script will be evaluted in.
- * @param {string} script
- * The script to evaluate.
- * @param {Array.<?>=} args
- * A sequence of arguments to call the script with.
- * @param {Object.<string, ?>=} opts
- * Dictionary of options:
- *
- * async (boolean)
- * Indicates if the script should return immediately or wait
- * for the callback be invoked before returning.
- * debug (boolean)
- * Attaches an {@code onerror} event listener.
- * directInject (boolean)
- * Evaluates the script without wrapping it in a function.
- * filename (string)
- * File location of the program in the client.
- * line (number)
- * Line number of the program in the client.
- * sandboxName (string)
- * Name of the sandbox. Elevated system privileges, equivalent
- * to chrome space, will be given if it is "system".
- * timeout (boolean)
- * Duration in milliseconds before interrupting the script.
- *
- * @return {Promise}
- * A promise that when resolved will give you the return value from
- * the script. Note that the return value requires serialisation before
- * it can be sent to the client.
- *
- * @throws JavaScriptError
- * If an Error was thrown whilst evaluating the script.
- * @throws ScriptTimeoutError
- * If the script was interrupted due to script timeout.
- */
-evaluate.sandbox = function (sb, script, args = [], opts = {}) {
- let scriptTimeoutID, timeoutHandler, unloadHandler;
-
- let promise = new Promise((resolve, reject) => {
- let src = "";
- sb[COMPLETE] = resolve;
- timeoutHandler = () => reject(new ScriptTimeoutError("Timed out"));
- unloadHandler = () => reject(
- new JavaScriptError("Document was unloaded during execution"));
-
- // wrap in function
- if (!opts.directInject) {
- if (opts.async) {
- sb[CALLBACK] = sb[COMPLETE];
- }
- sb[ARGUMENTS] = sandbox.cloneInto(args, sb);
-
- // callback function made private
- // so that introspection is possible
- // on the arguments object
- if (opts.async) {
- sb[CALLBACK] = sb[COMPLETE];
- src += `${ARGUMENTS}.push(rv => ${CALLBACK}(rv));`;
- }
-
- src += `(function() { ${script} }).apply(null, ${ARGUMENTS})`;
-
- // marionetteScriptFinished is not WebDriver conformant,
- // hence it is only exposed to immutable sandboxes
- if (opts.sandboxName) {
- sb[MARIONETTE_SCRIPT_FINISHED] = sb[CALLBACK];
- }
- }
-
- // onerror is not hooked on by default because of the inability to
- // differentiate content errors from chrome errors.
- //
- // see bug 1128760 for more details
- if (opts.debug) {
- sb.window.onerror = (msg, url, line) => {
- let err = new JavaScriptError(`${msg} at ${url}:${line}`);
- reject(err);
- };
- }
-
- // timeout and unload handlers
- scriptTimeoutID = setTimeout(timeoutHandler, opts.timeout || DEFAULT_TIMEOUT);
- sb.window.onunload = sandbox.cloneInto(unloadHandler, sb);
-
- let res;
- try {
- res = Cu.evalInSandbox(src, sb, "1.8", opts.filename || "dummy file", 0);
- } catch (e) {
- let err = new JavaScriptError(
- e,
- "execute_script",
- opts.filename,
- opts.line,
- script);
- reject(err);
- }
-
- if (!opts.async) {
- resolve(res);
- }
- });
-
- return promise.then(res => {
- clearTimeout(scriptTimeoutID);
- sb.window.removeEventListener("unload", unloadHandler);
- return res;
- });
-};
-
-this.sandbox = {};
-
-/**
- * Provides a safe way to take an object defined in a privileged scope and
- * create a structured clone of it in a less-privileged scope. It returns
- * a reference to the clone.
- *
- * Unlike for |Components.utils.cloneInto|, |obj| may contain functions
- * and DOM elemnets.
- */
-sandbox.cloneInto = function (obj, sb) {
- return Cu.cloneInto(obj, sb, {cloneFunctions: true, wrapReflectors: true});
-};
-
-/**
- * Augment given sandbox by an adapter that has an {@code exports}
- * map property, or a normal map, of function names and function
- * references.
- *
- * @param {Sandbox} sb
- * The sandbox to augment.
- * @param {Object} adapter
- * Object that holds an {@code exports} property, or a map, of
- * function names and function references.
- *
- * @return {Sandbox}
- * The augmented sandbox.
- */
-sandbox.augment = function (sb, adapter) {
- function* entries(obj) {
- for (let key of Object.keys(obj)) {
- yield [key, obj[key]];
- }
- }
-
- let funcs = adapter.exports || entries(adapter);
- for (let [name, func] of funcs) {
- sb[name] = func;
- }
-
- return sb;
-};
-
-/**
- * Creates a sandbox.
- *
- * @param {Window} window
- * The DOM Window object.
- * @param {nsIPrincipal=} principal
- * An optional, custom principal to prefer over the Window. Useful if
- * you need elevated security permissions.
- *
- * @return {Sandbox}
- * The created sandbox.
- */
-sandbox.create = function (window, principal = null, opts = {}) {
- let p = principal || window;
- opts = Object.assign({
- sameZoneAs: window,
- sandboxPrototype: window,
- wantComponents: true,
- wantXrays: true,
- }, opts);
- return new Cu.Sandbox(p, opts);
-};
-
-/**
- * Creates a mutable sandbox, where changes to the global scope
- * will have lasting side-effects.
- *
- * @param {Window} window
- * The DOM Window object.
- *
- * @return {Sandbox}
- * The created sandbox.
- */
-sandbox.createMutable = function (window) {
- let opts = {
- wantComponents: false,
- wantXrays: false,
- };
- return sandbox.create(window, null, opts);
-};
-
-sandbox.createSystemPrincipal = function (window) {
- let principal = Cc["@mozilla.org/systemprincipal;1"]
- .createInstance(Ci.nsIPrincipal);
- return sandbox.create(window, principal);
-};
-
-sandbox.createSimpleTest = function (window, harness) {
- let sb = sandbox.create(window);
- sb = sandbox.augment(sb, harness);
- sb[FINISH] = () => sb[COMPLETE](harness.generate_results());
- return sb;
-};
-
-/**
- * Sandbox storage. When the user requests a sandbox by a specific name,
- * if one exists in the storage this will be used as long as its window
- * reference is still valid.
- */
-this.Sandboxes = class {
- /**
- * @param {function(): Window} windowFn
- * A function that returns the references to the current Window
- * object.
- */
- constructor(windowFn) {
- this.windowFn_ = windowFn;
- this.boxes_ = new Map();
- }
-
- get window_() {
- return this.windowFn_();
- }
-
- /**
- * Factory function for getting a sandbox by name, or failing that,
- * creating a new one.
- *
- * If the sandbox' window does not match the provided window, a new one
- * will be created.
- *
- * @param {string} name
- * The name of the sandbox to get or create.
- * @param {boolean} fresh
- * Remove old sandbox by name first, if it exists.
- *
- * @return {Sandbox}
- * A used or fresh sandbox.
- */
- get(name = "default", fresh = false) {
- let sb = this.boxes_.get(name);
- if (sb) {
- if (fresh || sb.window != this.window_) {
- this.boxes_.delete(name);
- return this.get(name, false);
- }
- } else {
- if (name == "system") {
- sb = sandbox.createSystemPrincipal(this.window_);
- } else {
- sb = sandbox.create(this.window_);
- }
- this.boxes_.set(name, sb);
- }
- return sb;
- }
-
- /**
- * Clears cache of sandboxes.
- */
- clear() {
- this.boxes_.clear();
- }
-};
-
-/**
- * Stores scripts imported from the local end through the
- * {@code GeckoDriver#importScript} command.
- *
- * Imported scripts are prepended to the script that is evaluated
- * on each call to {@code GeckoDriver#executeScript},
- * {@code GeckoDriver#executeAsyncScript}, and
- * {@code GeckoDriver#executeJSScript}.
- *
- * Usage:
- *
- * let importedScripts = new evaluate.ScriptStorage();
- * importedScripts.add(firstScript);
- * importedScripts.add(secondScript);
- *
- * let scriptToEval = importedScripts.concat(script);
- * // firstScript and secondScript are prepended to script
- *
- */
-evaluate.ScriptStorage = class extends Set {
-
- /**
- * Produce a string of all stored scripts.
- *
- * The stored scripts are concatenated into a string, with optional
- * additional scripts then appended.
- *
- * @param {...string} addional
- * Optional scripts to include.
- *
- * @return {string}
- * Concatenated string consisting of stored scripts and additional
- * scripts, in that order.
- */
- concat(...additional) {
- let rv = "";
- for (let s of this) {
- rv = s + rv;
- }
- for (let s of additional) {
- rv = rv + s;
- }
- return rv;
- }
-
- toJson() {
- return Array.from(this);
- }
-
-};
-
-/**
- * Service that enables the script storage service to be queried from
- * content space.
- *
- * The storage can back multiple |ScriptStorage|, each typically belonging
- * to a |Context|. Since imported scripts' scope are global and not
- * scoped to the current browsing context, all imported scripts are stored
- * in chrome space and fetched by content space as needed.
- *
- * Usage in chrome space:
- *
- * let service = new evaluate.ScriptStorageService(
- * [Context.CHROME, Context.CONTENT]);
- * let storage = service.for(Context.CHROME);
- * let scriptToEval = storage.concat(script);
- *
- */
-evaluate.ScriptStorageService = class extends Map {
-
- /**
- * Create the service.
- *
- * An optional array of names for script storages to initially create
- * can be provided.
- *
- * @param {Array.<string>=} initialStorages
- * List of names of the script storages to create initially.
- */
- constructor(initialStorages = []) {
- super(initialStorages.map(name => [name, new evaluate.ScriptStorage()]));
- }
-
- /**
- * Retrieve the scripts associated with the given context.
- *
- * @param {Context} context
- * Context to retrieve the scripts from.
- *
- * @return {ScriptStorage}
- * Scrips associated with given |context|.
- */
- for(context) {
- return this.get(context);
- }
-
- processMessage(msg) {
- switch (msg.name) {
- case "Marionette:getImportedScripts":
- let storage = this.for.apply(this, msg.json);
- return storage.toJson();
-
- default:
- throw new TypeError("Unknown message: " + msg.name);
- }
- }
-
- // TODO(ato): The idea of services in chrome space
- // can be generalised at some later time (see cookies.js:38).
- receiveMessage(msg) {
- try {
- return this.processMessage(msg);
- } catch (e) {
- logger.error(e);
- }
- }
-
-};
-
-evaluate.ScriptStorageService.prototype.QueryInterface =
- XPCOMUtils.generateQI([
- Ci.nsIMessageListener,
- Ci.nsISupportsWeakReference,
- ]);
-
-/**
- * Bridges the script storage in chrome space, to make it possible to
- * retrieve a {@code ScriptStorage} associated with a given
- * {@code Context} from content space.
- *
- * Usage in content space:
- *
- * let client = new evaluate.ScriptStorageServiceClient(chromeProxy);
- * let storage = client.for(Context.CONTENT);
- * let scriptToEval = storage.concat(script);
- *
- */
-evaluate.ScriptStorageServiceClient = class {
-
- /**
- * @param {proxy.SyncChromeSender} chromeProxy
- * Proxy for communicating with chrome space.
- */
- constructor(chromeProxy) {
- this.chrome = chromeProxy;
- }
-
- /**
- * Retrieve scripts associated with the given context.
- *
- * @param {Context} context
- * Context to retrieve scripts from.
- *
- * @return {ScriptStorage}
- * Scripts associated with given |context|.
- */
- for(context) {
- let scripts = this.chrome.getImportedScripts(context)[0];
- return new evaluate.ScriptStorage(scripts);
- }
-
-};
diff --git a/testing/marionette/event.js b/testing/marionette/event.js
deleted file mode 100644
index c60ca306b1..0000000000
--- a/testing/marionette/event.js
+++ /dev/null
@@ -1,1365 +0,0 @@
-/* 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/. */
-
-// Provides functionality for creating and sending DOM events.
-
-"use strict";
-
-const {interfaces: Ci, utils: Cu, classes: Cc} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-const logger = Log.repository.getLogger("Marionette");
-
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["event"];
-
-// must be synchronised with nsIDOMWindowUtils
-const COMPOSITION_ATTR_RAWINPUT = 0x02;
-const COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03;
-const COMPOSITION_ATTR_CONVERTEDTEXT = 0x04;
-const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
-
-// TODO(ato): Document!
-let seenEvent = false;
-
-function getDOMWindowUtils(win) {
- if (!win) {
- win = window;
- }
-
- // this assumes we are operating in chrome space
- return win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
-}
-
-this.event = {};
-
-event.MouseEvents = {
- click: 0,
- dblclick: 1,
- mousedown: 2,
- mouseup: 3,
- mouseover: 4,
- mouseout: 5,
-};
-
-event.Modifiers = {
- shiftKey: 0,
- ctrlKey: 1,
- altKey: 2,
- metaKey: 3,
-};
-
-/**
- * Sends a mouse event to given target.
- *
- * @param {nsIDOMMouseEvent} mouseEvent
- * Event to send.
- * @param {(DOMElement|string)} target
- * Target of event. Can either be an element or the ID of an element.
- * @param {Window=} window
- * Window object. Defaults to the current window.
- *
- * @throws {TypeError}
- * If the event is unsupported.
- */
-event.sendMouseEvent = function (mouseEvent, target, window = undefined) {
- if (!event.MouseEvents.hasOwnProperty(mouseEvent.type)) {
- throw new TypeError("Unsupported event type: " + mouseEvent.type);
- }
-
- if (!target.nodeType && typeof target != "string") {
- throw new TypeError("Target can only be a DOM element or a string: " + target);
- }
-
- if (!target.nodeType) {
- target = window.document.getElementById(target);
- } else {
- window = window || target.ownerDocument.defaultView;
- }
-
- let ev = window.document.createEvent("MouseEvent");
-
- let type = mouseEvent.type;
- let view = window;
-
- let detail = mouseEvent.detail;
- if (!detail) {
- if (mouseEvent.type in ["click", "mousedown", "mouseup"]) {
- detail = 1;
- } else if (mouseEvent.type == "dblclick") {
- detail = 2;
- } else {
- detail = 0;
- }
- }
-
- let screenX = mouseEvent.screenX || 0;
- let screenY = mouseEvent.screenY || 0;
- let clientX = mouseEvent.clientX || 0;
- let clientY = mouseEvent.clientY || 0;
- let ctrlKey = mouseEvent.ctrlKey || false;
- let altKey = mouseEvent.altKey || false;
- let shiftKey = mouseEvent.shiftKey || false;
- let metaKey = mouseEvent.metaKey || false;
- let button = mouseEvent.button || 0;
- let relatedTarget = mouseEvent.relatedTarget || null;
-
- ev.initMouseEvent(
- mouseEvent.type,
- /* canBubble */ true,
- /* cancelable */ true,
- view,
- detail,
- screenX,
- screenY,
- clientX,
- clientY,
- ctrlKey,
- altKey,
- shiftKey,
- metaKey,
- button,
- relatedTarget);
-};
-
-/**
- * Send character to the currently focused element.
- *
- * This function handles casing of characters (sends the right charcode,
- * and sends a shift key for uppercase chars). No other modifiers are
- * handled at this point.
- *
- * For now this method only works for English letters (lower and upper
- * case) and the digits 0-9.
- */
-event.sendChar = function (char, window = undefined) {
- // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9
- let hasShift = (char == char.toUpperCase());
- event.synthesizeKey(char, {shiftKey: hasShift}, window);
-};
-
-/**
- * Send string to the focused element.
- *
- * For now this method only works for English letters (lower and upper
- * case) and the digits 0-9.
- */
-event.sendString = function (string, window = undefined) {
- for (let i = 0; i < string.length; ++i) {
- event.sendChar(string.charAt(i), window);
- }
-};
-
-/**
- * Send the non-character key to the focused element.
- *
- * The name of the key should be the part that comes after "DOM_VK_"
- * in the nsIDOMKeyEvent constant name for this key. No modifiers are
- * handled at this point.
- */
-event.sendKey = function (key, window = undefined) {
- let keyName = "VK_" + key.toUpperCase();
- event.synthesizeKey(keyName, {shiftKey: false}, window);
-};
-
-// TODO(ato): Unexpose this when action.Chain#emitMouseEvent
-// no longer emits its own events
-event.parseModifiers_ = function (modifiers) {
- let mval = 0;
- if (modifiers.shiftKey) {
- mval |= Ci.nsIDOMNSEvent.SHIFT_MASK;
- }
- if (modifiers.ctrlKey) {
- mval |= Ci.nsIDOMNSEvent.CONTROL_MASK;
- }
- if (modifiers.altKey) {
- mval |= Ci.nsIDOMNSEvent.ALT_MASK;
- }
- if (modifiers.metaKey) {
- mval |= Ci.nsIDOMNSEvent.META_MASK;
- }
- if (modifiers.accelKey) {
- if (navigator.platform.indexOf("Mac") >= 0) {
- mval |= Ci.nsIDOMNSEvent.META_MASK;
- } else {
- mval |= Ci.nsIDOMNSEvent.CONTROL_MASK;
- }
- }
- return mval;
-};
-
-/**
- * Synthesise a mouse event on a target.
- *
- * The actual client point is determined by taking the aTarget's client
- * box and offseting it by offsetX and offsetY. This allows mouse clicks
- * to be simulated by calling this method.
- *
- * If the type is specified, an mouse event of that type is
- * fired. Otherwise, a mousedown followed by a mouse up is performed.
- *
- * @param {Element} element
- * Element to click.
- * @param {number} offsetX
- * Horizontal offset to click from the target's bounding box.
- * @param {number} offsetY
- * Vertical offset to click from the target's bounding box.
- * @param {Object.<string, ?>} opts
- * Object which may contain the properties "shiftKey", "ctrlKey",
- * "altKey", "metaKey", "accessKey", "clickCount", "button", and
- * "type".
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeMouse = function (
- element, offsetX, offsetY, opts, window = undefined) {
- let rect = element.getBoundingClientRect();
- event.synthesizeMouseAtPoint(
- rect.left + offsetX, rect.top + offsetY, opts, window);
-};
-
-/*
- * Synthesize a mouse event at a particular point in a window.
- *
- * If the type of the event is specified, a mouse event of that type is
- * fired. Otherwise, a mousedown followed by a mouse up is performed.
- *
- * @param {number} left
- * CSS pixels from the left document margin.
- * @param {number} top
- * CSS pixels from the top document margin.
- * @param {Object.<string, ?>} opts
- * Object which may contain the properties "shiftKey", "ctrlKey",
- * "altKey", "metaKey", "accessKey", "clickCount", "button", and
- * "type".
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeMouseAtPoint = function (
- left, top, opts, window = undefined) {
-
- let domutils = getDOMWindowUtils(window);
-
- let button = opts.button || 0;
- let clickCount = opts.clickCount || 1;
- let modifiers = event.parseModifiers_(opts);
- let pressure = ("pressure" in opts) ? opts.pressure : 0;
- let inputSource = ("inputSource" in opts) ? opts.inputSource :
- Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE;
- let isDOMEventSynthesized =
- ("isSynthesized" in opts) ? opts.isSynthesized : true;
- let isWidgetEventSynthesized =
- ("isWidgetEventSynthesized" in opts) ? opts.isWidgetEventSynthesized : false;
- let buttons = ("buttons" in opts) ? opts.buttons : domutils.MOUSE_BUTTONS_NOT_SPECIFIED;
-
- if (("type" in opts) && opts.type) {
- domutils.sendMouseEvent(
- opts.type, left, top, button, clickCount, modifiers, false, pressure, inputSource,
- isDOMEventSynthesized, isWidgetEventSynthesized, buttons);
- } else {
- domutils.sendMouseEvent(
- "mousedown", left, top, button, clickCount, modifiers, false, pressure, inputSource,
- isDOMEventSynthesized, isWidgetEventSynthesized, buttons);
- domutils.sendMouseEvent(
- "mouseup", left, top, button, clickCount, modifiers, false, pressure, inputSource,
- isDOMEventSynthesized, isWidgetEventSynthesized, buttons);
- }
-};
-
-/**
- * Call event.synthesizeMouse with coordinates at the centre of the
- * target.
- */
-event.synthesizeMouseAtCenter = function (element, event, window) {
- let rect = element.getBoundingClientRect();
- event.synthesizeMouse(
- element,
- rect.width / 2,
- rect.height / 2,
- event,
- window);
-};
-
-/**
- * Synthesise a mouse scroll event on a target.
- *
- * The actual client point is determined by taking the target's client
- * box and offseting it by |offsetX| and |offsetY|.
- *
- * If the |type| property is specified for the |event| argument, a mouse
- * scroll event of that type is fired. Otherwise, DOMMouseScroll is used.
- *
- * If the |axis| is specified, it must be one of "horizontal" or
- * "vertical". If not specified, "vertical" is used.
- *
- * |delta| is the amount to scroll by (can be positive or negative).
- * It must be specified.
- *
- * |hasPixels| specifies whether kHasPixels should be set in the
- * |scrollFlags|.
- *
- * |isMomentum| specifies whether kIsMomentum should be set in the
- * |scrollFlags|.
- *
- * @param {Element} target
- * @param {number} offsetY
- * @param {number} offsetY
- * @param {Object.<string, ?>} event
- * Object which may contain the properties shiftKey, ctrlKey, altKey,
- * metaKey, accessKey, button, type, axis, delta, and hasPixels.
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeMouseScroll = function (
- target, offsetX, offsetY, ev, window = undefined) {
-
- let domutils = getDOMWindowUtils(window);
-
- // see nsMouseScrollFlags in nsGUIEvent.h
- const kIsVertical = 0x02;
- const kIsHorizontal = 0x04;
- const kHasPixels = 0x08;
- const kIsMomentum = 0x40;
-
- let button = ev.button || 0;
- let modifiers = event.parseModifiers_(ev);
-
- let rect = target.getBoundingClientRect();
- let left = rect.left;
- let top = rect.top;
-
- let type = (("type" in ev) && ev.type) || "DOMMouseScroll";
- let axis = ev.axis || "vertical";
- let scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
- if (ev.hasPixels) {
- scrollFlags |= kHasPixels;
- }
- if (ev.isMomentum) {
- scrollFlags |= kIsMomentum;
- }
-
- domutils.sendMouseScrollEvent(
- type,
- left + offsetX,
- top + offsetY,
- button,
- scrollFlags,
- ev.delta,
- modifiers);
-};
-
-function computeKeyCodeFromChar_(char) {
- if (char.length != 1) {
- return 0;
- }
-
- if (char >= "a" && char <= "z") {
- return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "a".charCodeAt(0);
- }
- if (char >= "A" && char <= "Z") {
- return Ci.nsIDOMKeyEvent.DOM_VK_A + char.charCodeAt(0) - "A".charCodeAt(0);
- }
- if (char >= "0" && char <= "9") {
- return Ci.nsIDOMKeyEvent.DOM_VK_0 + char.charCodeAt(0) - "0".charCodeAt(0);
- }
-
- // returns US keyboard layout's keycode
- switch (char) {
- case "~":
- case "`":
- return Ci.nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
-
- case "!":
- return Ci.nsIDOMKeyEvent.DOM_VK_1;
-
- case "@":
- return Ci.nsIDOMKeyEvent.DOM_VK_2;
-
- case "#":
- return Ci.nsIDOMKeyEvent.DOM_VK_3;
-
- case "$":
- return Ci.nsIDOMKeyEvent.DOM_VK_4;
-
- case "%":
- return Ci.nsIDOMKeyEvent.DOM_VK_5;
-
- case "^":
- return Ci.nsIDOMKeyEvent.DOM_VK_6;
-
- case "&":
- return Ci.nsIDOMKeyEvent.DOM_VK_7;
-
- case "*":
- return Ci.nsIDOMKeyEvent.DOM_VK_8;
-
- case "(":
- return Ci.nsIDOMKeyEvent.DOM_VK_9;
-
- case ")":
- return Ci.nsIDOMKeyEvent.DOM_VK_0;
-
- case "-":
- case "_":
- return Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT;
-
- case "+":
- case "=":
- return Ci.nsIDOMKeyEvent.DOM_VK_EQUALS;
-
- case "{":
- case "[":
- return Ci.nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
-
- case "}":
- case "]":
- return Ci.nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
-
- case "|":
- case "\\":
- return Ci.nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
-
- case ":":
- case ";":
- return Ci.nsIDOMKeyEvent.DOM_VK_SEMICOLON;
-
- case "'":
- case "\"":
- return Ci.nsIDOMKeyEvent.DOM_VK_QUOTE;
-
- case "<":
- case ",":
- return Ci.nsIDOMKeyEvent.DOM_VK_COMMA;
-
- case ">":
- case ".":
- return Ci.nsIDOMKeyEvent.DOM_VK_PERIOD;
-
- case "?":
- case "/":
- return Ci.nsIDOMKeyEvent.DOM_VK_SLASH;
-
- case "\n":
- return Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
-
- default:
- return 0;
- }
-}
-
-/**
- * Returns true if the given key should cause keypress event when widget
- * handles the native key event. Otherwise, false.
- *
- * The key code should be one of consts of nsIDOMKeyEvent.DOM_VK_*,
- * or a key name begins with "VK_", or a character.
- */
-event.isKeypressFiredKey = function (key) {
- if (typeof key == "string") {
- if (key.indexOf("VK_") === 0) {
- key = Ci.nsIDOMKeyEvent["DOM_" + key];
- if (!key) {
- throw new TypeError("Unknown key: " + key);
- }
-
- // if key generates a character, it must cause a keypress event
- } else {
- return true;
- }
- }
-
- switch (key) {
- case Ci.nsIDOMKeyEvent.DOM_VK_SHIFT:
- case Ci.nsIDOMKeyEvent.DOM_VK_CONTROL:
- case Ci.nsIDOMKeyEvent.DOM_VK_ALT:
- case Ci.nsIDOMKeyEvent.DOM_VK_CAPS_LOCK:
- case Ci.nsIDOMKeyEvent.DOM_VK_NUM_LOCK:
- case Ci.nsIDOMKeyEvent.DOM_VK_SCROLL_LOCK:
- case Ci.nsIDOMKeyEvent.DOM_VK_META:
- return false;
-
- default:
- return true;
- }
-};
-
-/**
- * Synthesise a key event.
- *
- * It is targeted at whatever would be targeted by an actual keypress
- * by the user, typically the focused element.
- *
- * @param {string} key
- * Key to synthesise. Should either be a character or a key code
- * starting with "VK_" such as VK_RETURN, or a normalized key value.
- * @param {Object.<string, ?>} event
- * Object which may contain the properties shiftKey, ctrlKey, altKey,
- * metaKey, accessKey, type. If the type is specified (keydown or keyup),
- * a key event of that type is fired. Otherwise, a keydown, a keypress,
- * and then a keyup event are fired in sequence.
- * @param {Window=} window
- * Window object. Defaults to the current window.
- *
- * @throws {TypeError}
- * If unknown key.
- */
-event.synthesizeKey = function (key, event, win = undefined)
-{
- var TIP = getTIP_(win);
- if (!TIP) {
- return;
- }
- var KeyboardEvent = getKeyboardEvent_(win);
- var modifiers = emulateToActivateModifiers_(TIP, event, win);
- var keyEventDict = createKeyboardEventDictionary_(key, event, win);
- var keyEvent = new KeyboardEvent("", keyEventDict.dictionary);
- var dispatchKeydown =
- !("type" in event) || event.type === "keydown" || !event.type;
- var dispatchKeyup =
- !("type" in event) || event.type === "keyup" || !event.type;
-
- try {
- if (dispatchKeydown) {
- TIP.keydown(keyEvent, keyEventDict.flags);
- if ("repeat" in event && event.repeat > 1) {
- keyEventDict.dictionary.repeat = true;
- var repeatedKeyEvent = new KeyboardEvent("", keyEventDict.dictionary);
- for (var i = 1; i < event.repeat; i++) {
- TIP.keydown(repeatedKeyEvent, keyEventDict.flags);
- }
- }
- }
- if (dispatchKeyup) {
- TIP.keyup(keyEvent, keyEventDict.flags);
- }
- } finally {
- emulateToInactivateModifiers_(TIP, modifiers, win);
- }
-};
-
-var TIPMap = new WeakMap();
-
-function getTIP_(win, callback)
-{
- if (!win) {
- win = window;
- }
- var tip;
- if (TIPMap.has(win)) {
- tip = TIPMap.get(win);
- } else {
- tip =
- Cc["@mozilla.org/text-input-processor;1"].
- createInstance(Ci.nsITextInputProcessor);
- TIPMap.set(win, tip);
- }
- if (!tip.beginInputTransactionForTests(win, callback)) {
- tip = null;
- TIPMap.delete(win);
- }
- return tip;
-}
-
-function getKeyboardEvent_(win = window)
-{
- if (typeof KeyboardEvent != "undefined") {
- try {
- // See if the object can be instantiated; sometimes this yields
- // 'TypeError: can't access dead object' or 'KeyboardEvent is not a constructor'.
- new KeyboardEvent("", {});
- return KeyboardEvent;
- } catch (ex) {}
- }
- if (typeof content != "undefined" && ("KeyboardEvent" in content)) {
- return content.KeyboardEvent;
- }
- return win.KeyboardEvent;
-}
-
-function createKeyboardEventDictionary_(key, keyEvent, win = window) {
- var result = { dictionary: null, flags: 0 };
- var keyCodeIsDefined = "keyCode" in keyEvent;
- var keyCode =
- (keyCodeIsDefined && keyEvent.keyCode >= 0 && keyEvent.keyCode <= 255) ?
- keyEvent.keyCode : 0;
- var keyName = "Unidentified";
- if (key.indexOf("KEY_") == 0) {
- keyName = key.substr("KEY_".length);
- result.flags |= Ci.nsITextInputProcessor.KEY_NON_PRINTABLE_KEY;
- } else if (key.indexOf("VK_") == 0) {
- keyCode = Ci.nsIDOMKeyEvent["DOM_" + key];
- if (!keyCode) {
- throw "Unknown key: " + key;
- }
- keyName = guessKeyNameFromKeyCode_(keyCode, win);
- result.flags |= Ci.nsITextInputProcessor.KEY_NON_PRINTABLE_KEY;
- } else if (key != "") {
- keyName = key;
- if (!keyCodeIsDefined) {
- keyCode = computeKeyCodeFromChar_(key.charAt(0));
- }
- if (!keyCode) {
- result.flags |= Ci.nsITextInputProcessor.KEY_KEEP_KEYCODE_ZERO;
- }
- // keyName was already determined in keyEvent so no fall-back needed
- if (!("key" in keyEvent && keyName == keyEvent.key)) {
- result.flags |= Ci.nsITextInputProcessor.KEY_FORCE_PRINTABLE_KEY;
- }
- }
- var locationIsDefined = "location" in keyEvent;
- if (locationIsDefined && keyEvent.location === 0) {
- result.flags |= Ci.nsITextInputProcessor.KEY_KEEP_KEY_LOCATION_STANDARD;
- }
- result.dictionary = {
- key: keyName,
- code: "code" in keyEvent ? keyEvent.code : "",
- location: locationIsDefined ? keyEvent.location : 0,
- repeat: "repeat" in keyEvent ? keyEvent.repeat === true : false,
- keyCode: keyCode,
- };
- return result;
-}
-
-function emulateToActivateModifiers_(TIP, keyEvent, win = window)
-{
- if (!keyEvent) {
- return null;
- }
- var KeyboardEvent = getKeyboardEvent_(win);
- var navigator = getNavigator_(win);
-
- var modifiers = {
- normal: [
- { key: "Alt", attr: "altKey" },
- { key: "AltGraph", attr: "altGraphKey" },
- { key: "Control", attr: "ctrlKey" },
- { key: "Fn", attr: "fnKey" },
- { key: "Meta", attr: "metaKey" },
- { key: "OS", attr: "osKey" },
- { key: "Shift", attr: "shiftKey" },
- { key: "Symbol", attr: "symbolKey" },
- { key: isMac_(win) ? "Meta" : "Control",
- attr: "accelKey" },
- ],
- lockable: [
- { key: "CapsLock", attr: "capsLockKey" },
- { key: "FnLock", attr: "fnLockKey" },
- { key: "NumLock", attr: "numLockKey" },
- { key: "ScrollLock", attr: "scrollLockKey" },
- { key: "SymbolLock", attr: "symbolLockKey" },
- ]
- }
-
- for (var i = 0; i < modifiers.normal.length; i++) {
- if (!keyEvent[modifiers.normal[i].attr]) {
- continue;
- }
- if (TIP.getModifierState(modifiers.normal[i].key)) {
- continue; // already activated.
- }
- var event = new KeyboardEvent("", { key: modifiers.normal[i].key });
- TIP.keydown(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- modifiers.normal[i].activated = true;
- }
- for (var i = 0; i < modifiers.lockable.length; i++) {
- if (!keyEvent[modifiers.lockable[i].attr]) {
- continue;
- }
- if (TIP.getModifierState(modifiers.lockable[i].key)) {
- continue; // already activated.
- }
- var event = new KeyboardEvent("", { key: modifiers.lockable[i].key });
- TIP.keydown(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- TIP.keyup(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- modifiers.lockable[i].activated = true;
- }
- return modifiers;
-}
-
-function emulateToInactivateModifiers_(TIP, modifiers, win = window)
-{
- if (!modifiers) {
- return;
- }
- var KeyboardEvent = getKeyboardEvent_(win);
- for (var i = 0; i < modifiers.normal.length; i++) {
- if (!modifiers.normal[i].activated) {
- continue;
- }
- var event = new KeyboardEvent("", { key: modifiers.normal[i].key });
- TIP.keyup(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- }
- for (var i = 0; i < modifiers.lockable.length; i++) {
- if (!modifiers.lockable[i].activated) {
- continue;
- }
- if (!TIP.getModifierState(modifiers.lockable[i].key)) {
- continue; // who already inactivated this?
- }
- var event = new KeyboardEvent("", { key: modifiers.lockable[i].key });
- TIP.keydown(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- TIP.keyup(event,
- TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
- }
-}
-
-function getNavigator_(win = window)
-{
- if (typeof navigator != "undefined") {
- return navigator;
- }
- return win.navigator;
-}
-
-function isMac_(win = window) {
- if (win) {
- try {
- return win.navigator.platform.indexOf("Mac") > -1;
- } catch (ex) {}
- }
- return navigator.platform.indexOf("Mac") > -1;
-}
-
-function guessKeyNameFromKeyCode_(aKeyCode, win = window)
-{
- var KeyboardEvent = getKeyboardEvent_(win);
- switch (aKeyCode) {
- case KeyboardEvent.DOM_VK_CANCEL:
- return "Cancel";
- case KeyboardEvent.DOM_VK_HELP:
- return "Help";
- case KeyboardEvent.DOM_VK_BACK_SPACE:
- return "Backspace";
- case KeyboardEvent.DOM_VK_TAB:
- return "Tab";
- case KeyboardEvent.DOM_VK_CLEAR:
- return "Clear";
- case KeyboardEvent.DOM_VK_RETURN:
- return "Enter";
- case KeyboardEvent.DOM_VK_SHIFT:
- return "Shift";
- case KeyboardEvent.DOM_VK_CONTROL:
- return "Control";
- case KeyboardEvent.DOM_VK_ALT:
- return "Alt";
- case KeyboardEvent.DOM_VK_PAUSE:
- return "Pause";
- case KeyboardEvent.DOM_VK_EISU:
- return "Eisu";
- case KeyboardEvent.DOM_VK_ESCAPE:
- return "Escape";
- case KeyboardEvent.DOM_VK_CONVERT:
- return "Convert";
- case KeyboardEvent.DOM_VK_NONCONVERT:
- return "NonConvert";
- case KeyboardEvent.DOM_VK_ACCEPT:
- return "Accept";
- case KeyboardEvent.DOM_VK_MODECHANGE:
- return "ModeChange";
- case KeyboardEvent.DOM_VK_PAGE_UP:
- return "PageUp";
- case KeyboardEvent.DOM_VK_PAGE_DOWN:
- return "PageDown";
- case KeyboardEvent.DOM_VK_END:
- return "End";
- case KeyboardEvent.DOM_VK_HOME:
- return "Home";
- case KeyboardEvent.DOM_VK_LEFT:
- return "ArrowLeft";
- case KeyboardEvent.DOM_VK_UP:
- return "ArrowUp";
- case KeyboardEvent.DOM_VK_RIGHT:
- return "ArrowRight";
- case KeyboardEvent.DOM_VK_DOWN:
- return "ArrowDown";
- case KeyboardEvent.DOM_VK_SELECT:
- return "Select";
- case KeyboardEvent.DOM_VK_PRINT:
- return "Print";
- case KeyboardEvent.DOM_VK_EXECUTE:
- return "Execute";
- case KeyboardEvent.DOM_VK_PRINTSCREEN:
- return "PrintScreen";
- case KeyboardEvent.DOM_VK_INSERT:
- return "Insert";
- case KeyboardEvent.DOM_VK_DELETE:
- return "Delete";
- case KeyboardEvent.DOM_VK_WIN:
- return "OS";
- case KeyboardEvent.DOM_VK_CONTEXT_MENU:
- return "ContextMenu";
- case KeyboardEvent.DOM_VK_SLEEP:
- return "Standby";
- case KeyboardEvent.DOM_VK_F1:
- return "F1";
- case KeyboardEvent.DOM_VK_F2:
- return "F2";
- case KeyboardEvent.DOM_VK_F3:
- return "F3";
- case KeyboardEvent.DOM_VK_F4:
- return "F4";
- case KeyboardEvent.DOM_VK_F5:
- return "F5";
- case KeyboardEvent.DOM_VK_F6:
- return "F6";
- case KeyboardEvent.DOM_VK_F7:
- return "F7";
- case KeyboardEvent.DOM_VK_F8:
- return "F8";
- case KeyboardEvent.DOM_VK_F9:
- return "F9";
- case KeyboardEvent.DOM_VK_F10:
- return "F10";
- case KeyboardEvent.DOM_VK_F11:
- return "F11";
- case KeyboardEvent.DOM_VK_F12:
- return "F12";
- case KeyboardEvent.DOM_VK_F13:
- return "F13";
- case KeyboardEvent.DOM_VK_F14:
- return "F14";
- case KeyboardEvent.DOM_VK_F15:
- return "F15";
- case KeyboardEvent.DOM_VK_F16:
- return "F16";
- case KeyboardEvent.DOM_VK_F17:
- return "F17";
- case KeyboardEvent.DOM_VK_F18:
- return "F18";
- case KeyboardEvent.DOM_VK_F19:
- return "F19";
- case KeyboardEvent.DOM_VK_F20:
- return "F20";
- case KeyboardEvent.DOM_VK_F21:
- return "F21";
- case KeyboardEvent.DOM_VK_F22:
- return "F22";
- case KeyboardEvent.DOM_VK_F23:
- return "F23";
- case KeyboardEvent.DOM_VK_F24:
- return "F24";
- case KeyboardEvent.DOM_VK_NUM_LOCK:
- return "NumLock";
- case KeyboardEvent.DOM_VK_SCROLL_LOCK:
- return "ScrollLock";
- case KeyboardEvent.DOM_VK_VOLUME_MUTE:
- return "AudioVolumeMute";
- case KeyboardEvent.DOM_VK_VOLUME_DOWN:
- return "AudioVolumeDown";
- case KeyboardEvent.DOM_VK_VOLUME_UP:
- return "AudioVolumeUp";
- case KeyboardEvent.DOM_VK_META:
- return "Meta";
- case KeyboardEvent.DOM_VK_ALTGR:
- return "AltGraph";
- case KeyboardEvent.DOM_VK_ATTN:
- return "Attn";
- case KeyboardEvent.DOM_VK_CRSEL:
- return "CrSel";
- case KeyboardEvent.DOM_VK_EXSEL:
- return "ExSel";
- case KeyboardEvent.DOM_VK_EREOF:
- return "EraseEof";
- case KeyboardEvent.DOM_VK_PLAY:
- return "Play";
- default:
- return "Unidentified";
- }
-}
-
-/**
- * Indicate that an event with an original target and type is expected
- * to be fired, or not expected to be fired.
- */
-function expectEvent_(expectedTarget, expectedEvent, testName) {
- if (!expectedTarget || !expectedEvent) {
- return null;
- }
-
- seenEvent = false;
-
- let type;
- if (expectedEvent.charAt(0) == "!") {
- type = expectedEvent.substring(1);
- } else {
- type = expectedEvent;
- }
-
- let handler = ev => {
- let pass = (!seenEvent && ev.originalTarget == expectedTarget && ev.type == type);
- is(pass, true, `${testName} ${type} event target ${seenEvent ? "twice" : ""}`);
- seenEvent = true;
- };
-
- expectedTarget.addEventListener(type, handler, false);
- return handler;
-}
-
-/**
- * Check if the event was fired or not. The provided event handler will
- * be removed.
- */
-function checkExpectedEvent_(
- expectedTarget, expectedEvent, eventHandler, testName) {
-
- if (eventHandler) {
- let expectEvent = (expectedEvent.charAt(0) != "!");
- let type = expectEvent;
- if (!type) {
- type = expectedEvent.substring(1);
- }
- expectedTarget.removeEventListener(type, eventHandler, false);
-
- let desc = `${type} event`;
- if (!expectEvent) {
- desc += " not";
- }
- is(seenEvent, expectEvent, `${testName} ${desc} fired`);
- }
-
- seenEvent = false;
-}
-
-/**
- * Similar to event.synthesizeMouse except that a test is performed to
- * see if an event is fired at the right target as a result.
- *
- * To test that an event is not fired, use an expected type preceded by
- * an exclamation mark, such as "!select". This might be used to test that
- * a click on a disabled element doesn't fire certain events for instance.
- *
- * @param {Element} target
- * Synthesise the mouse event on this target.
- * @param {number} offsetX
- * Horizontal offset from the target's bounding box.
- * @param {number} offsetY
- * Vertical offset from the target's bounding box.
- * @param {Object.<string, ?>} ev
- * Object which may contain the properties shiftKey, ctrlKey, altKey,
- * metaKey, accessKey, type.
- * @param {Element} expectedTarget
- * Expected originalTarget of the event.
- * @param {DOMEvent} expectedEvent
- * Expected type of the event, such as "select".
- * @param {string} testName
- * Test name when outputing results.
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeMouseExpectEvent = function (
- target, offsetX, offsetY, ev, expectedTarget, expectedEvent,
- testName, window = undefined) {
-
- let eventHandler = expectEvent_(
- expectedTarget,
- expectedEvent,
- testName);
- event.synthesizeMouse(target, offsetX, offsetY, ev, window);
- checkExpectedEvent_(
- expectedTarget,
- expectedEvent,
- eventHandler,
- testName);
-};
-
-/**
- * Similar to synthesizeKey except that a test is performed to see if
- * an event is fired at the right target as a result.
- *
- * @param {string} key
- * Key to synthesise.
- * @param {Object.<string, ?>} ev
- * Object which may contain the properties shiftKey, ctrlKey, altKey,
- * metaKey, accessKey, type.
- * @param {Element} expectedTarget
- * Expected originalTarget of the event.
- * @param {DOMEvent} expectedEvent
- * Expected type of the event, such as "select".
- * @param {string} testName
- * Test name when outputing results
- * @param {Window=} window
- * Window object. Defaults to the current window.
- *
- * To test that an event is not fired, use an expected type preceded by an
- * exclamation mark, such as "!select".
- *
- * aWindow is optional, and defaults to the current window object.
- */
-event.synthesizeKeyExpectEvent = function (
- key, ev, expectedTarget, expectedEvent, testName,
- window = undefined) {
-
- let eventHandler = expectEvent_(
- expectedTarget,
- expectedEvent,
- testName);
- event.synthesizeKey(key, ev, window);
- checkExpectedEvent_(
- expectedTarget,
- expectedEvent,
- eventHandler,
- testName);
-};
-
-/**
- * Synthesize a composition event.
- *
- * @param {DOMEvent} ev
- * The composition event information. This must have |type|
- * member. The value must be "compositionstart", "compositionend" or
- * "compositionupdate". And also this may have |data| and |locale|
- * which would be used for the value of each property of the
- * composition event. Note that the data would be ignored if the
- * event type were "compositionstart".
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeComposition = function (ev, window = undefined) {
- let domutils = getDOMWindowUtils(window);
- domutils.sendCompositionEvent(ev.type, ev.data || "", ev.locale || "");
-};
-
-/**
- * Synthesize a text event.
- *
- * The text event's information, this has |composition| and |caret|
- * members. |composition| has |string| and |clauses| members. |clauses|
- * must be array object. Each object has |length| and |attr|.
- * And |caret| has |start| and |length|. See the following tree image.
- *
- * ev
- * +-- composition
- * | +-- string
- * | +-- clauses[]
- * | +-- length
- * | +-- attr
- * +-- caret
- * +-- start
- * +-- length
- *
- * Set the composition string to |composition.string|. Set its clauses
- * information to the |clauses| array.
- *
- * When it's composing, set the each clauses' length
- * to the |composition.clauses[n].length|. The sum
- * of the all length values must be same as the length of
- * |composition.string|. Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
- * |composition.clauses[n].attr|.
- *
- * When it's not composing, set 0 to the |composition.clauses[0].length|
- * and |composition.clauses[0].attr|.
- *
- * Set caret position to the |caret.start|. Its offset from the start of
- * the composition string. Set caret length to |caret.length|. If it's
- * larger than 0, it should be wide caret. However, current nsEditor
- * doesn't support wide caret, therefore, you should always set 0 now.
- *
- * @param {Object.<string, ?>} ev
- * The text event's information,
- * @param {Window=} window
- * Window object. Defaults to the current window.
- */
-event.synthesizeText = function (ev, window = undefined) {
- let domutils = getDOMWindowUtils(window);
-
- if (!ev.composition ||
- !ev.composition.clauses ||
- !ev.composition.clauses[0]) {
- return;
- }
-
- let firstClauseLength = ev.composition.clauses[0].length;
- let firstClauseAttr = ev.composition.clauses[0].attr;
- let secondClauseLength = 0;
- let secondClauseAttr = 0;
- let thirdClauseLength = 0;
- let thirdClauseAttr = 0;
- if (ev.composition.clauses[1]) {
- secondClauseLength = ev.composition.clauses[1].length;
- secondClauseAttr = ev.composition.clauses[1].attr;
- if (event.composition.clauses[2]) {
- thirdClauseLength = ev.composition.clauses[2].length;
- thirdClauseAttr = ev.composition.clauses[2].attr;
- }
- }
-
- let caretStart = -1;
- let caretLength = 0;
- if (event.caret) {
- caretStart = ev.caret.start;
- caretLength = ev.caret.length;
- }
-
- domutils.sendTextEvent(
- ev.composition.string,
- firstClauseLength,
- firstClauseAttr,
- secondClauseLength,
- secondClauseAttr,
- thirdClauseLength,
- thirdClauseAttr,
- caretStart,
- caretLength);
-};
-
-/**
- * Synthesize a query selected text event.
- *
- * @param {Window=}
- * Window object. Defaults to the current window.
- *
- * @return {(nsIQueryContentEventResult|null)}
- * Event's result, or null if it failed.
- */
-event.synthesizeQuerySelectedText = function (window = undefined) {
- let domutils = getDOMWindowUtils(window);
- return domutils.sendQueryContentEvent(
- domutils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
-};
-
-/**
- * Synthesize a selection set event.
- *
- * @param {number} offset
- * Character offset. 0 means the first character in the selection
- * root.
- * @param {number} length
- * Length of the text. If the length is too long, the extra length
- * is ignored.
- * @param {boolean} reverse
- * If true, the selection is from |aOffset + aLength| to |aOffset|.
- * Otherwise, from |aOffset| to |aOffset + aLength|.
- * @param {Window=} window
- * Window object. Defaults to the current window.
- *
- * @return True, if succeeded. Otherwise false.
- */
-event.synthesizeSelectionSet = function (
- offset, length, reverse, window = undefined) {
- let domutils = getDOMWindowUtils(window);
- return domutils.sendSelectionSetEvent(offset, length, reverse);
-};
-
-const KEYCODES_LOOKUP = {
- "VK_SHIFT": "shiftKey",
- "VK_CONTROL": "ctrlKey",
- "VK_ALT": "altKey",
- "VK_META": "metaKey",
-};
-
-const VIRTUAL_KEYCODE_LOOKUP = {
- "\uE001": "VK_CANCEL",
- "\uE002": "VK_HELP",
- "\uE003": "VK_BACK_SPACE",
- "\uE004": "VK_TAB",
- "\uE005": "VK_CLEAR",
- "\uE006": "VK_RETURN",
- "\uE007": "VK_RETURN",
- "\uE008": "VK_SHIFT",
- "\uE009": "VK_CONTROL",
- "\uE00A": "VK_ALT",
- "\uE03D": "VK_META",
- "\uE00B": "VK_PAUSE",
- "\uE00C": "VK_ESCAPE",
- "\uE00D": "VK_SPACE", // printable
- "\uE00E": "VK_PAGE_UP",
- "\uE00F": "VK_PAGE_DOWN",
- "\uE010": "VK_END",
- "\uE011": "VK_HOME",
- "\uE012": "VK_LEFT",
- "\uE013": "VK_UP",
- "\uE014": "VK_RIGHT",
- "\uE015": "VK_DOWN",
- "\uE016": "VK_INSERT",
- "\uE017": "VK_DELETE",
- "\uE018": "VK_SEMICOLON",
- "\uE019": "VK_EQUALS",
- "\uE01A": "VK_NUMPAD0",
- "\uE01B": "VK_NUMPAD1",
- "\uE01C": "VK_NUMPAD2",
- "\uE01D": "VK_NUMPAD3",
- "\uE01E": "VK_NUMPAD4",
- "\uE01F": "VK_NUMPAD5",
- "\uE020": "VK_NUMPAD6",
- "\uE021": "VK_NUMPAD7",
- "\uE022": "VK_NUMPAD8",
- "\uE023": "VK_NUMPAD9",
- "\uE024": "VK_MULTIPLY",
- "\uE025": "VK_ADD",
- "\uE026": "VK_SEPARATOR",
- "\uE027": "VK_SUBTRACT",
- "\uE028": "VK_DECIMAL",
- "\uE029": "VK_DIVIDE",
- "\uE031": "VK_F1",
- "\uE032": "VK_F2",
- "\uE033": "VK_F3",
- "\uE034": "VK_F4",
- "\uE035": "VK_F5",
- "\uE036": "VK_F6",
- "\uE037": "VK_F7",
- "\uE038": "VK_F8",
- "\uE039": "VK_F9",
- "\uE03A": "VK_F10",
- "\uE03B": "VK_F11",
- "\uE03C": "VK_F12",
-};
-
-function getKeyCode(c) {
- if (c in VIRTUAL_KEYCODE_LOOKUP) {
- return VIRTUAL_KEYCODE_LOOKUP[c];
- }
- return c;
-}
-
-event.sendKeyDown = function (keyToSend, modifiers, document) {
- modifiers.type = "keydown";
- event.sendSingleKey(keyToSend, modifiers, document);
- // TODO This doesn't do anything since |synthesizeKeyEvent| ignores explicit
- // keypress request, and instead figures out itself when to send keypress
- if (["VK_SHIFT", "VK_CONTROL", "VK_ALT", "VK_META"].indexOf(getKeyCode(keyToSend)) < 0) {
- modifiers.type = "keypress";
- event.sendSingleKey(keyToSend, modifiers, document);
- }
- delete modifiers.type;
-};
-
-event.sendKeyUp = function (keyToSend, modifiers, window = undefined) {
- modifiers.type = "keyup";
- event.sendSingleKey(keyToSend, modifiers, window);
- delete modifiers.type;
-};
-
-/**
- * Synthesize a key event for a single key.
- *
- * @param {string} keyToSend
- * Code point or normalized key value
- * @param {?} modifiers
- * Object with properties used in KeyboardEvent (shiftkey, repeat, ...)
- * as well as, the event |type| such as keydown. All properties are optional.
- * @param {Window=} window
- * Window object. If |window| is undefined, the event is synthesized in
- * current window.
- */
-event.sendSingleKey = function (keyToSend, modifiers, window = undefined) {
- let keyCode = getKeyCode(keyToSend);
- if (keyCode in KEYCODES_LOOKUP) {
- // We assume that if |keyToSend| is a raw code point (like "\uE009") then
- // |modifiers| does not already have correct value for corresponding
- // |modName| attribute (like ctrlKey), so that value needs to be flipped
- let modName = KEYCODES_LOOKUP[keyCode];
- modifiers[modName] = !modifiers[modName];
- } else if (modifiers.shiftKey && keyCode != "Shift") {
- keyCode = keyCode.toUpperCase();
- }
- event.synthesizeKey(keyCode, modifiers, window);
-};
-
-/**
- * Focus element and, if a textual input field and no previous selection
- * state exists, move the caret to the end of the input field.
- *
- * @param {Element} element
- * Element to focus.
- */
-function focusElement(element) {
- let t = element.type;
- if (t && (t == "text" || t == "textarea")) {
- if (element.selectionEnd == 0) {
- let len = element.value.length;
- element.setSelectionRange(len, len);
- }
- }
- element.focus();
-}
-
-/**
- * @param {Array.<string>} keySequence
- * @param {Element} element
- * @param {Object.<string, boolean>=} opts
- * @param {Window=} window
- */
-event.sendKeysToElement = function (
- keySequence, el, opts = {}, window = undefined) {
-
- if (opts.ignoreVisibility || element.isVisible(el)) {
- focusElement(el);
-
- // make Object.<modifier, false> map
- let modifiers = Object.create(event.Modifiers);
- for (let modifier in event.Modifiers) {
- modifiers[modifier] = false;
- }
-
- let value = keySequence.join("");
- for (let i = 0; i < value.length; i++) {
- let c = value.charAt(i);
- event.sendSingleKey(c, modifiers, window);
- }
-
- } else {
- throw new ElementNotInteractableError("Element is not visible");
- }
-};
-
-event.sendEvent = function (eventType, el, modifiers = {}, opts = {}) {
- opts.canBubble = opts.canBubble || true;
-
- let doc = el.ownerDocument || el.document;
- let ev = doc.createEvent("Event");
-
- ev.shiftKey = modifiers["shift"];
- ev.metaKey = modifiers["meta"];
- ev.altKey = modifiers["alt"];
- ev.ctrlKey = modifiers["ctrl"];
-
- ev.initEvent(eventType, opts.canBubble, true);
- el.dispatchEvent(ev);
-};
-
-event.focus = function (el, opts = {}) {
- opts.canBubble = opts.canBubble || true;
- let doc = el.ownerDocument || el.document;
- let win = doc.defaultView;
-
- let ev = new win.FocusEvent(el);
- ev.initEvent("focus", opts.canBubble, true);
- el.dispatchEvent(ev);
-};
-
-event.mouseover = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("mouseover", el, modifiers, opts);
-};
-
-event.mousemove = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("mousemove", el, modifiers, opts);
-};
-
-event.mousedown = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("mousedown", el, modifiers, opts);
-};
-
-event.mouseup = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("mouseup", el, modifiers, opts);
-};
-
-event.click = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("click", el, modifiers, opts);
-};
-
-event.change = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("change", el, modifiers, opts);
-};
-
-event.input = function (el, modifiers = {}, opts = {}) {
- return event.sendEvent("input", el, modifiers, opts);
-};
diff --git a/testing/marionette/frame.js b/testing/marionette/frame.js
deleted file mode 100644
index fc713eb97b..0000000000
--- a/testing/marionette/frame.js
+++ /dev/null
@@ -1,260 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-this.EXPORTED_SYMBOLS = ["frame"];
-
-this.frame = {};
-
-const FRAME_SCRIPT = "chrome://marionette/content/listener.js";
-
-// list of OOP frames that has the frame script loaded
-var remoteFrames = [];
-
-/**
- * An object representing a frame that Marionette has loaded a
- * frame script in.
- */
-frame.RemoteFrame = function (windowId, frameId) {
- // outerWindowId relative to main process
- this.windowId = windowId;
- // actual frame relative to the windowId's frames list
- this.frameId = frameId;
- // assigned frame ID, used for messaging
- this.targetFrameId = this.frameId;
- // list of OOP frames that has the frame script loaded
- this.remoteFrames = [];
-};
-
-/**
- * The FrameManager will maintain the list of Out Of Process (OOP)
- * frames and will handle frame switching between them.
- *
- * It handles explicit frame switching (switchToFrame), and implicit
- * frame switching, which occurs when a modal dialog is triggered in B2G.
- *
- * @param {GeckoDriver} driver
- * Reference to the driver instance.
- */
-frame.Manager = class {
- constructor(driver) {
- // messageManager maintains the messageManager
- // for the current process' chrome frame or the global message manager
-
- // holds a member of the remoteFrames (for an OOP frame)
- // or null (for the main process)
- this.currentRemoteFrame = null;
- // frame we'll need to restore once interrupt is gone
- this.previousRemoteFrame = null;
- // set to true when we have been interrupted by a modal
- this.handledModal = false;
- this.driver = driver;
- }
-
- /**
- * Receives all messages from content messageManager.
- */
- receiveMessage(message) {
- switch (message.name) {
- case "MarionetteFrame:getInterruptedState":
- // this will return true if the calling frame was interrupted by a modal dialog
- if (this.previousRemoteFrame) {
- // get the frame window of the interrupted frame
- let interruptedFrame = Services.wm.getOuterWindowWithId(
- this.previousRemoteFrame.windowId);
-
- if (this.previousRemoteFrame.frameId !== null) {
- // find OOP frame
- let iframes = interruptedFrame.document.getElementsByTagName("iframe");
- interruptedFrame = iframes[this.previousRemoteFrame.frameId];
- }
-
- // check if the interrupted frame is the same as the calling frame
- if (interruptedFrame.src == message.target.src) {
- return {value: this.handledModal};
- }
-
- // we get here if previousRemoteFrame and currentRemoteFrame are null,
- // i.e. if we're in a non-OOP process, or we haven't switched into an OOP frame,
- // in which case, handledModal can't be set to true
- } else if (this.currentRemoteFrame === null) {
- return {value: this.handledModal};
- }
- return {value: false};
-
- // handleModal is called when we need to switch frames to the main
- // process due to a modal dialog interrupt
- case "MarionetteFrame:handleModal":
- // If previousRemoteFrame was set, that means we switched into a
- // remote frame. If this is the case, then we want to switch back
- // into the system frame. If it isn't the case, then we're in a
- // non-OOP environment, so we don't need to handle remote frames.
- let isLocal = true;
- if (this.currentRemoteFrame !== null) {
- isLocal = false;
- this.removeMessageManagerListeners(
- this.currentRemoteFrame.messageManager.get());
-
- // store the previous frame so we can switch back to it when
- // the modal is dismissed
- this.previousRemoteFrame = this.currentRemoteFrame;
-
- // by setting currentRemoteFrame to null,
- // it signifies we're in the main process
- this.currentRemoteFrame = null;
- this.driver.messageManager = Cc["@mozilla.org/globalmessagemanager;1"]
- .getService(Ci.nsIMessageBroadcaster);
- }
-
- this.handledModal = true;
- this.driver.sendOk(this.driver.command_id);
- return {value: isLocal};
-
- case "MarionetteFrame:getCurrentFrameId":
- if (this.currentRemoteFrame !== null) {
- return this.currentRemoteFrame.frameId;
- }
- }
- }
-
- getOopFrame(winId, frameId) {
- // get original frame window
- let outerWin = Services.wm.getOuterWindowWithId(winId);
- // find the OOP frame
- let f = outerWin.document.getElementsByTagName("iframe")[frameId];
- return f;
- }
-
- getFrameMM(winId, frameId) {
- let oopFrame = this.getOopFrame(winId, frameId);
- let mm = oopFrame.QueryInterface(Ci.nsIFrameLoaderOwner)
- .frameLoader.messageManager;
- return mm;
- }
-
- /**
- * Switch to OOP frame. We're handling this here so we can maintain
- * a list of remote frames.
- */
- switchToFrame(winId, frameId) {
- let oopFrame = this.getOopFrame(winId, frameId);
- let mm = this.getFrameMM(winId, frameId);
-
- // see if this frame already has our frame script loaded in it;
- // if so, just wake it up
- for (let i = 0; i < remoteFrames.length; i++) {
- let f = remoteFrames[i];
- let fmm = f.messageManager.get();
- try {
- fmm.sendAsyncMessage("aliveCheck", {});
- } catch (e) {
- if (e.result == Cr.NS_ERROR_NOT_INITIALIZED) {
- remoteFrames.splice(i--, 1);
- continue;
- }
- }
-
- if (fmm == mm) {
- this.currentRemoteFrame = f;
- this.addMessageManagerListeners(mm);
-
- mm.sendAsyncMessage("Marionette:restart");
- return oopFrame.id;
- }
- }
-
- // if we get here, then we need to load the frame script in this frame,
- // and set the frame's ChromeMessageSender as the active message manager
- // the driver will listen to.
- this.addMessageManagerListeners(mm);
- let f = new frame.RemoteFrame(winId, frameId);
- f.messageManager = Cu.getWeakReference(mm);
- remoteFrames.push(f);
- this.currentRemoteFrame = f;
-
- mm.loadFrameScript(FRAME_SCRIPT, true, true);
-
- return oopFrame.id;
- }
-
- /*
- * This function handles switching back to the frame that was
- * interrupted by the modal dialog. It gets called by the interrupted
- * frame once the dialog is dismissed and the frame resumes its process.
- */
- switchToModalOrigin() {
- // only handle this if we indeed switched out of the modal's
- // originating frame
- if (this.previousRemoteFrame !== null) {
- this.currentRemoteFrame = this.previousRemoteFrame;
- let mm = this.currentRemoteFrame.messageManager.get();
- this.addMessageManagerListeners(mm);
- }
- this.handledModal = false;
- }
-
- /**
- * Adds message listeners to the driver, listening for
- * messages from content frame scripts. It also adds a
- * MarionetteFrame:getInterruptedState message listener to the
- * FrameManager, so the frame manager's state can be checked by the frame.
- *
- * @param {nsIMessageListenerManager} mm
- * The message manager object, typically
- * ChromeMessageBroadcaster or ChromeMessageSender.
- */
- addMessageManagerListeners(mm) {
- mm.addWeakMessageListener("Marionette:ok", this.driver);
- mm.addWeakMessageListener("Marionette:done", this.driver);
- mm.addWeakMessageListener("Marionette:error", this.driver);
- mm.addWeakMessageListener("Marionette:emitTouchEvent", this.driver);
- mm.addWeakMessageListener("Marionette:log", this.driver);
- mm.addWeakMessageListener("Marionette:shareData", this.driver);
- mm.addWeakMessageListener("Marionette:switchToModalOrigin", this.driver);
- mm.addWeakMessageListener("Marionette:switchedToFrame", this.driver);
- mm.addWeakMessageListener("Marionette:getVisibleCookies", this.driver);
- mm.addWeakMessageListener("Marionette:getImportedScripts", this.driver.importedScripts);
- mm.addWeakMessageListener("Marionette:register", this.driver);
- mm.addWeakMessageListener("Marionette:listenersAttached", this.driver);
- mm.addWeakMessageListener("MarionetteFrame:handleModal", this);
- mm.addWeakMessageListener("MarionetteFrame:getCurrentFrameId", this);
- mm.addWeakMessageListener("MarionetteFrame:getInterruptedState", this);
- }
-
- /**
- * Removes listeners for messages from content frame scripts.
- * We do not remove the MarionetteFrame:getInterruptedState or
- * the Marionette:switchToModalOrigin message listener, because we
- * want to allow all known frames to contact the frame manager so
- * that it can check if it was interrupted, and if so, it will call
- * switchToModalOrigin when its process gets resumed.
- *
- * @param {nsIMessageListenerManager} mm
- * The message manager object, typically
- * ChromeMessageBroadcaster or ChromeMessageSender.
- */
- removeMessageManagerListeners(mm) {
- mm.removeWeakMessageListener("Marionette:ok", this.driver);
- mm.removeWeakMessageListener("Marionette:done", this.driver);
- mm.removeWeakMessageListener("Marionette:error", this.driver);
- mm.removeWeakMessageListener("Marionette:log", this.driver);
- mm.removeWeakMessageListener("Marionette:shareData", this.driver);
- mm.removeWeakMessageListener("Marionette:switchedToFrame", this.driver);
- mm.removeWeakMessageListener("Marionette:getVisibleCookies", this.driver);
- mm.removeWeakMessageListener("Marionette:getImportedScripts", this.driver.importedScripts);
- mm.removeWeakMessageListener("Marionette:listenersAttached", this.driver);
- mm.removeWeakMessageListener("Marionette:register", this.driver);
- mm.removeWeakMessageListener("MarionetteFrame:handleModal", this);
- mm.removeWeakMessageListener("MarionetteFrame:getCurrentFrameId", this);
- }
-};
-
-frame.Manager.prototype.QueryInterface = XPCOMUtils.generateQI(
- [Ci.nsIMessageListener, Ci.nsISupportsWeakReference]);
diff --git a/testing/marionette/harness/.flake8 b/testing/marionette/harness/.flake8
deleted file mode 100644
index 23c7990dc8..0000000000
--- a/testing/marionette/harness/.flake8
+++ /dev/null
@@ -1,3 +0,0 @@
-[flake8]
-max-line-length = 99
-exclude = __init__.py,disti/*,build/*,marionette_harness/runner/mixins/*, marionette_harness/tests/*
diff --git a/testing/marionette/harness/MANIFEST.in b/testing/marionette/harness/MANIFEST.in
deleted file mode 100644
index 1e39ed0e45..0000000000
--- a/testing/marionette/harness/MANIFEST.in
+++ /dev/null
@@ -1,3 +0,0 @@
-exclude MANIFEST.in
-include requirements.txt
-recursive-include marionette_harness/www *
diff --git a/testing/marionette/harness/README.rst b/testing/marionette/harness/README.rst
deleted file mode 100644
index 3f8865603e..0000000000
--- a/testing/marionette/harness/README.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-marionette-harness
-==================
-
-Marionette is an automation driver for Mozilla's Gecko engine. It can remotely
-control either the UI or the internal JavaScript of a Gecko platform, such as
-Firefox. It can control both the chrome (i.e. menus and functions) or the
-content (the webpage loaded inside the browsing context), giving a high level
-of control and ability to replicate user actions. In addition to performing
-actions on the browser, Marionette can also read the properties and attributes
-of the DOM.
-
-The marionette_harness package contains the test runner for Marionette, and
-allows you to run automated tests written in Python for Gecko based
-applications. Therefore it offers the necessary testcase classes, which are
-based on the unittest framework.
-
-For more information and the repository please checkout:
-
-- home and docs: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette
-
-
-Example
--------
-
-The following command will run the tests as specified via a manifest file, or
-test path, or test folder in Firefox:
-
- marionette --binary %path_to_firefox% [manifest_file | test_file | test_folder]
-
-To get an overview about all possible option run `marionette --help`.
diff --git a/testing/marionette/harness/marionette_harness/__init__.py b/testing/marionette/harness/marionette_harness/__init__.py
deleted file mode 100644
index 9ae4e1b29c..0000000000
--- a/testing/marionette/harness/marionette_harness/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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/.
-
-__version__ = '4.0.0'
-
-from .marionette_test import (
- CommonTestCase,
- expectedFailure,
- MarionetteTestCase,
- parameterized,
- run_if_e10s,
- run_if_manage_instance,
- skip,
- skip_if_chrome,
- skip_if_desktop,
- skip_if_e10s,
- skip_if_mobile,
- SkipTest,
- skip_unless_protocol,
-)
-from .runner import (
- BaseMarionetteArguments,
- BaseMarionetteTestRunner,
- BrowserMobProxyArguments,
- BrowserMobProxyTestCaseMixin,
- Marionette,
- MarionetteTest,
- MarionetteTestResult,
- MarionetteTextTestRunner,
- TestManifest,
- TestResult,
- TestResultCollection,
- WindowManagerMixin,
-)
diff --git a/testing/marionette/harness/marionette_harness/marionette_test/__init__.py b/testing/marionette/harness/marionette_harness/marionette_test/__init__.py
deleted file mode 100644
index efcf1d38eb..0000000000
--- a/testing/marionette/harness/marionette_harness/marionette_test/__init__.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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/.
-
-__version__ = '3.1.0'
-
-
-from unittest.case import (
- expectedFailure,
- skip,
- SkipTest,
-)
-
-from .decorators import (
- parameterized,
- run_if_e10s,
- run_if_manage_instance,
- skip_if_chrome,
- skip_if_desktop,
- skip_if_e10s,
- skip_if_mobile,
- skip_unless_browser_pref,
- skip_unless_protocol,
- with_parameters,
-)
-
-from .testcases import (
- CommonTestCase,
- MarionetteTestCase,
- MetaParameterized,
-)
diff --git a/testing/marionette/harness/marionette_harness/marionette_test/decorators.py b/testing/marionette/harness/marionette_harness/marionette_test/decorators.py
deleted file mode 100644
index 63f947ea28..0000000000
--- a/testing/marionette/harness/marionette_harness/marionette_test/decorators.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# 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 functools
-import types
-
-from unittest.case import (
- SkipTest,
-)
-
-
-def parameterized(func_suffix, *args, **kwargs):
- r"""Decorator which generates methods given a base method and some data.
-
- **func_suffix** is used as a suffix for the new created method and must be
- unique given a base method. if **func_suffix** countains characters that
- are not allowed in normal python function name, these characters will be
- replaced with "_".
-
- This decorator can be used more than once on a single base method. The class
- must have a metaclass of :class:`MetaParameterized`.
-
- Example::
-
- # This example will generate two methods:
- #
- # - MyTestCase.test_it_1
- # - MyTestCase.test_it_2
- #
- class MyTestCase(MarionetteTestCase):
- @parameterized("1", 5, named='name')
- @parameterized("2", 6, named='name2')
- def test_it(self, value, named=None):
- print value, named
-
- :param func_suffix: will be used as a suffix for the new method
- :param \*args: arguments to pass to the new method
- :param \*\*kwargs: named arguments to pass to the new method
- """
- def wrapped(func):
- if not hasattr(func, 'metaparameters'):
- func.metaparameters = []
- func.metaparameters.append((func_suffix, args, kwargs))
- return func
- return wrapped
-
-
-def run_if_e10s(reason):
- """Decorator which runs a test if e10s mode is active."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- with self.marionette.using_context('chrome'):
- multi_process_browser = not self.marionette.execute_script("""
- try {
- return Services.appinfo.browserTabsRemoteAutostart;
- } catch (e) {
- return false;
- }
- """)
- if multi_process_browser:
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def run_if_manage_instance(reason):
- """Decorator which runs a test if Marionette manages the application instance."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- if self.marionette.instance is None:
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_if_chrome(reason):
- """Decorator which skips a test if chrome context is active."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- if self.marionette._send_message('getContext', key='value') == 'chrome':
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_if_desktop(reason):
- """Decorator which skips a test if run on desktop."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- if self.marionette.session_capabilities.get('browserName') == 'firefox':
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_if_e10s(reason):
- """Decorator which skips a test if e10s mode is active."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- with self.marionette.using_context('chrome'):
- multi_process_browser = self.marionette.execute_script("""
- try {
- return Services.appinfo.browserTabsRemoteAutostart;
- } catch (e) {
- return false;
- }
- """)
- if multi_process_browser:
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_if_mobile(reason):
- """Decorator which skips a test if run on mobile."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- if self.marionette.session_capabilities.get('browserName') == 'fennec':
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_unless_browser_pref(reason, pref, predicate=bool):
- """Decorator which skips a test based on the value of a browser preference.
-
- :param reason: Message describing why the test need to be skipped.
- :param pref: the preference name
- :param predicate: a function that should return false to skip the test.
- The function takes one parameter, the preference value.
- Defaults to the python built-in bool function.
-
- Note that the preference must exist, else a failure is raised.
-
- Example: ::
-
- class TestSomething(MarionetteTestCase):
- @skip_unless_browser_pref("Sessionstore needs to be enabled for crashes",
- "browser.sessionstore.resume_from_crash",
- lambda value: value is True,
- )
- def test_foo(self):
- pass # test implementation here
-
- """
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
- if not callable(predicate):
- raise ValueError('predicate must be callable')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- value = self.marionette.get_pref(pref)
- if value is None:
- self.fail("No such browser preference: {0!r}".format(pref))
- if not predicate(value):
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def skip_unless_protocol(reason, predicate):
- """Decorator which skips a test if the predicate does not match the current protocol level."""
- def decorator(test_item):
- if not isinstance(test_item, types.FunctionType):
- raise Exception('Decorator only supported for functions')
- if not callable(predicate):
- raise ValueError('predicate must be callable')
-
- @functools.wraps(test_item)
- def skip_wrapper(self, *args, **kwargs):
- level = self.marionette.client.protocol
- if not predicate(level):
- raise SkipTest(reason)
- return test_item(self, *args, **kwargs)
- return skip_wrapper
- return decorator
-
-
-def with_parameters(parameters):
- """Decorator which generates methods given a base method and some data.
-
- Acts like :func:`parameterized`, but define all methods in one call.
-
- Example::
-
- # This example will generate two methods:
- #
- # - MyTestCase.test_it_1
- # - MyTestCase.test_it_2
- #
-
- DATA = [("1", [5], {'named':'name'}), ("2", [6], {'named':'name2'})]
-
- class MyTestCase(MarionetteTestCase):
- @with_parameters(DATA)
- def test_it(self, value, named=None):
- print value, named
-
- :param parameters: list of tuples (**func_suffix**, **args**, **kwargs**)
- defining parameters like in :func:`todo`.
- """
- def wrapped(func):
- func.metaparameters = parameters
- return func
- return wrapped
diff --git a/testing/marionette/harness/marionette_harness/marionette_test/testcases.py b/testing/marionette/harness/marionette_harness/marionette_test/testcases.py
deleted file mode 100644
index 5051e3351e..0000000000
--- a/testing/marionette/harness/marionette_harness/marionette_test/testcases.py
+++ /dev/null
@@ -1,504 +0,0 @@
-# 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 imp
-import os
-import re
-import sys
-import time
-import types
-import unittest
-import warnings
-import weakref
-
-from unittest.case import (
- _ExpectedFailure,
- _UnexpectedSuccess,
- SkipTest,
-)
-
-from marionette_driver.errors import (
- MarionetteException,
- ScriptTimeoutException,
- TimeoutException,
-)
-from mozlog import get_default_logger
-
-
-def _wraps_parameterized(func, func_suffix, args, kwargs):
- """Internal: Decorator used in class MetaParameterized."""
- def wrapper(self):
- return func(self, *args, **kwargs)
- wrapper.__name__ = func.__name__ + '_' + str(func_suffix)
- wrapper.__doc__ = '[{0}] {1}'.format(func_suffix, func.__doc__)
- return wrapper
-
-
-class MetaParameterized(type):
- """
- A metaclass that allow a class to use decorators.
-
- It can be used like :func:`parameterized`
- or :func:`with_parameters` to generate new methods.
- """
-
- RE_ESCAPE_BAD_CHARS = re.compile(r'[\.\(\) -/]')
-
- def __new__(cls, name, bases, attrs):
- for k, v in attrs.items():
- if callable(v) and hasattr(v, 'metaparameters'):
- for func_suffix, args, kwargs in v.metaparameters:
- func_suffix = cls.RE_ESCAPE_BAD_CHARS.sub('_', func_suffix)
- wrapper = _wraps_parameterized(v, func_suffix, args, kwargs)
- if wrapper.__name__ in attrs:
- raise KeyError("{0} is already a defined method on {1}"
- .format(wrapper.__name__, name))
- attrs[wrapper.__name__] = wrapper
- del attrs[k]
-
- return type.__new__(cls, name, bases, attrs)
-
-
-class JSTest:
- head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
- context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
- timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
- inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
-
-
-class CommonTestCase(unittest.TestCase):
-
- __metaclass__ = MetaParameterized
- match_re = None
- failureException = AssertionError
- pydebugger = None
-
- def __init__(self, methodName, marionette_weakref, fixtures, **kwargs):
- super(CommonTestCase, self).__init__(methodName)
- self.methodName = methodName
-
- self._marionette_weakref = marionette_weakref
- self.fixtures = fixtures
-
- self.loglines = []
- self.duration = 0
- self.start_time = 0
- self.expected = kwargs.pop('expected', 'pass')
- self.logger = get_default_logger()
-
- def _enter_pm(self):
- if self.pydebugger:
- self.pydebugger.post_mortem(sys.exc_info()[2])
-
- def _addSkip(self, result, reason):
- addSkip = getattr(result, 'addSkip', None)
- if addSkip is not None:
- addSkip(self, reason)
- else:
- warnings.warn("TestResult has no addSkip method, skips not reported",
- RuntimeWarning, 2)
- result.addSuccess(self)
-
- def run(self, result=None):
- # Bug 967566 suggests refactoring run, which would hopefully
- # mean getting rid of this inner function, which only sits
- # here to reduce code duplication:
- def expected_failure(result, exc_info):
- addExpectedFailure = getattr(result, "addExpectedFailure", None)
- if addExpectedFailure is not None:
- addExpectedFailure(self, exc_info)
- else:
- warnings.warn("TestResult has no addExpectedFailure method, "
- "reporting as passes", RuntimeWarning)
- result.addSuccess(self)
-
- self.start_time = time.time()
- orig_result = result
- if result is None:
- result = self.defaultTestResult()
- startTestRun = getattr(result, 'startTestRun', None)
- if startTestRun is not None:
- startTestRun()
-
- result.startTest(self)
-
- testMethod = getattr(self, self._testMethodName)
- if (getattr(self.__class__, "__unittest_skip__", False) or
- getattr(testMethod, "__unittest_skip__", False)):
- # If the class or method was skipped.
- try:
- skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') or
- getattr(testMethod, '__unittest_skip_why__', ''))
- self._addSkip(result, skip_why)
- finally:
- result.stopTest(self)
- self.stop_time = time.time()
- return
- try:
- success = False
- try:
- if self.expected == "fail":
- try:
- self.setUp()
- except Exception:
- raise _ExpectedFailure(sys.exc_info())
- else:
- self.setUp()
- except SkipTest as e:
- self._addSkip(result, str(e))
- except KeyboardInterrupt:
- raise
- except _ExpectedFailure as e:
- expected_failure(result, e.exc_info)
- except:
- self._enter_pm()
- result.addError(self, sys.exc_info())
- else:
- try:
- if self.expected == 'fail':
- try:
- testMethod()
- except:
- raise _ExpectedFailure(sys.exc_info())
- raise _UnexpectedSuccess
- else:
- testMethod()
- except self.failureException:
- self._enter_pm()
- result.addFailure(self, sys.exc_info())
- except KeyboardInterrupt:
- raise
- except _ExpectedFailure as e:
- expected_failure(result, e.exc_info)
- except _UnexpectedSuccess:
- addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
- if addUnexpectedSuccess is not None:
- addUnexpectedSuccess(self)
- else:
- warnings.warn("TestResult has no addUnexpectedSuccess method, "
- "reporting as failures",
- RuntimeWarning)
- result.addFailure(self, sys.exc_info())
- except SkipTest as e:
- self._addSkip(result, str(e))
- except:
- self._enter_pm()
- result.addError(self, sys.exc_info())
- else:
- success = True
- try:
- if self.expected == "fail":
- try:
- self.tearDown()
- except:
- raise _ExpectedFailure(sys.exc_info())
- else:
- self.tearDown()
- except KeyboardInterrupt:
- raise
- except _ExpectedFailure as e:
- expected_failure(result, e.exc_info)
- except:
- self._enter_pm()
- result.addError(self, sys.exc_info())
- success = False
- # Here we could handle doCleanups() instead of calling cleanTest directly
- self.cleanTest()
-
- if success:
- result.addSuccess(self)
-
- finally:
- result.stopTest(self)
- if orig_result is None:
- stopTestRun = getattr(result, 'stopTestRun', None)
- if stopTestRun is not None:
- stopTestRun()
-
- @classmethod
- def match(cls, filename):
- """Determine if the specified filename should be handled by this test class.
-
- This is done by looking for a match for the filename using cls.match_re.
- """
- if not cls.match_re:
- return False
- m = cls.match_re.match(filename)
- return m is not None
-
- @classmethod
- def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
- fixtures, testvars, **kwargs):
- """Add all the tests in the specified file to the specified suite."""
- raise NotImplementedError
-
- @property
- def test_name(self):
- if hasattr(self, 'jsFile'):
- return os.path.basename(self.jsFile)
- else:
- return '{0}.py {1}.{2}'.format(self.__class__.__module__,
- self.__class__.__name__,
- self._testMethodName)
-
- def id(self):
- # TBPL starring requires that the "test name" field of a failure message
- # not differ over time. The test name to be used is passed to
- # mozlog via the test id, so this is overriden to maintain
- # consistency.
- return self.test_name
-
- def setUp(self):
- # Convert the marionette weakref to an object, just for the
- # duration of the test; this is deleted in tearDown() to prevent
- # a persistent circular reference which in turn would prevent
- # proper garbage collection.
- self.start_time = time.time()
- self.marionette = self._marionette_weakref()
- if self.marionette.session is None:
- self.marionette.start_session()
- self.marionette.timeout.reset()
-
- super(CommonTestCase, self).setUp()
-
- def cleanTest(self):
- self._deleteSession()
-
- def _deleteSession(self):
- if hasattr(self, 'start_time'):
- self.duration = time.time() - self.start_time
- if hasattr(self.marionette, 'session'):
- if self.marionette.session is not None:
- try:
- self.loglines.extend(self.marionette.get_logs())
- except Exception, inst:
- self.loglines = [['Error getting log: {}'.format(inst)]]
- try:
- self.marionette.delete_session()
- except IOError:
- # Gecko has crashed?
- pass
- self.marionette = None
-
- def setup_SpecialPowers_observer(self):
- self.marionette.set_context("chrome")
- self.marionette.execute_script("""
-let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
-Components.utils.import("resource://gre/modules/Preferences.jsm");
-Preferences.set(SECURITY_PREF, true);
-
-if (!testUtils.hasOwnProperty("specialPowersObserver")) {
- let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader);
- loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
- testUtils);
- testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
- testUtils.specialPowersObserver.init();
-}
-""")
-
- def run_js_test(self, filename, marionette=None):
- """Run a JavaScript test file.
-
- It collects its set of assertions into the current test's results.
-
- :param filename: The path to the JavaScript test file to execute.
- May be relative to the current script.
- :param marionette: The Marionette object in which to execute the test.
- Defaults to self.marionette.
- """
- marionette = marionette or self.marionette
- if not os.path.isabs(filename):
- # Find the caller's filename and make the path relative to that.
- caller_file = sys._getframe(1).f_globals.get('__file__', '')
- caller_file = os.path.abspath(caller_file)
- filename = os.path.join(os.path.dirname(caller_file), filename)
- self.assert_(os.path.exists(filename),
- 'Script "{}" must exist' .format(filename))
- original_test_name = self.marionette.test_name
- self.marionette.test_name = os.path.basename(filename)
- f = open(filename, 'r')
- js = f.read()
- args = []
-
- head_js = JSTest.head_js_re.search(js)
- if head_js:
- head_js = head_js.group(3)
- head = open(os.path.join(os.path.dirname(filename), head_js), 'r')
- js = head.read() + js
-
- context = JSTest.context_re.search(js)
- if context:
- context = context.group(3)
- else:
- context = 'content'
-
- if 'SpecialPowers' in js:
- self.setup_SpecialPowers_observer()
-
- if context == 'content':
- js = "var SpecialPowers = window.wrappedJSObject.SpecialPowers;\n" + js
- else:
- marionette.execute_script("""
- if (typeof(SpecialPowers) == 'undefined') {
- let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader);
- loader.loadSubScript("chrome://specialpowers/content/specialpowersAPI.js");
- loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js");
- loader.loadSubScript("chrome://specialpowers/content/ChromePowers.js");
- }
- """)
-
- marionette.set_context(context)
-
- if context != 'chrome':
- marionette.navigate('data:text/html,<html>test page</html>')
-
- timeout = JSTest.timeout_re.search(js)
- if timeout:
- ms = timeout.group(3)
- marionette.timeout.script = int(ms) / 1000.0
-
- inactivity_timeout = JSTest.inactivity_timeout_re.search(js)
- if inactivity_timeout:
- inactivity_timeout = int(inactivity_timeout.group(3))
-
- try:
- results = marionette.execute_js_script(
- js,
- args,
- inactivity_timeout=inactivity_timeout,
- filename=os.path.basename(filename)
- )
-
- self.assertTrue('timeout' not in filename,
- 'expected timeout not triggered')
-
- if 'fail' in filename:
- self.assertTrue(len(results['failures']) > 0,
- "expected test failures didn't occur")
- else:
- for failure in results['failures']:
- diag = "" if failure.get('diag') is None else failure['diag']
- name = ("got false, expected true" if failure.get('name') is None else
- failure['name'])
- self.logger.test_status(self.test_name, name, 'FAIL',
- message=diag)
- for failure in results['expectedFailures']:
- diag = "" if failure.get('diag') is None else failure['diag']
- name = ("got false, expected false" if failure.get('name') is None else
- failure['name'])
- self.logger.test_status(self.test_name, name, 'FAIL',
- expected='FAIL', message=diag)
- for failure in results['unexpectedSuccesses']:
- diag = "" if failure.get('diag') is None else failure['diag']
- name = ("got true, expected false" if failure.get('name') is None else
- failure['name'])
- self.logger.test_status(self.test_name, name, 'PASS',
- expected='FAIL', message=diag)
- self.assertEqual(0, len(results['failures']),
- '{} tests failed' .format(len(results['failures'])))
- if len(results['unexpectedSuccesses']) > 0:
- raise _UnexpectedSuccess('')
- if len(results['expectedFailures']) > 0:
- raise _ExpectedFailure((AssertionError, AssertionError(''), None))
-
- self.assertTrue(results['passed'] +
- len(results['failures']) +
- len(results['expectedFailures']) +
- len(results['unexpectedSuccesses']) > 0,
- 'no tests run')
-
- except ScriptTimeoutException:
- if 'timeout' in filename:
- # expected exception
- pass
- else:
- self.loglines = marionette.get_logs()
- raise
- self.marionette.test_name = original_test_name
-
-
-class MarionetteTestCase(CommonTestCase):
-
- match_re = re.compile(r"test_(.*)\.py$")
-
- def __init__(self, marionette_weakref, fixtures, methodName='runTest',
- filepath='', **kwargs):
- self.filepath = filepath
- self.testvars = kwargs.pop('testvars', None)
-
- super(MarionetteTestCase, self).__init__(
- methodName, marionette_weakref=marionette_weakref, fixtures=fixtures, **kwargs)
-
- @classmethod
- def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
- fixtures, testvars, **kwargs):
- # since we use imp.load_source to load test modules, if a module
- # is loaded with the same name as another one the module would just be
- # reloaded.
- #
- # We may end up by finding too many test in a module then since
- # reload() only update the module dict (so old keys are still there!)
- # see https://docs.python.org/2/library/functions.html#reload
- #
- # we get rid of that by removing the module from sys.modules,
- # so we ensure that it will be fully loaded by the
- # imp.load_source call.
- if mod_name in sys.modules:
- del sys.modules[mod_name]
-
- test_mod = imp.load_source(mod_name, filepath)
-
- for name in dir(test_mod):
- obj = getattr(test_mod, name)
- if (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, unittest.TestCase)):
- testnames = testloader.getTestCaseNames(obj)
- for testname in testnames:
- suite.addTest(obj(weakref.ref(marionette),
- fixtures,
- methodName=testname,
- filepath=filepath,
- testvars=testvars,
- **kwargs))
-
- def setUp(self):
- super(MarionetteTestCase, self).setUp()
- self.marionette.test_name = self.test_name
- self.marionette.execute_script("log('TEST-START: {0}:{1}')"
- .format(self.filepath.replace('\\', '\\\\'),
- self.methodName),
- sandbox="simpletest")
-
- def tearDown(self):
- # In the case no session is active (eg. the application was quit), start
- # a new session for clean-up steps.
- if not self.marionette.session:
- self.marionette.start_session()
-
- if not self.marionette.crashed:
- try:
- self.marionette.clear_imported_scripts()
- self.marionette.execute_script("log('TEST-END: {0}:{1}')"
- .format(self.filepath.replace('\\', '\\\\'),
- self.methodName),
- sandbox="simpletest")
- self.marionette.test_name = None
- except (MarionetteException, IOError):
- # We have tried to log the test end when there is no listener
- # object that we can access
- pass
-
- super(MarionetteTestCase, self).tearDown()
-
- def wait_for_condition(self, method, timeout=30):
- timeout = float(timeout) + time.time()
- while time.time() < timeout:
- value = method(self.marionette)
- if value:
- return value
- time.sleep(0.5)
- else:
- raise TimeoutException("wait_for_condition timed out")
diff --git a/testing/marionette/harness/marionette_harness/runner/__init__.py b/testing/marionette/harness/marionette_harness/runner/__init__.py
deleted file mode 100644
index e8a0575bb9..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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 .base import (
- BaseMarionetteArguments,
- BaseMarionetteTestRunner,
- Marionette,
- MarionetteTest,
- MarionetteTestResult,
- MarionetteTextTestRunner,
- TestManifest,
- TestResult,
- TestResultCollection,
-)
-
-from .mixins import (
- BrowserMobProxyTestCaseMixin,
- BrowserMobProxyArguments,
- BrowserMobTestCase,
- WindowManagerMixin,
-)
diff --git a/testing/marionette/harness/marionette_harness/runner/base.py b/testing/marionette/harness/marionette_harness/runner/base.py
deleted file mode 100644
index 72f23524ba..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/base.py
+++ /dev/null
@@ -1,1076 +0,0 @@
-# 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 json
-import os
-import random
-import re
-import socket
-import sys
-import time
-import traceback
-import unittest
-
-from argparse import ArgumentParser
-from copy import deepcopy
-
-import mozinfo
-import moznetwork
-import mozprofile
-import mozversion
-import serve
-
-from manifestparser import TestManifest
-from manifestparser.filters import tags
-from marionette_driver.marionette import Marionette
-from moztest.adapters.unit import StructuredTestResult, StructuredTestRunner
-from moztest.results import TestResult, TestResultCollection, relevant_line
-from serve import iter_proc, iter_url
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-
-def update_mozinfo(path=None):
- """Walk up directories to find mozinfo.json and update the info."""
- path = path or here
- dirs = set()
- while path != os.path.expanduser('~'):
- if path in dirs:
- break
- dirs.add(path)
- path = os.path.split(path)[0]
-
- return mozinfo.find_and_update_from_json(*dirs)
-
-
-class MarionetteTest(TestResult):
-
- @property
- def test_name(self):
- if self.test_class is not None:
- return '{0}.py {1}.{2}'.format(self.test_class.split('.')[0],
- self.test_class,
- self.name)
- else:
- return self.name
-
-
-class MarionetteTestResult(StructuredTestResult, TestResultCollection):
-
- resultClass = MarionetteTest
-
- def __init__(self, *args, **kwargs):
- self.marionette = kwargs.pop('marionette')
- TestResultCollection.__init__(self, 'MarionetteTest')
- self.passed = 0
- self.testsRun = 0
- self.result_modifiers = [] # used by mixins to modify the result
- StructuredTestResult.__init__(self, *args, **kwargs)
-
- @property
- def skipped(self):
- return [t for t in self if t.result == 'SKIPPED']
-
- @skipped.setter
- def skipped(self, value):
- pass
-
- @property
- def expectedFailures(self):
- return [t for t in self if t.result == 'KNOWN-FAIL']
-
- @expectedFailures.setter
- def expectedFailures(self, value):
- pass
-
- @property
- def unexpectedSuccesses(self):
- return [t for t in self if t.result == 'UNEXPECTED-PASS']
-
- @unexpectedSuccesses.setter
- def unexpectedSuccesses(self, value):
- pass
-
- @property
- def tests_passed(self):
- return [t for t in self if t.result == 'PASS']
-
- @property
- def errors(self):
- return [t for t in self if t.result == 'ERROR']
-
- @errors.setter
- def errors(self, value):
- pass
-
- @property
- def failures(self):
- return [t for t in self if t.result == 'UNEXPECTED-FAIL']
-
- @failures.setter
- def failures(self, value):
- pass
-
- @property
- def duration(self):
- if self.stop_time:
- return self.stop_time - self.start_time
- else:
- return 0
-
- def add_test_result(self, test, result_expected='PASS',
- result_actual='PASS', output='', context=None, **kwargs):
- def get_class(test):
- return test.__class__.__module__ + '.' + test.__class__.__name__
-
- name = str(test).split()[0]
- test_class = get_class(test)
- if hasattr(test, 'jsFile'):
- name = os.path.basename(test.jsFile)
- test_class = None
-
- t = self.resultClass(name=name, test_class=test_class,
- time_start=test.start_time, result_expected=result_expected,
- context=context, **kwargs)
- # call any registered result modifiers
- for modifier in self.result_modifiers:
- result_expected, result_actual, output, context = modifier(
- t, result_expected, result_actual, output, context)
- t.finish(result_actual,
- time_end=time.time() if test.start_time else 0,
- reason=relevant_line(output),
- output=output)
- self.append(t)
-
- def addError(self, test, err):
- self.add_test_result(test, output=self._exc_info_to_string(err, test),
- result_actual='ERROR')
- super(MarionetteTestResult, self).addError(test, err)
-
- def addFailure(self, test, err):
- self.add_test_result(test, output=self._exc_info_to_string(err, test),
- result_actual='UNEXPECTED-FAIL')
- super(MarionetteTestResult, self).addFailure(test, err)
-
- def addSuccess(self, test):
- self.passed += 1
- self.add_test_result(test, result_actual='PASS')
- super(MarionetteTestResult, self).addSuccess(test)
-
- def addExpectedFailure(self, test, err):
- """Called when an expected failure/error occured."""
- self.add_test_result(test, output=self._exc_info_to_string(err, test),
- result_actual='KNOWN-FAIL')
- super(MarionetteTestResult, self).addExpectedFailure(test, err)
-
- def addUnexpectedSuccess(self, test):
- """Called when a test was expected to fail, but succeed."""
- self.add_test_result(test, result_actual='UNEXPECTED-PASS')
- super(MarionetteTestResult, self).addUnexpectedSuccess(test)
-
- def addSkip(self, test, reason):
- self.add_test_result(test, output=reason, result_actual='SKIPPED')
- super(MarionetteTestResult, self).addSkip(test, reason)
-
- def getInfo(self, test):
- return test.test_name
-
- def getDescription(self, test):
- doc_first_line = test.shortDescription()
- if self.descriptions and doc_first_line:
- return '\n'.join((str(test), doc_first_line))
- else:
- desc = str(test)
- if hasattr(test, 'jsFile'):
- desc = "{0}, {1}".format(test.jsFile, desc)
- return desc
-
- def printLogs(self, test):
- for testcase in test._tests:
- if hasattr(testcase, 'loglines') and testcase.loglines:
- # Don't dump loglines to the console if they only contain
- # TEST-START and TEST-END.
- skip_log = True
- for line in testcase.loglines:
- str_line = ' '.join(line)
- if 'TEST-END' not in str_line and 'TEST-START' not in str_line:
- skip_log = False
- break
- if skip_log:
- return
- self.logger.info('START LOG:')
- for line in testcase.loglines:
- self.logger.info(' '.join(line).encode('ascii', 'replace'))
- self.logger.info('END LOG:')
-
- def stopTest(self, *args, **kwargs):
- unittest._TextTestResult.stopTest(self, *args, **kwargs)
- if self.marionette.check_for_crash():
- # this tells unittest.TestSuite not to continue running tests
- self.shouldStop = True
- test = next((a for a in args if isinstance(a, unittest.TestCase)),
- None)
- if test:
- self.addError(test, sys.exc_info())
-
-
-class MarionetteTextTestRunner(StructuredTestRunner):
-
- resultclass = MarionetteTestResult
-
- def __init__(self, **kwargs):
- self.marionette = kwargs.pop('marionette')
- self.capabilities = kwargs.pop('capabilities')
-
- StructuredTestRunner.__init__(self, **kwargs)
-
- def _makeResult(self):
- return self.resultclass(self.stream,
- self.descriptions,
- self.verbosity,
- marionette=self.marionette,
- logger=self.logger,
- result_callbacks=self.result_callbacks)
-
- def run(self, test):
- result = super(MarionetteTextTestRunner, self).run(test)
- result.printLogs(test)
- return result
-
-
-class BaseMarionetteArguments(ArgumentParser):
- # Bug 1336953 - Until we can remove the socket timeout parameter it has to be
- # set a default value which is larger than the longest timeout as defined by the
- # WebDriver spec. In that case its 300s for page load. Also add another minute
- # so that slow builds have enough time to send the timeout error to the client.
- socket_timeout_default = 360.0
-
- def __init__(self, **kwargs):
- ArgumentParser.__init__(self, **kwargs)
-
- def dir_path(path):
- path = os.path.abspath(os.path.expanduser(path))
- if not os.access(path, os.F_OK):
- os.makedirs(path)
- return path
-
- self.argument_containers = []
- self.add_argument('tests',
- nargs='*',
- default=[],
- help='Tests to run. '
- 'One or more paths to test files (Python or JS), '
- 'manifest files (.ini) or directories. '
- 'When a directory is specified, '
- 'all test files in the directory will be run.')
- self.add_argument('--binary',
- help='path to gecko executable to launch before running the test')
- self.add_argument('--address',
- help='host:port of running Gecko instance to connect to')
- self.add_argument('--emulator',
- action='store_true',
- help='If no --address is given, then the harness will launch an '
- 'emulator. (See Remote options group.) '
- 'If --address is given, then the harness assumes you are '
- 'running an emulator already, and will launch gecko app '
- 'on that emulator.')
- self.add_argument('--app',
- help='application to use. see marionette_driver.geckoinstance')
- self.add_argument('--app-arg',
- dest='app_args',
- action='append',
- default=[],
- help='specify a command line argument to be passed onto the application')
- self.add_argument('--profile',
- help='profile to use when launching the gecko process. If not passed, '
- 'then a profile will be constructed and used',
- type=dir_path)
- self.add_argument('--pref',
- action='append',
- dest='prefs_args',
- help="A preference to set. Must be a key-value pair separated by a ':'.")
- self.add_argument('--preferences',
- action='append',
- dest='prefs_files',
- help="read preferences from a JSON or INI file. For INI, use "
- "'file.ini:section' to specify a particular section.")
- self.add_argument('--addon',
- action='append',
- dest='addons',
- help="addon to install; repeat for multiple addons.")
- self.add_argument('--repeat',
- type=int,
- default=0,
- help='number of times to repeat the test(s)')
- self.add_argument('--testvars',
- action='append',
- help='path to a json file with any test data required')
- self.add_argument('--symbols-path',
- help='absolute path to directory containing breakpad symbols, or the '
- 'url of a zip file containing symbols')
- self.add_argument('--startup-timeout',
- type=int,
- default=60,
- help='the max number of seconds to wait for a Marionette connection '
- 'after launching a binary')
- self.add_argument('--shuffle',
- action='store_true',
- default=False,
- help='run tests in a random order')
- self.add_argument('--shuffle-seed',
- type=int,
- default=random.randint(0, sys.maxint),
- help='Use given seed to shuffle tests')
- self.add_argument('--total-chunks',
- type=int,
- help='how many chunks to split the tests up into')
- self.add_argument('--this-chunk',
- type=int,
- help='which chunk to run')
- self.add_argument('--server-root',
- help='url to a webserver or path to a document root from which content '
- 'resources are served (default: {}).'.format(os.path.join(
- os.path.dirname(here), 'www')))
- self.add_argument('--gecko-log',
- help="Define the path to store log file. If the path is"
- " a directory, the real log file will be created"
- " given the format gecko-(timestamp).log. If it is"
- " a file, if will be used directly. '-' may be passed"
- " to write to stdout. Default: './gecko.log'")
- self.add_argument('--logger-name',
- default='Marionette-based Tests',
- help='Define the name to associate with the logger used')
- self.add_argument('--jsdebugger',
- action='store_true',
- default=False,
- help='Enable the jsdebugger for marionette javascript.')
- self.add_argument('--pydebugger',
- help='Enable python post-mortem debugger when a test fails.'
- ' Pass in the debugger you want to use, eg pdb or ipdb.')
- self.add_argument('--socket-timeout',
- type=float,
- default=self.socket_timeout_default,
- help='Set the global timeout for marionette socket operations.'
- ' Default: %(default)ss.')
- self.add_argument('--disable-e10s',
- action='store_false',
- dest='e10s',
- default=True,
- help='Disable e10s when running marionette tests.')
- self.add_argument('--tag',
- action='append', dest='test_tags',
- default=None,
- help="Filter out tests that don't have the given tag. Can be "
- "used multiple times in which case the test must contain "
- "at least one of the given tags.")
- self.add_argument('--workspace',
- action='store',
- default=None,
- help="Path to directory for Marionette output. "
- "(Default: .) (Default profile dest: TMP)",
- type=dir_path)
- self.add_argument('-v', '--verbose',
- action='count',
- help='Increase verbosity to include debug messages with -v, '
- 'and trace messages with -vv.')
- self.register_argument_container(RemoteMarionetteArguments())
-
- def register_argument_container(self, container):
- group = self.add_argument_group(container.name)
-
- for cli, kwargs in container.args:
- group.add_argument(*cli, **kwargs)
-
- self.argument_containers.append(container)
-
- def parse_known_args(self, args=None, namespace=None):
- args, remainder = ArgumentParser.parse_known_args(self, args, namespace)
- for container in self.argument_containers:
- if hasattr(container, 'parse_args_handler'):
- container.parse_args_handler(args)
- return (args, remainder)
-
- def _get_preferences(self, prefs_files, prefs_args):
- """Return user defined profile preferences as a dict."""
- # object that will hold the preferences
- prefs = mozprofile.prefs.Preferences()
-
- # add preferences files
- if prefs_files:
- for prefs_file in prefs_files:
- prefs.add_file(prefs_file)
-
- separator = ':'
- cli_prefs = []
- if prefs_args:
- misformatted = []
- for pref in prefs_args:
- if separator not in pref:
- misformatted.append(pref)
- else:
- cli_prefs.append(pref.split(separator, 1))
- if misformatted:
- self._print_message("Warning: Ignoring preferences not in key{}value format: {}\n"
- .format(separator, ", ".join(misformatted)))
- # string preferences
- prefs.add(cli_prefs, cast=True)
-
- return dict(prefs())
-
- def verify_usage(self, args):
- if not args.tests:
- self.error('You must specify one or more test files, manifests, or directories.')
-
- missing_tests = [path for path in args.tests if not os.path.exists(path)]
- if missing_tests:
- self.error("Test file(s) not found: " + " ".join([path for path in missing_tests]))
-
- if not args.address and not args.binary and not args.emulator:
- self.error('You must specify --binary, or --address, or --emulator')
-
- if args.total_chunks is not None and args.this_chunk is None:
- self.error('You must specify which chunk to run.')
-
- if args.this_chunk is not None and args.total_chunks is None:
- self.error('You must specify how many chunks to split the tests into.')
-
- if args.total_chunks is not None:
- if not 1 < args.total_chunks:
- self.error('Total chunks must be greater than 1.')
- if not 1 <= args.this_chunk <= args.total_chunks:
- self.error('Chunk to run must be between 1 and {}.'.format(args.total_chunks))
-
- if args.jsdebugger:
- args.app_args.append('-jsdebugger')
- args.socket_timeout = None
-
- args.prefs = self._get_preferences(args.prefs_files, args.prefs_args)
-
- for container in self.argument_containers:
- if hasattr(container, 'verify_usage_handler'):
- container.verify_usage_handler(args)
-
- return args
-
-
-class RemoteMarionetteArguments(object):
- name = 'Remote (Emulator/Device)'
- args = [
- [['--emulator-binary'],
- {'help': 'Path to emulator binary. By default mozrunner uses `which emulator`',
- 'dest': 'emulator_bin',
- }],
- [['--adb'],
- {'help': 'Path to the adb. By default mozrunner uses `which adb`',
- 'dest': 'adb_path'
- }],
- [['--avd'],
- {'help': ('Name of an AVD available in your environment.'
- 'See mozrunner.FennecEmulatorRunner'),
- }],
- [['--avd-home'],
- {'help': 'Path to avd parent directory',
- }],
- [['--device'],
- {'help': ('Serial ID to connect to as seen in `adb devices`,'
- 'e.g emulator-5444'),
- 'dest': 'device_serial',
- }],
- [['--package'],
- {'help': 'Name of Android package, e.g. org.mozilla.fennec',
- 'dest': 'package_name',
- }],
-
- ]
-
-
-class Fixtures(object):
- def where_is(self, uri, on="http"):
- return serve.where_is(uri, on)
-
-
-class BaseMarionetteTestRunner(object):
-
- textrunnerclass = MarionetteTextTestRunner
- driverclass = Marionette
-
- def __init__(self, address=None,
- app=None, app_args=None, binary=None, profile=None,
- logger=None, logdir=None,
- repeat=0, testvars=None,
- symbols_path=None,
- shuffle=False, shuffle_seed=random.randint(0, sys.maxint), this_chunk=1,
- total_chunks=1,
- server_root=None, gecko_log=None, result_callbacks=None,
- prefs=None, test_tags=None,
- socket_timeout=BaseMarionetteArguments.socket_timeout_default,
- startup_timeout=None, addons=None, workspace=None,
- verbose=0, e10s=True, emulator=False, **kwargs):
- self._appinfo = None
- self._appName = None
- self._capabilities = None
- self._filename_pattern = None
- self._version_info = {}
-
- self.fixture_servers = {}
- self.fixtures = Fixtures()
- self.extra_kwargs = kwargs
- self.test_kwargs = deepcopy(kwargs)
- self.address = address
- self.app = app
- self.app_args = app_args or []
- self.bin = binary
- self.emulator = emulator
- self.profile = profile
- self.addons = addons
- self.logger = logger
- self.marionette = None
- self.logdir = logdir
- self.repeat = repeat
- self.symbols_path = symbols_path
- self.socket_timeout = socket_timeout
- self.shuffle = shuffle
- self.shuffle_seed = shuffle_seed
- self.server_root = server_root
- self.this_chunk = this_chunk
- self.total_chunks = total_chunks
- self.mixin_run_tests = []
- self.manifest_skipped_tests = []
- self.tests = []
- self.result_callbacks = result_callbacks or []
- self.prefs = prefs or {}
- self.test_tags = test_tags
- self.startup_timeout = startup_timeout
- self.workspace = workspace
- # If no workspace is set, default location for gecko.log is .
- # and default location for profile is TMP
- self.workspace_path = workspace or os.getcwd()
- self.verbose = verbose
- self.e10s = e10s
- if self.e10s:
- self.prefs.update({
- 'browser.tabs.remote.autostart': True,
- 'browser.tabs.remote.force-enable': True,
- 'extensions.e10sBlocksEnabling': False
- })
-
- def gather_debug(test, status):
- # No screenshots and page source for skipped tests
- if status == "SKIP":
- return
-
- rv = {}
- marionette = test._marionette_weakref()
-
- # In the event we're gathering debug without starting a session,
- # skip marionette commands
- if marionette.session is not None:
- try:
- with marionette.using_context(marionette.CONTEXT_CHROME):
- rv['screenshot'] = marionette.screenshot()
- with marionette.using_context(marionette.CONTEXT_CONTENT):
- rv['source'] = marionette.page_source
- except Exception as exc:
- self.logger.warning('Failed to gather test failure debug: {}'.format(exc))
- return rv
-
- self.result_callbacks.append(gather_debug)
-
- # testvars are set up in self.testvars property
- self._testvars = None
- self.testvars_paths = testvars
-
- self.test_handlers = []
-
- self.reset_test_stats()
-
- self.logger.info('Using workspace for temporary data: '
- '"{}"'.format(self.workspace_path))
-
- if not gecko_log:
- self.gecko_log = os.path.join(self.workspace_path or '', 'gecko.log')
- else:
- self.gecko_log = gecko_log
-
- self.results = []
-
- @property
- def filename_pattern(self):
- if self._filename_pattern is None:
- self._filename_pattern = re.compile(
- "^test(((_.+?)+?\.((py)|(js)))|(([A-Z].*?)+?\.js))$")
-
- return self._filename_pattern
-
- @property
- def testvars(self):
- if self._testvars is not None:
- return self._testvars
-
- self._testvars = {}
-
- def update(d, u):
- """Update a dictionary that may contain nested dictionaries."""
- for k, v in u.iteritems():
- o = d.get(k, {})
- if isinstance(v, dict) and isinstance(o, dict):
- d[k] = update(d.get(k, {}), v)
- else:
- d[k] = u[k]
- return d
-
- json_testvars = self._load_testvars()
- for j in json_testvars:
- self._testvars = update(self._testvars, j)
- return self._testvars
-
- def _load_testvars(self):
- data = []
- if self.testvars_paths is not None:
- for path in list(self.testvars_paths):
- path = os.path.abspath(os.path.expanduser(path))
- if not os.path.exists(path):
- raise IOError('--testvars file {} does not exist'.format(path))
- try:
- with open(path) as f:
- data.append(json.loads(f.read()))
- except ValueError as e:
- exc, val, tb = sys.exc_info()
- msg = "JSON file ({0}) is not properly formatted: {1}"
- raise exc, msg.format(os.path.abspath(path), e.message), tb
- return data
-
- @property
- def capabilities(self):
- if self._capabilities:
- return self._capabilities
-
- self.marionette.start_session()
- self._capabilities = self.marionette.session_capabilities
- self.marionette.delete_session()
- return self._capabilities
-
- @property
- def appinfo(self):
- if self._appinfo:
- return self._appinfo
-
- self.marionette.start_session()
- with self.marionette.using_context('chrome'):
- self._appinfo = self.marionette.execute_script("""
- try {
- return Services.appinfo;
- } catch (e) {
- return null;
- }""")
- self.marionette.delete_session()
- self._appinfo = self._appinfo or {}
- return self._appinfo
-
- @property
- def appName(self):
- if self._appName:
- return self._appName
-
- self._appName = self.capabilities.get('browserName')
- return self._appName
-
- @property
- def bin(self):
- return self._bin
-
- @bin.setter
- def bin(self, path):
- """Set binary and reset parts of runner accordingly.
- Intended use: to change binary between calls to run_tests
- """
- self._bin = path
- self.tests = []
- self.cleanup()
-
- @property
- def version_info(self):
- if not self._version_info:
- try:
- # TODO: Get version_info in Fennec case
- self._version_info = mozversion.get_version(binary=self.bin)
- except Exception:
- self.logger.warning("Failed to retrieve version information for {}".format(
- self.bin))
- return self._version_info
-
- def reset_test_stats(self):
- self.passed = 0
- self.failed = 0
- self.crashed = 0
- self.unexpected_successes = 0
- self.todo = 0
- self.skipped = 0
- self.failures = []
-
- def _build_kwargs(self):
- if self.logdir and not os.access(self.logdir, os.F_OK):
- os.mkdir(self.logdir)
-
- kwargs = {
- 'socket_timeout': self.socket_timeout,
- 'prefs': self.prefs,
- 'startup_timeout': self.startup_timeout,
- 'verbose': self.verbose,
- 'symbols_path': self.symbols_path,
- }
- if self.bin or self.emulator:
- kwargs.update({
- 'host': 'localhost',
- 'port': 2828,
- 'app': self.app,
- 'app_args': self.app_args,
- 'profile': self.profile,
- 'addons': self.addons,
- 'gecko_log': self.gecko_log,
- # ensure Marionette class takes care of starting gecko instance
- 'bin': True,
- })
-
- if self.bin:
- kwargs.update({
- 'bin': self.bin,
- })
-
- if self.emulator:
- kwargs.update({
- 'avd_home': self.extra_kwargs.get('avd_home'),
- 'adb_path': self.extra_kwargs.get('adb_path'),
- 'emulator_binary': self.extra_kwargs.get('emulator_bin'),
- 'avd': self.extra_kwargs.get('avd'),
- 'package_name': self.extra_kwargs.get('package_name'),
- })
-
- if self.address:
- host, port = self.address.split(':')
- kwargs.update({
- 'host': host,
- 'port': int(port),
- })
- if self.emulator:
- kwargs.update({
- 'connect_to_running_emulator': True,
- })
- if not self.bin and not self.emulator:
- try:
- # Establish a socket connection so we can vertify the data come back
- connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- connection.connect((host, int(port)))
- connection.close()
- except Exception as e:
- exc, val, tb = sys.exc_info()
- msg = "Connection attempt to {0}:{1} failed with error: {2}"
- raise exc, msg.format(host, port, e), tb
- if self.workspace:
- kwargs['workspace'] = self.workspace_path
- return kwargs
-
- def record_crash(self):
- crash = True
- try:
- crash = self.marionette.check_for_crash()
- self.crashed += int(crash)
- except Exception:
- traceback.print_exc()
- return crash
-
- def _initialize_test_run(self, tests):
- assert len(tests) > 0
- assert len(self.test_handlers) > 0
- self.reset_test_stats()
-
- def _add_tests(self, tests):
- for test in tests:
- self.add_test(test)
-
- invalid_tests = [t['filepath'] for t in self.tests
- if not self._is_filename_valid(t['filepath'])]
- if invalid_tests:
- raise Exception("Test file names must be of the form "
- "'test_something.py', 'test_something.js', or 'testSomething.js'."
- " Invalid test names:\n {}".format('\n '.join(invalid_tests)))
-
- def _is_filename_valid(self, filename):
- filename = os.path.basename(filename)
- return self.filename_pattern.match(filename)
-
- def _log_skipped_tests(self):
- for test in self.manifest_skipped_tests:
- name = os.path.basename(test['path'])
- self.logger.test_start(name)
- self.logger.test_end(name,
- 'SKIP',
- message=test['disabled'])
- self.todo += 1
-
- def run_tests(self, tests):
- start_time = time.time()
- self._initialize_test_run(tests)
-
- if self.marionette is None:
- self.marionette = self.driverclass(**self._build_kwargs())
- self.logger.info("Profile path is %s" % self.marionette.profile_path)
-
- if len(self.fixture_servers) == 0 or \
- any(not server.is_alive for _, server in self.fixture_servers):
- self.logger.info("Starting fixture servers")
- self.fixture_servers = self.start_fixture_servers()
- for url in iter_url(self.fixture_servers):
- self.logger.info("Fixture server listening on %s" % url)
-
- # backwards compatibility
- self.marionette.baseurl = serve.where_is("/")
-
- self._add_tests(tests)
-
- device_info = None
- if self.marionette.instance and self.emulator:
- try:
- device_info = self.marionette.instance.runner.device.dm.getInfo()
- except Exception:
- self.logger.warning('Could not get device info', exc_info=True)
-
- appinfo_e10s = self.appinfo.get('browserTabsRemoteAutostart', False)
- self.logger.info("e10s is {}".format("enabled" if appinfo_e10s else "disabled"))
- if self.e10s != appinfo_e10s:
- message_e10s = ("BaseMarionetteTestRunner configuration (self.e10s) does "
- "not match browser appinfo")
- self.cleanup()
- raise AssertionError(message_e10s)
-
- self.logger.suite_start(self.tests,
- version_info=self.version_info,
- device_info=device_info)
-
- self._log_skipped_tests()
-
- interrupted = None
- try:
- counter = self.repeat
- while counter >= 0:
- round_num = self.repeat - counter
- if round_num > 0:
- self.logger.info('\nREPEAT {}\n-------'.format(round_num))
- self.run_test_sets()
- counter -= 1
- except KeyboardInterrupt:
- # in case of KeyboardInterrupt during the test execution
- # we want to display current test results.
- # so we keep the exception to raise it later.
- interrupted = sys.exc_info()
- except:
- # For any other exception we return immediately and have to
- # cleanup running processes
- self.cleanup()
- raise
-
- try:
- self._print_summary(tests)
- self.record_crash()
- self.elapsedtime = time.time() - start_time
-
- for run_tests in self.mixin_run_tests:
- run_tests(tests)
- if self.shuffle:
- self.logger.info("Using shuffle seed: %d" % self.shuffle_seed)
-
- self.logger.suite_end()
- except:
- # raise only the exception if we were not interrupted
- if not interrupted:
- raise
- finally:
- self.cleanup()
-
- # reraise previous interruption now
- if interrupted:
- raise interrupted[0], interrupted[1], interrupted[2]
-
- def _print_summary(self, tests):
- self.logger.info('\nSUMMARY\n-------')
- self.logger.info('passed: {}'.format(self.passed))
- if self.unexpected_successes == 0:
- self.logger.info('failed: {}'.format(self.failed))
- else:
- self.logger.info(
- 'failed: {0} (unexpected sucesses: {1})'.format(self.failed,
- self.unexpected_successes))
- if self.skipped == 0:
- self.logger.info('todo: {}'.format(self.todo))
- else:
- self.logger.info('todo: {0} (skipped: {1})'.format(self.todo, self.skipped))
-
- if self.failed > 0:
- self.logger.info('\nFAILED TESTS\n-------')
- for failed_test in self.failures:
- self.logger.info('{}'.format(failed_test[0]))
-
- def start_fixture_servers(self):
- root = self.server_root or os.path.join(os.path.dirname(here), "www")
- if self.appName == "fennec":
- return serve.start(root, host=moznetwork.get_ip())
- else:
- return serve.start(root)
-
- def add_test(self, test, expected='pass'):
- filepath = os.path.abspath(test)
-
- if os.path.isdir(filepath):
- for root, dirs, files in os.walk(filepath):
- for filename in files:
- if filename.endswith('.ini'):
- msg_tmpl = ("Ignoring manifest '{0}'; running all tests in '{1}'."
- " See --help for details.")
- relpath = os.path.relpath(os.path.join(root, filename), filepath)
- self.logger.warning(msg_tmpl.format(relpath, filepath))
- elif self._is_filename_valid(filename):
- test_file = os.path.join(root, filename)
- self.add_test(test_file)
- return
-
- file_ext = os.path.splitext(os.path.split(filepath)[-1])[1]
-
- if file_ext == '.ini':
- manifest = TestManifest()
- manifest.read(filepath)
-
- json_path = update_mozinfo(filepath)
- self.logger.info("mozinfo updated from: {}".format(json_path))
- self.logger.info("mozinfo is: {}".format(mozinfo.info))
-
- filters = []
- if self.test_tags:
- filters.append(tags(self.test_tags))
-
- values = {
- "appname": self.appName,
- "e10s": self.e10s,
- "manage_instance": self.marionette.instance is not None,
- }
- values.update(mozinfo.info)
-
- manifest_tests = manifest.active_tests(exists=False,
- disabled=True,
- filters=filters,
- **values)
- if len(manifest_tests) == 0:
- self.logger.error("No tests to run using specified "
- "combination of filters: {}".format(
- manifest.fmt_filters()))
-
- target_tests = []
- for test in manifest_tests:
- if test.get('disabled'):
- self.manifest_skipped_tests.append(test)
- else:
- target_tests.append(test)
-
- for i in target_tests:
- if not os.path.exists(i["path"]):
- raise IOError("test file: {} does not exist".format(i["path"]))
-
- file_ext = os.path.splitext(os.path.split(i['path'])[-1])[-1]
-
- self.add_test(i["path"], i["expected"])
- return
-
- self.tests.append({'filepath': filepath, 'expected': expected})
-
- def run_test(self, filepath, expected):
- testloader = unittest.TestLoader()
- suite = unittest.TestSuite()
- self.test_kwargs['expected'] = expected
- mod_name = os.path.splitext(os.path.split(filepath)[-1])[0]
- for handler in self.test_handlers:
- if handler.match(os.path.basename(filepath)):
- handler.add_tests_to_suite(mod_name,
- filepath,
- suite,
- testloader,
- self.marionette,
- self.fixtures,
- self.testvars,
- **self.test_kwargs)
- break
-
- if suite.countTestCases():
- runner = self.textrunnerclass(logger=self.logger,
- marionette=self.marionette,
- capabilities=self.capabilities,
- result_callbacks=self.result_callbacks)
-
- results = runner.run(suite)
- self.results.append(results)
-
- self.failed += len(results.failures) + len(results.errors)
- if hasattr(results, 'skipped'):
- self.skipped += len(results.skipped)
- self.todo += len(results.skipped)
- self.passed += results.passed
- for failure in results.failures + results.errors:
- self.failures.append((results.getInfo(failure), failure.output,
- 'TEST-UNEXPECTED-FAIL'))
- if hasattr(results, 'unexpectedSuccesses'):
- self.failed += len(results.unexpectedSuccesses)
- self.unexpected_successes += len(results.unexpectedSuccesses)
- for failure in results.unexpectedSuccesses:
- self.failures.append((results.getInfo(failure), failure.output,
- 'TEST-UNEXPECTED-PASS'))
- if hasattr(results, 'expectedFailures'):
- self.todo += len(results.expectedFailures)
-
- self.mixin_run_tests = []
- for result in self.results:
- result.result_modifiers = []
-
- def run_test_set(self, tests):
- if self.shuffle:
- random.seed(self.shuffle_seed)
- random.shuffle(tests)
-
- for test in tests:
- self.run_test(test['filepath'], test['expected'])
- if self.record_crash():
- break
-
- def run_test_sets(self):
- if len(self.tests) < 1:
- raise Exception('There are no tests to run.')
- elif self.total_chunks > len(self.tests):
- raise ValueError('Total number of chunks must be between 1 and {}.'
- .format(len(self.tests)))
- if self.total_chunks > 1:
- chunks = [[] for i in range(self.total_chunks)]
- for i, test in enumerate(self.tests):
- target_chunk = i % self.total_chunks
- chunks[target_chunk].append(test)
-
- self.logger.info('Running chunk {0} of {1} ({2} tests selected from a '
- 'total of {3})'.format(self.this_chunk, self.total_chunks,
- len(chunks[self.this_chunk - 1]),
- len(self.tests)))
- self.tests = chunks[self.this_chunk - 1]
-
- self.run_test_set(self.tests)
-
- def cleanup(self):
- for proc in iter_proc(self.fixture_servers):
- proc.stop()
- proc.kill()
- self.fixture_servers = {}
-
- if hasattr(self, 'marionette') and self.marionette:
- if self.marionette.instance is not None:
- self.marionette.instance.close()
- self.marionette.instance = None
-
- self.marionette.cleanup()
- self.marionette = None
-
- __del__ = cleanup
diff --git a/testing/marionette/harness/marionette_harness/runner/httpd.py b/testing/marionette/harness/marionette_harness/runner/httpd.py
deleted file mode 100644
index 2136e2bccb..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/httpd.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env python
-
-# 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/.
-
-"""Specialisation of wptserver.server.WebTestHttpd for testing
-Marionette.
-
-"""
-
-import argparse
-import os
-import select
-import sys
-import time
-import urlparse
-
-from wptserve import server, handlers, routes as default_routes
-
-
-here = os.path.abspath(os.path.dirname(__file__))
-default_doc_root = os.path.join(os.path.dirname(here), "www")
-default_ssl_cert = os.path.join(here, "test.cert")
-default_ssl_key = os.path.join(here, "test.key")
-
-
-@handlers.handler
-def upload_handler(request, response):
- return 200, [], [request.headers.get("Content-Type")] or []
-
-
-@handlers.handler
-def slow_loading_document(request, response):
- time.sleep(5)
- return """<!doctype html>
-<title>ok</title>
-<p>ok"""
-
-
-class NotAliveError(Exception):
- """Occurs when attempting to run a function that requires the HTTPD
- to have been started, and it has not.
-
- """
- pass
-
-
-class FixtureServer(object):
-
- def __init__(self, doc_root, url="http://127.0.0.1:0", use_ssl=False,
- ssl_cert=None, ssl_key=None):
- if not os.path.isdir(doc_root):
- raise ValueError("Server root is not a directory: %s" % doc_root)
-
- url = urlparse.urlparse(url)
- if url.scheme is None:
- raise ValueError("Server scheme not provided")
-
- scheme, host, port = url.scheme, url.hostname, url.port
- if host is None:
- host = "127.0.0.1"
- if port is None:
- port = 0
-
- routes = [("POST", "/file_upload", upload_handler),
- ("GET", "/slow", slow_loading_document)]
- routes.extend(default_routes.routes)
-
- self._httpd = server.WebTestHttpd(host=host,
- port=port,
- bind_hostname=True,
- doc_root=doc_root,
- routes=routes,
- use_ssl=True if scheme == "https" else False,
- certificate=ssl_cert,
- key_file=ssl_key)
-
- def start(self, block=False):
- if self.is_alive:
- return
- self._httpd.start(block=block)
-
- def wait(self):
- if not self.is_alive:
- return
- try:
- select.select([], [], [])
- except KeyboardInterrupt:
- self.stop()
-
- def stop(self):
- if not self.is_alive:
- return
- self._httpd.stop()
-
- def get_url(self, path):
- if not self.is_alive:
- raise NotAliveError()
- return self._httpd.get_url(path)
-
- @property
- def doc_root(self):
- return self._httpd.router.doc_root
-
- @property
- def router(self):
- return self._httpd.router
-
- @property
- def routes(self):
- return self._httpd.router.routes
-
- @property
- def is_alive(self):
- return self._httpd.started
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(
- description="Specialised HTTP server for testing Marionette.")
- parser.add_argument("url", help="""
-service address including scheme, hostname, port, and prefix for document root,
-e.g. \"https://0.0.0.0:0/base/\"""")
- parser.add_argument(
- "-r", dest="doc_root", default=default_doc_root,
- help="path to document root (default %(default)s)")
- parser.add_argument(
- "-c", dest="ssl_cert", default=default_ssl_cert,
- help="path to SSL certificate (default %(default)s)")
- parser.add_argument(
- "-k", dest="ssl_key", default=default_ssl_key,
- help="path to SSL certificate key (default %(default)s)")
- args = parser.parse_args()
-
- httpd = FixtureServer(args.doc_root, args.url,
- ssl_cert=args.ssl_cert,
- ssl_key=args.ssl_key)
- httpd.start()
- print >>sys.stderr, "%s: started fixture server on %s" % \
- (sys.argv[0], httpd.get_url("/"))
- httpd.wait()
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/__init__.py b/testing/marionette/harness/marionette_harness/runner/mixins/__init__.py
deleted file mode 100644
index d4abaacb45..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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 .browsermob import (
- BrowserMobProxyTestCaseMixin,
- BrowserMobProxyArguments,
- BrowserMobTestCase,
-)
-
-from .window_manager import (
- WindowManagerMixin,
-)
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/History.md b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/History.md
deleted file mode 100644
index 65c692bfc5..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/History.md
+++ /dev/null
@@ -1,57 +0,0 @@
-
-0.6.0 / 2014-01-21
-==================
-
- * Added support for parameters in har creation
- * Bug fixes for tests that are out of date
- * Setup server constructor to look on path for location of browsermob-proxy executable. As well as looking for a file. Also added example code for using browsermob-proxy with chrome
- * Fix project name
- * adding docs
-
-0.5.0 / 2013-05-23
-==================
-* Allow proxying of ssl requests with selenium.
-* Updating case for proxy type
-
-
-0.4.0 / 2013-03-06
-==================
-
- * Allow setting basic authentication
- * Adding the ability to remap hosts which is available from BrowserMob Proxy Beta 7
- * Merge pull request #6 from lukeis/patch-2
- * Update readme.md
- * initial commit of event listener to auto do record
- * server.create_proxy is a function, should be called :)
- * forgot to add the port
-
-0.2.0 / 2012-06-18
-==================
-
- * pep8 --ignore=E501
- * DELETE /proxy/:port/
- * /proxy/:port/limits
- * /proxy/:port/blacklist
- * /proxy/:port/whitelist
- * fixing /proxy/:port/har/pageRef
- * fixing /proxy/:port/har/pageRef
- * fixing passing in a page ref as the name for the page in /proxy/:port/har
- * tests around /proxy/:port/har and some cleanup of the implementation
- * make /proxy/:port/headers work
- * wrapping selenium_proxy with webdriver_proxy since the project is more than just webdriver
- * extending the client to play nice with remote webdriver instances
- * create_proxy sounds and feels like a method to me, let's make it so
- * ensure the self.process exist, to reduce possibilities of AttributeError
- * check the path before attempting to start the server
- * wait longer than 3 seconds for the server to come up
-
-0.1.0 / 2012-03-22
-==================
-
-* Removed httplib2 in preference for requests
-* Added support for setting headers
-
-0.0.1 / 2012-01-16
-==================
-
-* Initial version
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/__init__.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/__init__.py
deleted file mode 100644
index 5c6d63004f..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-__version__ = '0.5.0'
-
-from .server import Server
-from .client import Client
-
-__all__ = ['Server', 'Client', 'browsermobproxy']
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/client.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/client.py
deleted file mode 100644
index 00b98ca5ee..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/client.py
+++ /dev/null
@@ -1,326 +0,0 @@
-import requests
-
-try:
- from urllib.parse import urlencode, unquote
-except ImportError:
- from urllib import urlencode, unquote
-import json
-
-
-class Client(object):
- def __init__(self, url, params={}):
- """
- Initialises a new Client object
-
-
- :param url: This is where the BrowserMob Proxy lives
- :param params: URL query (for example httpProxy and httpsProxy vars)
- """
- self.host = "http://" + url
- if params:
- urlparams = "?" + unquote(urlencode(params))
- else:
- urlparams = ""
- resp = requests.post('{}/proxy'.format(self.host + urlparams))
- jcontent = json.loads(resp.content.decode('utf-8'))
- self.port = jcontent['port']
- url_parts = self.host.split(":")
- self.proxy = url_parts[1][2:] + ":" + str(self.port)
-
- def close(self):
- """
- shuts down the proxy and closes the port
- """
- r = requests.delete('{0}/proxy/{1}'.format(self.host, self.port))
- return r.status_code
-
- # webdriver integration
- # ...as a proxy object
- def selenium_proxy(self):
- """
- Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy
- """
- from selenium import webdriver
- return webdriver.Proxy({
- "httpProxy": self.proxy,
- "sslProxy": self.proxy,
- })
-
- def webdriver_proxy(self):
- """
- Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy
- """
- return self.selenium_proxy()
-
- # ...as a capability
- def add_to_capabilities(self, capabilities):
- """
- Adds an 'proxy' entry to a desired capabilities dictionary with the
- BrowserMob proxy information
-
-
- :param capabilities: The Desired capabilities object from Selenium WebDriver
- """
- capabilities['proxy'] = {
- 'proxyType': "MANUAL",
- 'httpProxy': self.proxy,
- 'sslProxy': self.proxy
- }
-
- def add_to_webdriver_capabilities(self, capabilities):
- self.add_to_capabilities(capabilities)
-
- # browsermob proxy api
- @property
- def har(self):
- """
- Gets the HAR that has been recorded
- """
- r = requests.get('{0}/proxy/{1}/har'.format(self.host, self.port))
-
- return r.json()
-
- def new_har(self, ref=None, options={}):
- """
- This sets a new HAR to be recorded
-
-
- :param ref: A reference for the HAR. Defaults to None
- :param options: A dictionary that will be passed to BrowserMob Proxy \
- with specific keywords. Keywords are: \
- captureHeaders - Boolean, capture headers \
- captureContent - Boolean, capture content bodies \
- captureBinaryContent - Boolean, capture binary content
- """
- if ref:
- payload = {"initialPageRef": ref}
- else:
- payload = {}
- if options:
- payload.update(options)
-
- r = requests.put('{0}/proxy/{1}/har'.format(self.host, self.port), payload)
- if r.status_code == 200:
- return (r.status_code, r.json())
- else:
- return (r.status_code, None)
-
- def new_page(self, ref=None):
- """
- This sets a new page to be recorded
-
-
- :param ref: A reference for the new page. Defaults to None
- """
- if ref:
- payload = {"pageRef": ref}
- else:
- payload = {}
- r = requests.put('{0}/proxy/{1}/har/pageRef'.format(self.host, self.port),
- payload)
- return r.status_code
-
- def blacklist(self, regexp, status_code):
- """
- Sets a list of URL patterns to blacklist
-
-
- :param regex: a comma separated list of regular expressions
- :param status_code: the HTTP status code to return for URLs that do not \
- match the blacklist
-
- """
- r = requests.put('{0}/proxy/{1}/blacklist'.format(self.host, self.port),
- {'regex': regexp, 'status': status_code})
- return r.status_code
-
- def whitelist(self, regexp, status_code):
- """
- Sets a list of URL patterns to whitelist
-
-
- :param regex: a comma separated list of regular expressions
- :param status_code: the HTTP status code to return for URLs that do not \
- match the whitelist
- """
- r = requests.put('{0}/proxy/{1}/whitelist'.format(self.host, self.port),
- {'regex': regexp, 'status': status_code})
- return r.status_code
-
- def basic_authentication(self, domain, username, password):
- """
- This add automatic basic authentication
-
-
- :param domain: domain to set authentication credentials for
- :param username: valid username to use when authenticating
- :param password: valid password to use when authenticating
- """
- r = requests.post(url='{0}/proxy/{1}/auth/basic/{2}'.format(self.host, self.port, domain),
- data=json.dumps({'username': username, 'password': password}),
- headers={'content-type': 'application/json'})
- return r.status_code
-
- def headers(self, headers):
- """
- This sets the headers that will set by the proxy on all requests
-
-
- :param headers: this is a dictionary of the headers to be set
- """
- if not isinstance(headers, dict):
- raise TypeError("headers needs to be dictionary")
-
- r = requests.post(url='{0}/proxy/{1}/headers'.format(self.host, self.port),
- data=json.dumps(headers),
- headers={'content-type': 'application/json'})
- return r.status_code
-
- def response_interceptor(self, js):
- """
- Executes the javascript against each response
-
-
- :param js: the javascript to execute
- """
- r = requests.post(url='{0}/proxy/{1}/interceptor/response'.format(self.host, self.port),
- data=js,
- headers={'content-type': 'x-www-form-urlencoded'})
- return r.status_code
-
- def request_interceptor(self, js):
- """
- Executes the javascript against each request
-
-
- :param js: the javascript to execute
- """
- r = requests.post(url='{0}/proxy/{1}/interceptor/request'.format(self.host, self.port),
- data=js,
- headers={'content-type': 'x-www-form-urlencoded'})
- return r.status_code
-
- LIMITS = {
- 'upstream_kbps': 'upstreamKbps',
- 'downstream_kbps': 'downstreamKbps',
- 'latency': 'latency'
- }
-
- def limits(self, options):
- """
- Limit the bandwidth through the proxy.
-
-
- :param options: A dictionary with all the details you want to set. \
- downstreamKbps - Sets the downstream kbps \
- upstreamKbps - Sets the upstream kbps \
- latency - Add the given latency to each HTTP request
- """
- params = {}
-
- for (k, v) in list(options.items()):
- if k not in self.LIMITS:
- raise KeyError('invalid key: {}'.format(k))
-
- params[self.LIMITS[k]] = int(v)
-
- if len(list(params.items())) == 0:
- raise KeyError("You need to specify one of the valid Keys")
-
- r = requests.put('{0}/proxy/{1}/limit'.format(self.host, self.port),
- params)
- return r.status_code
-
- TIMEOUTS = {
- 'request': 'requestTimeout',
- 'read': 'readTimeout',
- 'connection': 'connectionTimeout',
- 'dns': 'dnsCacheTimeout'
- }
-
- def timeouts(self, options):
- """
- Configure various timeouts in the proxy
-
-
- :param options: A dictionary with all the details you want to set. \
- request - request timeout (in seconds) \
- read - read timeout (in seconds) \
- connection - connection timeout (in seconds) \
- dns - dns lookup timeout (in seconds)
- """
- params = {}
-
- for (k, v) in list(options.items()):
- if k not in self.TIMEOUTS:
- raise KeyError('invalid key: {}'.format(k))
-
- params[self.TIMEOUTS[k]] = int(v)
-
- if len(list(params.items())) == 0:
- raise KeyError("You need to specify one of the valid Keys")
-
- r = requests.put('{0}/proxy/{1}/timeout'.format(self.host, self.port),
- params)
- return r.status_code
-
- def remap_hosts(self, address, ip_address):
- """
- Remap the hosts for a specific URL
-
-
- :param address: url that you wish to remap
- :param ip_address: IP Address that will handle all traffic for the address passed in
- """
- assert address is not None and ip_address is not None
- r = requests.post('{0}/proxy/{1}/hosts'.format(self.host, self.port),
- json.dumps({address: ip_address}),
- headers={'content-type': 'application/json'})
- return r.status_code
-
- def wait_for_traffic_to_stop(self, quiet_period, timeout):
- """
- Waits for the network to be quiet
-
-
- :param quiet_period: number of miliseconds the network needs to be quiet for
- :param timeout: max number of miliseconds to wait
- """
- r = requests.put('{0}/proxy/{1}/wait'.format(self.host, self.port),
- {'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout})
- return r.status_code
-
- def clear_dns_cache(self):
- """
- Clears the DNS cache associated with the proxy instance
- """
- r = requests.delete('{0}/proxy/{1}/dns/cache'.format(self.host, self.port))
- return r.status_code
-
- def rewrite_url(self, match, replace):
- """
- Rewrites the requested url.
-
-
- :param match: a regex to match requests with
- :param replace: unicode \
- a string to replace the matches with
- """
- params = {
- "matchRegex": match,
- "replace": replace
- }
- r = requests.put('{0}/proxy/{1}/rewrite'.format(self.host, self.port),
- params)
- return r.status_code
-
- def retry(self, retry_count):
- """
- Retries. No idea what its used for, but its in the API...
-
-
- :param retry_count: the number of retries
- """
- r = requests.put('{0}/proxy/{1}/retry'.format(self.host, self.port),
- {'retrycount': retry_count})
- return r.status_code
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/server.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/server.py
deleted file mode 100644
index ff6db4efe3..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/server.py
+++ /dev/null
@@ -1,106 +0,0 @@
-import os
-import platform
-import socket
-import subprocess
-import time
-
-from .client import Client
-
-
-class Server(object):
-
- def __init__(self, path='browsermob-proxy', options={}):
- """
- Initialises a Server object
-
- :param path: Path to the browsermob proxy batch file
- :param options: Dictionary that can hold the port. \
- More items will be added in the future. \
- This defaults to an empty dictionary
- """
- path_var_sep = ':'
- if platform.system() == 'Windows':
- path_var_sep = ';'
- if not path.endswith('.bat'):
- path += '.bat'
-
- exec_not_on_path = True
- for directory in os.environ['PATH'].split(path_var_sep):
- if(os.path.isfile(os.path.join(directory, path))):
- exec_not_on_path = False
- break
-
- if not os.path.isfile(path) and exec_not_on_path:
- raise IOError("Browsermob-Proxy binary couldn't be found in path"
- " provided: {}".format(path))
-
- self.path = path
- self.port = options.get('port', 8080)
- self.process = None
-
- if platform.system() == 'Darwin':
- self.command = ['sh']
- else:
- self.command = []
- self.command += [path, '--port={}'.format(self.port)]
-
- def start(self):
- """
- This will start the browsermob proxy and then wait until it can
- interact with it
- """
- self.log_file = open(os.path.abspath('server.log'), 'w')
- self.process = subprocess.Popen(self.command,
- stdout=self.log_file,
- stderr=subprocess.STDOUT)
- count = 0
- while not self._is_listening():
- time.sleep(0.5)
- count += 1
- if count == 60:
- self.stop()
- raise Exception("Can't connect to Browsermob-Proxy")
-
- def stop(self):
- """
- This will stop the process running the proxy
- """
- if self.process.poll() is not None:
- return
-
- try:
- self.process.kill()
- self.process.wait()
- except AttributeError:
- # kill may not be available under windows environment
- pass
-
- self.log_file.close()
-
- @property
- def url(self):
- """
- Gets the url that the proxy is running on. This is not the URL clients
- should connect to.
- """
- return "http://localhost:{}".format(self.port)
-
- def create_proxy(self, params={}):
- """
- Gets a client class that allow to set all the proxy details that you
- may need to.
- :param params: Dictionary where you can specify params \
- like httpProxy and httpsProxy
- """
- client = Client(self.url[7:], params)
- return client
-
- def _is_listening(self):
- try:
- socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- socket_.settimeout(1)
- socket_.connect(("localhost", self.port))
- socket_.close()
- return True
- except socket.error:
- return False
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/webdriver_event_listener.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/webdriver_event_listener.py
deleted file mode 100644
index 533542b096..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/browsermobproxy/webdriver_event_listener.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from selenium.webdriver.support.abstract_event_listener import AbstractEventListener
-
-class WebDriverEventListener(AbstractEventListener):
-
- def __init__(self, client, refs={}):
- self.client = client
- self.hars = []
- self.refs = refs
-
- def before_navigate_to(self, url, driver):
- if len(self.hars) != 0:
- self.hars.append(self.client.har)
- self.client.new_har("navigate-to-{}".format(url), self.refs)
-
- def before_navigate_back(self, driver=None):
- if driver:
- name = "-from-{}".format(driver.current_url)
- else:
- name = "navigate-back"
- self.client.new_page(name)
-
- def before_navigate_forward(self, driver=None):
- if driver:
- name = "-from-{}".format(driver.current_url)
- else:
- name = "navigate-forward"
- self.client.new_page(name)
-
- def before_click(self, element, driver):
- name = "click-element-{}".format(element.id)
- self.client.new_page(name)
-
- def before_quit(self, driver):
- self.hars.append(self.client.har)
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/Makefile b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/Makefile
deleted file mode 100644
index 554b2a7cfd..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BrowserMobProxy.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BrowserMobProxy.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/BrowserMobProxy"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BrowserMobProxy"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/.buildinfo b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/.buildinfo
deleted file mode 100644
index 9274f43c28..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/.buildinfo
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sphinx build info version 1
-# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 22346719ac3713bfe792fb5638c0a301
-tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/browsermobproxy.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/browsermobproxy.html
deleted file mode 100644
index d3b83c20fb..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/browsermobproxy.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>browsermobproxy &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="../_static/default.css" type="text/css" />
- <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: '../',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="../_static/jquery.js"></script>
- <script type="text/javascript" src="../_static/underscore.js"></script>
- <script type="text/javascript" src="../_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="../index.html" />
- <link rel="up" title="Module code" href="index.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="../index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- <li><a href="index.html" accesskey="U">Module code</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <h1>Source code for browsermobproxy</h1><div class="highlight"><pre>
-<span class="n">__version__</span> <span class="o">=</span> <span class="s">&#39;0.5.0&#39;</span>
-
-<span class="kn">from</span> <span class="nn">server</span> <span class="kn">import</span> <span class="n">Server</span>
-<span class="kn">from</span> <span class="nn">client</span> <span class="kn">import</span> <span class="n">Client</span>
-
-<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;Server&#39;</span><span class="p">,</span> <span class="s">&#39;Client&#39;</span><span class="p">,</span> <span class="s">&#39;browsermobproxy&#39;</span><span class="p">]</span>
-</pre></div>
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="../search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="../index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- <li><a href="index.html" >Module code</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/index.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/index.html
deleted file mode 100644
index 5650bd3634..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_modules/index.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Overview: module code &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="../_static/default.css" type="text/css" />
- <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: '../',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="../_static/jquery.js"></script>
- <script type="text/javascript" src="../_static/underscore.js"></script>
- <script type="text/javascript" src="../_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="../index.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="../index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <h1>All modules for which code is available</h1>
-<ul><li><a href="browsermobproxy.html">browsermobproxy</a></li>
-</ul>
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="../search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="../genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="../py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="../index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/client.txt b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/client.txt
deleted file mode 100644
index 95c74fa9f3..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/client.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-.. toctree::
- :maxdepth: 2
-
-:mod:`client` Package
----------------------
-.. automodule:: browsermobproxy
-.. autoclass:: Client
- :members:
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/index.txt b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/index.txt
deleted file mode 100644
index 0a568cf643..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/index.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-.. BrowserMob Proxy documentation master file, created by
- sphinx-quickstart on Fri May 24 12:37:12 2013.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-.. highlightlang:: python
-
-
-
-Welcome to BrowserMob Proxy's documentation!
-============================================
-
-Python client for the BrowserMob Proxy 2.0 REST API.
-
-How to install
---------------
-
-BrowserMob Proxy is available on PyPI_, so you can install it with ``pip``::
-
- $ pip install browsermob-proxy
-
-Or with `easy_install`::
-
- $ easy_install browsermob-proxy
-
-Or by cloning the repo from GitHub_::
-
- $ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git
-
-Then install it by running::
-
- $ python setup.py install
-
-How to use with selenium-webdriver
-----------------------------------
-
-Manually::
-
- from browsermobproxy import Server
- server = Server("path/to/browsermob-proxy")
- server.start()
- proxy = server.create_proxy()
-
- from selenium import webdriver
- profile = webdriver.FirefoxProfile()
- profile.set_proxy(proxy.selenium_proxy())
- driver = webdriver.Firefox(firefox_profile=profile)
-
-
- proxy.new_har("google")
- driver.get("http://www.google.co.uk")
- proxy.har # returns a HAR JSON blob
-
- server.stop()
- driver.quit()
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- client.rst
- server.rst
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
-.. _GitHub: https://github.com/AutomatedTester/browsermob-proxy-py
-.. _PyPI: http://pypi.python.org/pypi/browsermob-proxy
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/server.txt b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/server.txt
deleted file mode 100644
index 8af94b70a6..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_sources/server.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-.. toctree::
- :maxdepth: 2
-
-:mod:`server` Package
----------------------
-.. automodule:: browsermobproxy
-.. autoclass:: Server
- :members: \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/basic.css b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/basic.css
deleted file mode 100644
index c959cf0db1..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/basic.css
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * basic.css
- * ~~~~~~~~~
- *
- * Sphinx stylesheet -- basic theme.
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-/* -- main layout ----------------------------------------------------------- */
-
-div.clearer {
- clear: both;
-}
-
-/* -- relbar ---------------------------------------------------------------- */
-
-div.related {
- width: 100%;
- font-size: 90%;
-}
-
-div.related h3 {
- display: none;
-}
-
-div.related ul {
- margin: 0;
- padding: 0 0 0 10px;
- list-style: none;
-}
-
-div.related li {
- display: inline;
-}
-
-div.related li.right {
- float: right;
- margin-right: 5px;
-}
-
-/* -- sidebar --------------------------------------------------------------- */
-
-div.sphinxsidebarwrapper {
- padding: 10px 5px 0 10px;
-}
-
-div.sphinxsidebar {
- float: left;
- width: 230px;
- margin-left: -100%;
- font-size: 90%;
-}
-
-div.sphinxsidebar ul {
- list-style: none;
-}
-
-div.sphinxsidebar ul ul,
-div.sphinxsidebar ul.want-points {
- margin-left: 20px;
- list-style: square;
-}
-
-div.sphinxsidebar ul ul {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-div.sphinxsidebar form {
- margin-top: 10px;
-}
-
-div.sphinxsidebar input {
- border: 1px solid #98dbcc;
- font-family: sans-serif;
- font-size: 1em;
-}
-
-div.sphinxsidebar #searchbox input[type="text"] {
- width: 170px;
-}
-
-div.sphinxsidebar #searchbox input[type="submit"] {
- width: 30px;
-}
-
-img {
- border: 0;
- max-width: 100%;
-}
-
-/* -- search page ----------------------------------------------------------- */
-
-ul.search {
- margin: 10px 0 0 20px;
- padding: 0;
-}
-
-ul.search li {
- padding: 5px 0 5px 20px;
- background-image: url(file.png);
- background-repeat: no-repeat;
- background-position: 0 7px;
-}
-
-ul.search li a {
- font-weight: bold;
-}
-
-ul.search li div.context {
- color: #888;
- margin: 2px 0 0 30px;
- text-align: left;
-}
-
-ul.keywordmatches li.goodmatch a {
- font-weight: bold;
-}
-
-/* -- index page ------------------------------------------------------------ */
-
-table.contentstable {
- width: 90%;
-}
-
-table.contentstable p.biglink {
- line-height: 150%;
-}
-
-a.biglink {
- font-size: 1.3em;
-}
-
-span.linkdescr {
- font-style: italic;
- padding-top: 5px;
- font-size: 90%;
-}
-
-/* -- general index --------------------------------------------------------- */
-
-table.indextable {
- width: 100%;
-}
-
-table.indextable td {
- text-align: left;
- vertical-align: top;
-}
-
-table.indextable dl, table.indextable dd {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-table.indextable tr.pcap {
- height: 10px;
-}
-
-table.indextable tr.cap {
- margin-top: 10px;
- background-color: #f2f2f2;
-}
-
-img.toggler {
- margin-right: 3px;
- margin-top: 3px;
- cursor: pointer;
-}
-
-div.modindex-jumpbox {
- border-top: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- margin: 1em 0 1em 0;
- padding: 0.4em;
-}
-
-div.genindex-jumpbox {
- border-top: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- margin: 1em 0 1em 0;
- padding: 0.4em;
-}
-
-/* -- general body styles --------------------------------------------------- */
-
-a.headerlink {
- visibility: hidden;
-}
-
-h1:hover > a.headerlink,
-h2:hover > a.headerlink,
-h3:hover > a.headerlink,
-h4:hover > a.headerlink,
-h5:hover > a.headerlink,
-h6:hover > a.headerlink,
-dt:hover > a.headerlink {
- visibility: visible;
-}
-
-div.body p.caption {
- text-align: inherit;
-}
-
-div.body td {
- text-align: left;
-}
-
-.field-list ul {
- padding-left: 1em;
-}
-
-.first {
- margin-top: 0 !important;
-}
-
-p.rubric {
- margin-top: 30px;
- font-weight: bold;
-}
-
-img.align-left, .figure.align-left, object.align-left {
- clear: left;
- float: left;
- margin-right: 1em;
-}
-
-img.align-right, .figure.align-right, object.align-right {
- clear: right;
- float: right;
- margin-left: 1em;
-}
-
-img.align-center, .figure.align-center, object.align-center {
- display: block;
- margin-left: auto;
- margin-right: auto;
-}
-
-.align-left {
- text-align: left;
-}
-
-.align-center {
- text-align: center;
-}
-
-.align-right {
- text-align: right;
-}
-
-/* -- sidebars -------------------------------------------------------------- */
-
-div.sidebar {
- margin: 0 0 0.5em 1em;
- border: 1px solid #ddb;
- padding: 7px 7px 0 7px;
- background-color: #ffe;
- width: 40%;
- float: right;
-}
-
-p.sidebar-title {
- font-weight: bold;
-}
-
-/* -- topics ---------------------------------------------------------------- */
-
-div.topic {
- border: 1px solid #ccc;
- padding: 7px 7px 0 7px;
- margin: 10px 0 10px 0;
-}
-
-p.topic-title {
- font-size: 1.1em;
- font-weight: bold;
- margin-top: 10px;
-}
-
-/* -- admonitions ----------------------------------------------------------- */
-
-div.admonition {
- margin-top: 10px;
- margin-bottom: 10px;
- padding: 7px;
-}
-
-div.admonition dt {
- font-weight: bold;
-}
-
-div.admonition dl {
- margin-bottom: 0;
-}
-
-p.admonition-title {
- margin: 0px 10px 5px 0px;
- font-weight: bold;
-}
-
-div.body p.centered {
- text-align: center;
- margin-top: 25px;
-}
-
-/* -- tables ---------------------------------------------------------------- */
-
-table.docutils {
- border: 0;
- border-collapse: collapse;
-}
-
-table.docutils td, table.docutils th {
- padding: 1px 8px 1px 5px;
- border-top: 0;
- border-left: 0;
- border-right: 0;
- border-bottom: 1px solid #aaa;
-}
-
-table.field-list td, table.field-list th {
- border: 0 !important;
-}
-
-table.footnote td, table.footnote th {
- border: 0 !important;
-}
-
-th {
- text-align: left;
- padding-right: 5px;
-}
-
-table.citation {
- border-left: solid 1px gray;
- margin-left: 1px;
-}
-
-table.citation td {
- border-bottom: none;
-}
-
-/* -- other body styles ----------------------------------------------------- */
-
-ol.arabic {
- list-style: decimal;
-}
-
-ol.loweralpha {
- list-style: lower-alpha;
-}
-
-ol.upperalpha {
- list-style: upper-alpha;
-}
-
-ol.lowerroman {
- list-style: lower-roman;
-}
-
-ol.upperroman {
- list-style: upper-roman;
-}
-
-dl {
- margin-bottom: 15px;
-}
-
-dd p {
- margin-top: 0px;
-}
-
-dd ul, dd table {
- margin-bottom: 10px;
-}
-
-dd {
- margin-top: 3px;
- margin-bottom: 10px;
- margin-left: 30px;
-}
-
-dt:target, .highlighted {
- background-color: #fbe54e;
-}
-
-dl.glossary dt {
- font-weight: bold;
- font-size: 1.1em;
-}
-
-.field-list ul {
- margin: 0;
- padding-left: 1em;
-}
-
-.field-list p {
- margin: 0;
-}
-
-.optional {
- font-size: 1.3em;
-}
-
-.versionmodified {
- font-style: italic;
-}
-
-.system-message {
- background-color: #fda;
- padding: 5px;
- border: 3px solid red;
-}
-
-.footnote:target {
- background-color: #ffa;
-}
-
-.line-block {
- display: block;
- margin-top: 1em;
- margin-bottom: 1em;
-}
-
-.line-block .line-block {
- margin-top: 0;
- margin-bottom: 0;
- margin-left: 1.5em;
-}
-
-.guilabel, .menuselection {
- font-family: sans-serif;
-}
-
-.accelerator {
- text-decoration: underline;
-}
-
-.classifier {
- font-style: oblique;
-}
-
-abbr, acronym {
- border-bottom: dotted 1px;
- cursor: help;
-}
-
-/* -- code displays --------------------------------------------------------- */
-
-pre {
- overflow: auto;
- overflow-y: hidden; /* fixes display issues on Chrome browsers */
-}
-
-td.linenos pre {
- padding: 5px 0px;
- border: 0;
- background-color: transparent;
- color: #aaa;
-}
-
-table.highlighttable {
- margin-left: 0.5em;
-}
-
-table.highlighttable td {
- padding: 0 0.5em 0 0.5em;
-}
-
-tt.descname {
- background-color: transparent;
- font-weight: bold;
- font-size: 1.2em;
-}
-
-tt.descclassname {
- background-color: transparent;
-}
-
-tt.xref, a tt {
- background-color: transparent;
- font-weight: bold;
-}
-
-h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
- background-color: transparent;
-}
-
-.viewcode-link {
- float: right;
-}
-
-.viewcode-back {
- float: right;
- font-family: sans-serif;
-}
-
-div.viewcode-block:target {
- margin: -1px -10px;
- padding: 0 10px;
-}
-
-/* -- math display ---------------------------------------------------------- */
-
-img.math {
- vertical-align: middle;
-}
-
-div.body div.math p {
- text-align: center;
-}
-
-span.eqno {
- float: right;
-}
-
-/* -- printout stylesheet --------------------------------------------------- */
-
-@media print {
- div.document,
- div.documentwrapper,
- div.bodywrapper {
- margin: 0 !important;
- width: 100%;
- }
-
- div.sphinxsidebar,
- div.related,
- div.footer,
- #top-link {
- display: none;
- }
-} \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/default.css b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/default.css
deleted file mode 100644
index e534a07802..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/default.css
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * default.css_t
- * ~~~~~~~~~~~~~
- *
- * Sphinx stylesheet -- default theme.
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-@import url("basic.css");
-
-/* -- page layout ----------------------------------------------------------- */
-
-body {
- font-family: sans-serif;
- font-size: 100%;
- background-color: #11303d;
- color: #000;
- margin: 0;
- padding: 0;
-}
-
-div.document {
- background-color: #1c4e63;
-}
-
-div.documentwrapper {
- float: left;
- width: 100%;
-}
-
-div.bodywrapper {
- margin: 0 0 0 230px;
-}
-
-div.body {
- background-color: #ffffff;
- color: #000000;
- padding: 0 20px 30px 20px;
-}
-
-div.footer {
- color: #ffffff;
- width: 100%;
- padding: 9px 0 9px 0;
- text-align: center;
- font-size: 75%;
-}
-
-div.footer a {
- color: #ffffff;
- text-decoration: underline;
-}
-
-div.related {
- background-color: #133f52;
- line-height: 30px;
- color: #ffffff;
-}
-
-div.related a {
- color: #ffffff;
-}
-
-div.sphinxsidebar {
-}
-
-div.sphinxsidebar h3 {
- font-family: 'Trebuchet MS', sans-serif;
- color: #ffffff;
- font-size: 1.4em;
- font-weight: normal;
- margin: 0;
- padding: 0;
-}
-
-div.sphinxsidebar h3 a {
- color: #ffffff;
-}
-
-div.sphinxsidebar h4 {
- font-family: 'Trebuchet MS', sans-serif;
- color: #ffffff;
- font-size: 1.3em;
- font-weight: normal;
- margin: 5px 0 0 0;
- padding: 0;
-}
-
-div.sphinxsidebar p {
- color: #ffffff;
-}
-
-div.sphinxsidebar p.topless {
- margin: 5px 10px 10px 10px;
-}
-
-div.sphinxsidebar ul {
- margin: 10px;
- padding: 0;
- color: #ffffff;
-}
-
-div.sphinxsidebar a {
- color: #98dbcc;
-}
-
-div.sphinxsidebar input {
- border: 1px solid #98dbcc;
- font-family: sans-serif;
- font-size: 1em;
-}
-
-
-
-/* -- hyperlink styles ------------------------------------------------------ */
-
-a {
- color: #355f7c;
- text-decoration: none;
-}
-
-a:visited {
- color: #355f7c;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-
-
-/* -- body styles ----------------------------------------------------------- */
-
-div.body h1,
-div.body h2,
-div.body h3,
-div.body h4,
-div.body h5,
-div.body h6 {
- font-family: 'Trebuchet MS', sans-serif;
- background-color: #f2f2f2;
- font-weight: normal;
- color: #20435c;
- border-bottom: 1px solid #ccc;
- margin: 20px -20px 10px -20px;
- padding: 3px 0 3px 10px;
-}
-
-div.body h1 { margin-top: 0; font-size: 200%; }
-div.body h2 { font-size: 160%; }
-div.body h3 { font-size: 140%; }
-div.body h4 { font-size: 120%; }
-div.body h5 { font-size: 110%; }
-div.body h6 { font-size: 100%; }
-
-a.headerlink {
- color: #c60f0f;
- font-size: 0.8em;
- padding: 0 4px 0 4px;
- text-decoration: none;
-}
-
-a.headerlink:hover {
- background-color: #c60f0f;
- color: white;
-}
-
-div.body p, div.body dd, div.body li {
- text-align: justify;
- line-height: 130%;
-}
-
-div.admonition p.admonition-title + p {
- display: inline;
-}
-
-div.admonition p {
- margin-bottom: 5px;
-}
-
-div.admonition pre {
- margin-bottom: 5px;
-}
-
-div.admonition ul, div.admonition ol {
- margin-bottom: 5px;
-}
-
-div.note {
- background-color: #eee;
- border: 1px solid #ccc;
-}
-
-div.seealso {
- background-color: #ffc;
- border: 1px solid #ff6;
-}
-
-div.topic {
- background-color: #eee;
-}
-
-div.warning {
- background-color: #ffe4e4;
- border: 1px solid #f66;
-}
-
-p.admonition-title {
- display: inline;
-}
-
-p.admonition-title:after {
- content: ":";
-}
-
-pre {
- padding: 5px;
- background-color: #eeffcc;
- color: #333333;
- line-height: 120%;
- border: 1px solid #ac9;
- border-left: none;
- border-right: none;
-}
-
-tt {
- background-color: #ecf0f3;
- padding: 0 1px 0 1px;
- font-size: 0.95em;
-}
-
-th {
- background-color: #ede;
-}
-
-.warning tt {
- background: #efc2c2;
-}
-
-.note tt {
- background: #d6d6d6;
-}
-
-.viewcode-back {
- font-family: sans-serif;
-}
-
-div.viewcode-block:target {
- background-color: #f4debf;
- border-top: 1px solid #ac9;
- border-bottom: 1px solid #ac9;
-} \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/doctools.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/doctools.js
deleted file mode 100644
index 2036e5f5f8..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/doctools.js
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * doctools.js
- * ~~~~~~~~~~~
- *
- * Sphinx JavaScript utilities for all documentation.
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-/**
- * select a different prefix for underscore
- */
-$u = _.noConflict();
-
-/**
- * make the code below compatible with browsers without
- * an installed firebug like debugger
-if (!window.console || !console.firebug) {
- var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
- "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
- "profile", "profileEnd"];
- window.console = {};
- for (var i = 0; i < names.length; ++i)
- window.console[names[i]] = function() {};
-}
- */
-
-/**
- * small helper function to urldecode strings
- */
-jQuery.urldecode = function(x) {
- return decodeURIComponent(x).replace(/\+/g, ' ');
-};
-
-/**
- * small helper function to urlencode strings
- */
-jQuery.urlencode = encodeURIComponent;
-
-/**
- * This function returns the parsed url parameters of the
- * current request. Multiple values per key are supported,
- * it will always return arrays of strings for the value parts.
- */
-jQuery.getQueryParameters = function(s) {
- if (typeof s == 'undefined')
- s = document.location.search;
- var parts = s.substr(s.indexOf('?') + 1).split('&');
- var result = {};
- for (var i = 0; i < parts.length; i++) {
- var tmp = parts[i].split('=', 2);
- var key = jQuery.urldecode(tmp[0]);
- var value = jQuery.urldecode(tmp[1]);
- if (key in result)
- result[key].push(value);
- else
- result[key] = [value];
- }
- return result;
-};
-
-/**
- * highlight a given string on a jquery object by wrapping it in
- * span elements with the given class name.
- */
-jQuery.fn.highlightText = function(text, className) {
- function highlight(node) {
- if (node.nodeType == 3) {
- var val = node.nodeValue;
- var pos = val.toLowerCase().indexOf(text);
- if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
- var span = document.createElement("span");
- span.className = className;
- span.appendChild(document.createTextNode(val.substr(pos, text.length)));
- node.parentNode.insertBefore(span, node.parentNode.insertBefore(
- document.createTextNode(val.substr(pos + text.length)),
- node.nextSibling));
- node.nodeValue = val.substr(0, pos);
- }
- }
- else if (!jQuery(node).is("button, select, textarea")) {
- jQuery.each(node.childNodes, function() {
- highlight(this);
- });
- }
- }
- return this.each(function() {
- highlight(this);
- });
-};
-
-/**
- * Small JavaScript module for the documentation.
- */
-var Documentation = {
-
- init : function() {
- this.fixFirefoxAnchorBug();
- this.highlightSearchWords();
- this.initIndexTable();
- },
-
- /**
- * i18n support
- */
- TRANSLATIONS : {},
- PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
- LOCALE : 'unknown',
-
- // gettext and ngettext don't access this so that the functions
- // can safely bound to a different name (_ = Documentation.gettext)
- gettext : function(string) {
- var translated = Documentation.TRANSLATIONS[string];
- if (typeof translated == 'undefined')
- return string;
- return (typeof translated == 'string') ? translated : translated[0];
- },
-
- ngettext : function(singular, plural, n) {
- var translated = Documentation.TRANSLATIONS[singular];
- if (typeof translated == 'undefined')
- return (n == 1) ? singular : plural;
- return translated[Documentation.PLURALEXPR(n)];
- },
-
- addTranslations : function(catalog) {
- for (var key in catalog.messages)
- this.TRANSLATIONS[key] = catalog.messages[key];
- this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
- this.LOCALE = catalog.locale;
- },
-
- /**
- * add context elements like header anchor links
- */
- addContextElements : function() {
- $('div[id] > :header:first').each(function() {
- $('<a class="headerlink">\u00B6</a>').
- attr('href', '#' + this.id).
- attr('title', _('Permalink to this headline')).
- appendTo(this);
- });
- $('dt[id]').each(function() {
- $('<a class="headerlink">\u00B6</a>').
- attr('href', '#' + this.id).
- attr('title', _('Permalink to this definition')).
- appendTo(this);
- });
- },
-
- /**
- * workaround a firefox stupidity
- */
- fixFirefoxAnchorBug : function() {
- if (document.location.hash && $.browser.mozilla)
- window.setTimeout(function() {
- document.location.href += '';
- }, 10);
- },
-
- /**
- * highlight the search words provided in the url in the text
- */
- highlightSearchWords : function() {
- var params = $.getQueryParameters();
- var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
- if (terms.length) {
- var body = $('div.body');
- if (!body.length) {
- body = $('body');
- }
- window.setTimeout(function() {
- $.each(terms, function() {
- body.highlightText(this.toLowerCase(), 'highlighted');
- });
- }, 10);
- $('<p class="highlight-link"><a href="javascript:Documentation.' +
- 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
- .appendTo($('#searchbox'));
- }
- },
-
- /**
- * init the domain index toggle buttons
- */
- initIndexTable : function() {
- var togglers = $('img.toggler').click(function() {
- var src = $(this).attr('src');
- var idnum = $(this).attr('id').substr(7);
- $('tr.cg-' + idnum).toggle();
- if (src.substr(-9) == 'minus.png')
- $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
- else
- $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
- }).css('display', '');
- if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
- togglers.click();
- }
- },
-
- /**
- * helper function to hide the search marks again
- */
- hideSearchWords : function() {
- $('#searchbox .highlight-link').fadeOut(300);
- $('span.highlighted').removeClass('highlighted');
- },
-
- /**
- * make the url absolute
- */
- makeURL : function(relativeURL) {
- return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
- },
-
- /**
- * get the current relative url
- */
- getCurrentURL : function() {
- var path = document.location.pathname;
- var parts = path.split(/\//);
- $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
- if (this == '..')
- parts.pop();
- });
- var url = parts.join('/');
- return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
- }
-};
-
-// quick alias for translations
-_ = Documentation.gettext;
-
-$(document).ready(function() {
- Documentation.init();
-});
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/jquery.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/jquery.js
deleted file mode 100644
index 3883779527..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/jquery.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery v1.8.3 jquery.com | jquery.org/license */
-(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/pygments.css b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/pygments.css
deleted file mode 100644
index d79caa151c..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/pygments.css
+++ /dev/null
@@ -1,62 +0,0 @@
-.highlight .hll { background-color: #ffffcc }
-.highlight { background: #eeffcc; }
-.highlight .c { color: #408090; font-style: italic } /* Comment */
-.highlight .err { border: 1px solid #FF0000 } /* Error */
-.highlight .k { color: #007020; font-weight: bold } /* Keyword */
-.highlight .o { color: #666666 } /* Operator */
-.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #007020 } /* Comment.Preproc */
-.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
-.highlight .gd { color: #A00000 } /* Generic.Deleted */
-.highlight .ge { font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #FF0000 } /* Generic.Error */
-.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #333333 } /* Generic.Output */
-.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0044DD } /* Generic.Traceback */
-.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
-.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
-.highlight .kp { color: #007020 } /* Keyword.Pseudo */
-.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #902000 } /* Keyword.Type */
-.highlight .m { color: #208050 } /* Literal.Number */
-.highlight .s { color: #4070a0 } /* Literal.String */
-.highlight .na { color: #4070a0 } /* Name.Attribute */
-.highlight .nb { color: #007020 } /* Name.Builtin */
-.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
-.highlight .no { color: #60add5 } /* Name.Constant */
-.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
-.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
-.highlight .ne { color: #007020 } /* Name.Exception */
-.highlight .nf { color: #06287e } /* Name.Function */
-.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
-.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
-.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
-.highlight .nv { color: #bb60d5 } /* Name.Variable */
-.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mf { color: #208050 } /* Literal.Number.Float */
-.highlight .mh { color: #208050 } /* Literal.Number.Hex */
-.highlight .mi { color: #208050 } /* Literal.Number.Integer */
-.highlight .mo { color: #208050 } /* Literal.Number.Oct */
-.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
-.highlight .sc { color: #4070a0 } /* Literal.String.Char */
-.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
-.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
-.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
-.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
-.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
-.highlight .sx { color: #c65d09 } /* Literal.String.Other */
-.highlight .sr { color: #235388 } /* Literal.String.Regex */
-.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
-.highlight .ss { color: #517918 } /* Literal.String.Symbol */
-.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
-.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
-.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
-.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
-.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/searchtools.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/searchtools.js
deleted file mode 100644
index f5c7e5fee7..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/searchtools.js
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * searchtools.js_t
- * ~~~~~~~~~~~~~~~~
- *
- * Sphinx JavaScript utilties for the full-text search.
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-
-/**
- * Porter Stemmer
- */
-var Stemmer = function() {
-
- var step2list = {
- ational: 'ate',
- tional: 'tion',
- enci: 'ence',
- anci: 'ance',
- izer: 'ize',
- bli: 'ble',
- alli: 'al',
- entli: 'ent',
- eli: 'e',
- ousli: 'ous',
- ization: 'ize',
- ation: 'ate',
- ator: 'ate',
- alism: 'al',
- iveness: 'ive',
- fulness: 'ful',
- ousness: 'ous',
- aliti: 'al',
- iviti: 'ive',
- biliti: 'ble',
- logi: 'log'
- };
-
- var step3list = {
- icate: 'ic',
- ative: '',
- alize: 'al',
- iciti: 'ic',
- ical: 'ic',
- ful: '',
- ness: ''
- };
-
- var c = "[^aeiou]"; // consonant
- var v = "[aeiouy]"; // vowel
- var C = c + "[^aeiouy]*"; // consonant sequence
- var V = v + "[aeiou]*"; // vowel sequence
-
- var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
- var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
- var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
- var s_v = "^(" + C + ")?" + v; // vowel in stem
-
- this.stemWord = function (w) {
- var stem;
- var suffix;
- var firstch;
- var origword = w;
-
- if (w.length < 3)
- return w;
-
- var re;
- var re2;
- var re3;
- var re4;
-
- firstch = w.substr(0,1);
- if (firstch == "y")
- w = firstch.toUpperCase() + w.substr(1);
-
- // Step 1a
- re = /^(.+?)(ss|i)es$/;
- re2 = /^(.+?)([^s])s$/;
-
- if (re.test(w))
- w = w.replace(re,"$1$2");
- else if (re2.test(w))
- w = w.replace(re2,"$1$2");
-
- // Step 1b
- re = /^(.+?)eed$/;
- re2 = /^(.+?)(ed|ing)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- re = new RegExp(mgr0);
- if (re.test(fp[1])) {
- re = /.$/;
- w = w.replace(re,"");
- }
- }
- else if (re2.test(w)) {
- var fp = re2.exec(w);
- stem = fp[1];
- re2 = new RegExp(s_v);
- if (re2.test(stem)) {
- w = stem;
- re2 = /(at|bl|iz)$/;
- re3 = new RegExp("([^aeiouylsz])\\1$");
- re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
- if (re2.test(w))
- w = w + "e";
- else if (re3.test(w)) {
- re = /.$/;
- w = w.replace(re,"");
- }
- else if (re4.test(w))
- w = w + "e";
- }
- }
-
- // Step 1c
- re = /^(.+?)y$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(s_v);
- if (re.test(stem))
- w = stem + "i";
- }
-
- // Step 2
- re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- suffix = fp[2];
- re = new RegExp(mgr0);
- if (re.test(stem))
- w = stem + step2list[suffix];
- }
-
- // Step 3
- re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- suffix = fp[2];
- re = new RegExp(mgr0);
- if (re.test(stem))
- w = stem + step3list[suffix];
- }
-
- // Step 4
- re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
- re2 = /^(.+?)(s|t)(ion)$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(mgr1);
- if (re.test(stem))
- w = stem;
- }
- else if (re2.test(w)) {
- var fp = re2.exec(w);
- stem = fp[1] + fp[2];
- re2 = new RegExp(mgr1);
- if (re2.test(stem))
- w = stem;
- }
-
- // Step 5
- re = /^(.+?)e$/;
- if (re.test(w)) {
- var fp = re.exec(w);
- stem = fp[1];
- re = new RegExp(mgr1);
- re2 = new RegExp(meq1);
- re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
- if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
- w = stem;
- }
- re = /ll$/;
- re2 = new RegExp(mgr1);
- if (re.test(w) && re2.test(w)) {
- re = /.$/;
- w = w.replace(re,"");
- }
-
- // and turn initial Y back to y
- if (firstch == "y")
- w = firstch.toLowerCase() + w.substr(1);
- return w;
- }
-}
-
-
-
-/**
- * Simple result scoring code.
- */
-var Scorer = {
- // Implement the following function to further tweak the score for each result
- // The function takes a result array [filename, title, anchor, descr, score]
- // and returns the new score.
- /*
- score: function(result) {
- return result[4];
- },
- */
-
- // query matches the full name of an object
- objNameMatch: 11,
- // or matches in the last dotted part of the object name
- objPartialMatch: 6,
- // Additive scores depending on the priority of the object
- objPrio: {0: 15, // used to be importantResults
- 1: 5, // used to be objectResults
- 2: -5}, // used to be unimportantResults
- // Used when the priority is not in the mapping.
- objPrioDefault: 0,
-
- // query found in title
- title: 15,
- // query found in terms
- term: 5
-};
-
-
-/**
- * Search Module
- */
-var Search = {
-
- _index : null,
- _queued_query : null,
- _pulse_status : -1,
-
- init : function() {
- var params = $.getQueryParameters();
- if (params.q) {
- var query = params.q[0];
- $('input[name="q"]')[0].value = query;
- this.performSearch(query);
- }
- },
-
- loadIndex : function(url) {
- $.ajax({type: "GET", url: url, data: null,
- dataType: "script", cache: true,
- complete: function(jqxhr, textstatus) {
- if (textstatus != "success") {
- document.getElementById("searchindexloader").src = url;
- }
- }});
- },
-
- setIndex : function(index) {
- var q;
- this._index = index;
- if ((q = this._queued_query) !== null) {
- this._queued_query = null;
- Search.query(q);
- }
- },
-
- hasIndex : function() {
- return this._index !== null;
- },
-
- deferQuery : function(query) {
- this._queued_query = query;
- },
-
- stopPulse : function() {
- this._pulse_status = 0;
- },
-
- startPulse : function() {
- if (this._pulse_status >= 0)
- return;
- function pulse() {
- var i;
- Search._pulse_status = (Search._pulse_status + 1) % 4;
- var dotString = '';
- for (i = 0; i < Search._pulse_status; i++)
- dotString += '.';
- Search.dots.text(dotString);
- if (Search._pulse_status > -1)
- window.setTimeout(pulse, 500);
- }
- pulse();
- },
-
- /**
- * perform a search for something (or wait until index is loaded)
- */
- performSearch : function(query) {
- // create the required interface elements
- this.out = $('#search-results');
- this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
- this.dots = $('<span></span>').appendTo(this.title);
- this.status = $('<p style="display: none"></p>').appendTo(this.out);
- this.output = $('<ul class="search"/>').appendTo(this.out);
-
- $('#search-progress').text(_('Preparing search...'));
- this.startPulse();
-
- // index already loaded, the browser was quick!
- if (this.hasIndex())
- this.query(query);
- else
- this.deferQuery(query);
- },
-
- /**
- * execute search (requires search index to be loaded)
- */
- query : function(query) {
- var i;
- var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
-
- // stem the searchterms and add them to the correct list
- var stemmer = new Stemmer();
- var searchterms = [];
- var excluded = [];
- var hlterms = [];
- var tmp = query.split(/\s+/);
- var objectterms = [];
- for (i = 0; i < tmp.length; i++) {
- if (tmp[i] !== "") {
- objectterms.push(tmp[i].toLowerCase());
- }
-
- if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
- tmp[i] === "") {
- // skip this "word"
- continue;
- }
- // stem the word
- var word = stemmer.stemWord(tmp[i].toLowerCase());
- var toAppend;
- // select the correct list
- if (word[0] == '-') {
- toAppend = excluded;
- word = word.substr(1);
- }
- else {
- toAppend = searchterms;
- hlterms.push(tmp[i].toLowerCase());
- }
- // only add if not already in the list
- if (!$u.contains(toAppend, word))
- toAppend.push(word);
- }
- var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
-
- // console.debug('SEARCH: searching for:');
- // console.info('required: ', searchterms);
- // console.info('excluded: ', excluded);
-
- // prepare search
- var terms = this._index.terms;
- var titleterms = this._index.titleterms;
-
- // array of [filename, title, anchor, descr, score]
- var results = [];
- $('#search-progress').empty();
-
- // lookup as object
- for (i = 0; i < objectterms.length; i++) {
- var others = [].concat(objectterms.slice(0, i),
- objectterms.slice(i+1, objectterms.length));
- results = results.concat(this.performObjectSearch(objectterms[i], others));
- }
-
- // lookup as search terms in fulltext
- results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
- .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
-
- // let the scorer override scores with a custom scoring function
- if (Scorer.score) {
- for (i = 0; i < results.length; i++)
- results[i][4] = Scorer.score(results[i]);
- }
-
- // now sort the results by score (in opposite order of appearance, since the
- // display function below uses pop() to retrieve items) and then
- // alphabetically
- results.sort(function(a, b) {
- var left = a[4];
- var right = b[4];
- if (left > right) {
- return 1;
- } else if (left < right) {
- return -1;
- } else {
- // same score: sort alphabetically
- left = a[1].toLowerCase();
- right = b[1].toLowerCase();
- return (left > right) ? -1 : ((left < right) ? 1 : 0);
- }
- });
-
- // for debugging
- //Search.lastresults = results.slice(); // a copy
- //console.info('search results:', Search.lastresults);
-
- // print the results
- var resultCount = results.length;
- function displayNextItem() {
- // results left, load the summary and display it
- if (results.length) {
- var item = results.pop();
- var listItem = $('<li style="display:none"></li>');
- if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
- // dirhtml builder
- var dirname = item[0] + '/';
- if (dirname.match(/\/index\/$/)) {
- dirname = dirname.substring(0, dirname.length-6);
- } else if (dirname == 'index/') {
- dirname = '';
- }
- listItem.append($('<a/>').attr('href',
- DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
- highlightstring + item[2]).html(item[1]));
- } else {
- // normal html builders
- listItem.append($('<a/>').attr('href',
- item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
- highlightstring + item[2]).html(item[1]));
- }
- if (item[3]) {
- listItem.append($('<span> (' + item[3] + ')</span>'));
- Search.output.append(listItem);
- listItem.slideDown(5, function() {
- displayNextItem();
- });
- } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
- $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
- dataType: "text",
- complete: function(jqxhr, textstatus) {
- var data = jqxhr.responseText;
- if (data !== '') {
- listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
- }
- Search.output.append(listItem);
- listItem.slideDown(5, function() {
- displayNextItem();
- });
- }});
- } else {
- // no source available, just display title
- Search.output.append(listItem);
- listItem.slideDown(5, function() {
- displayNextItem();
- });
- }
- }
- // search finished, update title and status message
- else {
- Search.stopPulse();
- Search.title.text(_('Search Results'));
- if (!resultCount)
- Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
- else
- Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
- Search.status.fadeIn(500);
- }
- }
- displayNextItem();
- },
-
- /**
- * search for object names
- */
- performObjectSearch : function(object, otherterms) {
- var filenames = this._index.filenames;
- var objects = this._index.objects;
- var objnames = this._index.objnames;
- var titles = this._index.titles;
-
- var i;
- var results = [];
-
- for (var prefix in objects) {
- for (var name in objects[prefix]) {
- var fullname = (prefix ? prefix + '.' : '') + name;
- if (fullname.toLowerCase().indexOf(object) > -1) {
- var score = 0;
- var parts = fullname.split('.');
- // check for different match types: exact matches of full name or
- // "last name" (i.e. last dotted part)
- if (fullname == object || parts[parts.length - 1] == object) {
- score += Scorer.objNameMatch;
- // matches in last name
- } else if (parts[parts.length - 1].indexOf(object) > -1) {
- score += Scorer.objPartialMatch;
- }
- var match = objects[prefix][name];
- var objname = objnames[match[1]][2];
- var title = titles[match[0]];
- // If more than one term searched for, we require other words to be
- // found in the name/title/description
- if (otherterms.length > 0) {
- var haystack = (prefix + ' ' + name + ' ' +
- objname + ' ' + title).toLowerCase();
- var allfound = true;
- for (i = 0; i < otherterms.length; i++) {
- if (haystack.indexOf(otherterms[i]) == -1) {
- allfound = false;
- break;
- }
- }
- if (!allfound) {
- continue;
- }
- }
- var descr = objname + _(', in ') + title;
-
- var anchor = match[3];
- if (anchor === '')
- anchor = fullname;
- else if (anchor == '-')
- anchor = objnames[match[1]][1] + '-' + fullname;
- // add custom score for some objects according to scorer
- if (Scorer.objPrio.hasOwnProperty(match[2])) {
- score += Scorer.objPrio[match[2]];
- } else {
- score += Scorer.objPrioDefault;
- }
- results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
- }
- }
- }
-
- return results;
- },
-
- /**
- * search for full-text terms in the index
- */
- performTermsSearch : function(searchterms, excluded, terms, score) {
- var filenames = this._index.filenames;
- var titles = this._index.titles;
-
- var i, j, file, files;
- var fileMap = {};
- var results = [];
-
- // perform the search on the required terms
- for (i = 0; i < searchterms.length; i++) {
- var word = searchterms[i];
- // no match but word was a required one
- if ((files = terms[word]) === undefined)
- break;
- if (files.length === undefined) {
- files = [files];
- }
- // create the mapping
- for (j = 0; j < files.length; j++) {
- file = files[j];
- if (file in fileMap)
- fileMap[file].push(word);
- else
- fileMap[file] = [word];
- }
- }
-
- // now check if the files don't contain excluded terms
- for (file in fileMap) {
- var valid = true;
-
- // check if all requirements are matched
- if (fileMap[file].length != searchterms.length)
- continue;
-
- // ensure that none of the excluded terms is in the search result
- for (i = 0; i < excluded.length; i++) {
- if (terms[excluded[i]] == file ||
- $u.contains(terms[excluded[i]] || [], file)) {
- valid = false;
- break;
- }
- }
-
- // if we have still a valid result we can add it to the result list
- if (valid) {
- results.push([filenames[file], titles[file], '', null, score]);
- }
- }
- return results;
- },
-
- /**
- * helper function to return a node containing the
- * search summary for a given text. keywords is a list
- * of stemmed words, hlwords is the list of normal, unstemmed
- * words. the first one is used to find the occurance, the
- * latter for highlighting it.
- */
- makeSearchSummary : function(text, keywords, hlwords) {
- var textLower = text.toLowerCase();
- var start = 0;
- $.each(keywords, function() {
- var i = textLower.indexOf(this.toLowerCase());
- if (i > -1)
- start = i;
- });
- start = Math.max(start - 120, 0);
- var excerpt = ((start > 0) ? '...' : '') +
- $.trim(text.substr(start, 240)) +
- ((start + 240 - text.length) ? '...' : '');
- var rv = $('<div class="context"></div>').text(excerpt);
- $.each(hlwords, function() {
- rv = rv.highlightText(this, 'highlighted');
- });
- return rv;
- }
-};
-
-$(document).ready(function() {
- Search.init();
-}); \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/sidebar.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/sidebar.js
deleted file mode 100644
index 874a890a3c..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/sidebar.js
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * sidebar.js
- * ~~~~~~~~~~
- *
- * This script makes the Sphinx sidebar collapsible.
- *
- * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
- * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
- * used to collapse and expand the sidebar.
- *
- * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
- * and the width of the sidebar and the margin-left of the document
- * are decreased. When the sidebar is expanded the opposite happens.
- * This script saves a per-browser/per-session cookie used to
- * remember the position of the sidebar among the pages.
- * Once the browser is closed the cookie is deleted and the position
- * reset to the default (expanded).
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-$(function() {
-
-
-
-
-
-
-
-
- // global elements used by the functions.
- // the 'sidebarbutton' element is defined as global after its
- // creation, in the add_sidebar_button function
- var bodywrapper = $('.bodywrapper');
- var sidebar = $('.sphinxsidebar');
- var sidebarwrapper = $('.sphinxsidebarwrapper');
-
- // for some reason, the document has no sidebar; do not run into errors
- if (!sidebar.length) return;
-
- // original margin-left of the bodywrapper and width of the sidebar
- // with the sidebar expanded
- var bw_margin_expanded = bodywrapper.css('margin-left');
- var ssb_width_expanded = sidebar.width();
-
- // margin-left of the bodywrapper and width of the sidebar
- // with the sidebar collapsed
- var bw_margin_collapsed = '.8em';
- var ssb_width_collapsed = '.8em';
-
- // colors used by the current theme
- var dark_color = $('.related').css('background-color');
- var light_color = $('.document').css('background-color');
-
- function sidebar_is_collapsed() {
- return sidebarwrapper.is(':not(:visible)');
- }
-
- function toggle_sidebar() {
- if (sidebar_is_collapsed())
- expand_sidebar();
- else
- collapse_sidebar();
- }
-
- function collapse_sidebar() {
- sidebarwrapper.hide();
- sidebar.css('width', ssb_width_collapsed);
- bodywrapper.css('margin-left', bw_margin_collapsed);
- sidebarbutton.css({
- 'margin-left': '0',
- 'height': bodywrapper.height()
- });
- sidebarbutton.find('span').text('»');
- sidebarbutton.attr('title', _('Expand sidebar'));
- document.cookie = 'sidebar=collapsed';
- }
-
- function expand_sidebar() {
- bodywrapper.css('margin-left', bw_margin_expanded);
- sidebar.css('width', ssb_width_expanded);
- sidebarwrapper.show();
- sidebarbutton.css({
- 'margin-left': ssb_width_expanded-12,
- 'height': bodywrapper.height()
- });
- sidebarbutton.find('span').text('«');
- sidebarbutton.attr('title', _('Collapse sidebar'));
- document.cookie = 'sidebar=expanded';
- }
-
- function add_sidebar_button() {
- sidebarwrapper.css({
- 'float': 'left',
- 'margin-right': '0',
- 'width': ssb_width_expanded - 28
- });
- // create the button
- sidebar.append(
- '<div id="sidebarbutton"><span>&laquo;</span></div>'
- );
- var sidebarbutton = $('#sidebarbutton');
- light_color = sidebarbutton.css('background-color');
- // find the height of the viewport to center the '<<' in the page
- var viewport_height;
- if (window.innerHeight)
- viewport_height = window.innerHeight;
- else
- viewport_height = $(window).height();
- sidebarbutton.find('span').css({
- 'display': 'block',
- 'margin-top': (viewport_height - sidebar.position().top - 20) / 2
- });
-
- sidebarbutton.click(toggle_sidebar);
- sidebarbutton.attr('title', _('Collapse sidebar'));
- sidebarbutton.css({
- 'color': '#FFFFFF',
- 'border-left': '1px solid ' + dark_color,
- 'font-size': '1.2em',
- 'cursor': 'pointer',
- 'height': bodywrapper.height(),
- 'padding-top': '1px',
- 'margin-left': ssb_width_expanded - 12
- });
-
- sidebarbutton.hover(
- function () {
- $(this).css('background-color', dark_color);
- },
- function () {
- $(this).css('background-color', light_color);
- }
- );
- }
-
- function set_position_from_cookie() {
- if (!document.cookie)
- return;
- var items = document.cookie.split(';');
- for(var k=0; k<items.length; k++) {
- var key_val = items[k].split('=');
- var key = key_val[0].replace(/ /, ""); // strip leading spaces
- if (key == 'sidebar') {
- var value = key_val[1];
- if ((value == 'collapsed') && (!sidebar_is_collapsed()))
- collapse_sidebar();
- else if ((value == 'expanded') && (sidebar_is_collapsed()))
- expand_sidebar();
- }
- }
- }
-
- add_sidebar_button();
- var sidebarbutton = $('#sidebarbutton');
- set_position_from_cookie();
-}); \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/underscore.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/underscore.js
deleted file mode 100644
index 5b55f32bea..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/underscore.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Underscore.js 1.3.1
-// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
-// Underscore is freely distributable under the MIT license.
-// Portions of Underscore are inspired or borrowed from Prototype,
-// Oliver Steele's Functional, and John Resig's Micro-Templating.
-// For all details and documentation:
-// http://documentcloud.github.com/underscore
-(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
-c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
-h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
-b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
-null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
-function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
-e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
-function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
-return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
-c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
-b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
-return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
-d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
-var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
-c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
-a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
-b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
-1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
-b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
-b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
-function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
-u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
-function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
-true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/websupport.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/websupport.js
deleted file mode 100644
index 19fcda5647..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/_static/websupport.js
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * websupport.js
- * ~~~~~~~~~~~~~
- *
- * sphinx.websupport utilties for all documentation.
- *
- * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-(function($) {
- $.fn.autogrow = function() {
- return this.each(function() {
- var textarea = this;
-
- $.fn.autogrow.resize(textarea);
-
- $(textarea)
- .focus(function() {
- textarea.interval = setInterval(function() {
- $.fn.autogrow.resize(textarea);
- }, 500);
- })
- .blur(function() {
- clearInterval(textarea.interval);
- });
- });
- };
-
- $.fn.autogrow.resize = function(textarea) {
- var lineHeight = parseInt($(textarea).css('line-height'), 10);
- var lines = textarea.value.split('\n');
- var columns = textarea.cols;
- var lineCount = 0;
- $.each(lines, function() {
- lineCount += Math.ceil(this.length / columns) || 1;
- });
- var height = lineHeight * (lineCount + 1);
- $(textarea).css('height', height);
- };
-})(jQuery);
-
-(function($) {
- var comp, by;
-
- function init() {
- initEvents();
- initComparator();
- }
-
- function initEvents() {
- $('a.comment-close').live("click", function(event) {
- event.preventDefault();
- hide($(this).attr('id').substring(2));
- });
- $('a.vote').live("click", function(event) {
- event.preventDefault();
- handleVote($(this));
- });
- $('a.reply').live("click", function(event) {
- event.preventDefault();
- openReply($(this).attr('id').substring(2));
- });
- $('a.close-reply').live("click", function(event) {
- event.preventDefault();
- closeReply($(this).attr('id').substring(2));
- });
- $('a.sort-option').live("click", function(event) {
- event.preventDefault();
- handleReSort($(this));
- });
- $('a.show-proposal').live("click", function(event) {
- event.preventDefault();
- showProposal($(this).attr('id').substring(2));
- });
- $('a.hide-proposal').live("click", function(event) {
- event.preventDefault();
- hideProposal($(this).attr('id').substring(2));
- });
- $('a.show-propose-change').live("click", function(event) {
- event.preventDefault();
- showProposeChange($(this).attr('id').substring(2));
- });
- $('a.hide-propose-change').live("click", function(event) {
- event.preventDefault();
- hideProposeChange($(this).attr('id').substring(2));
- });
- $('a.accept-comment').live("click", function(event) {
- event.preventDefault();
- acceptComment($(this).attr('id').substring(2));
- });
- $('a.delete-comment').live("click", function(event) {
- event.preventDefault();
- deleteComment($(this).attr('id').substring(2));
- });
- $('a.comment-markup').live("click", function(event) {
- event.preventDefault();
- toggleCommentMarkupBox($(this).attr('id').substring(2));
- });
- }
-
- /**
- * Set comp, which is a comparator function used for sorting and
- * inserting comments into the list.
- */
- function setComparator() {
- // If the first three letters are "asc", sort in ascending order
- // and remove the prefix.
- if (by.substring(0,3) == 'asc') {
- var i = by.substring(3);
- comp = function(a, b) { return a[i] - b[i]; };
- } else {
- // Otherwise sort in descending order.
- comp = function(a, b) { return b[by] - a[by]; };
- }
-
- // Reset link styles and format the selected sort option.
- $('a.sel').attr('href', '#').removeClass('sel');
- $('a.by' + by).removeAttr('href').addClass('sel');
- }
-
- /**
- * Create a comp function. If the user has preferences stored in
- * the sortBy cookie, use those, otherwise use the default.
- */
- function initComparator() {
- by = 'rating'; // Default to sort by rating.
- // If the sortBy cookie is set, use that instead.
- if (document.cookie.length > 0) {
- var start = document.cookie.indexOf('sortBy=');
- if (start != -1) {
- start = start + 7;
- var end = document.cookie.indexOf(";", start);
- if (end == -1) {
- end = document.cookie.length;
- by = unescape(document.cookie.substring(start, end));
- }
- }
- }
- setComparator();
- }
-
- /**
- * Show a comment div.
- */
- function show(id) {
- $('#ao' + id).hide();
- $('#ah' + id).show();
- var context = $.extend({id: id}, opts);
- var popup = $(renderTemplate(popupTemplate, context)).hide();
- popup.find('textarea[name="proposal"]').hide();
- popup.find('a.by' + by).addClass('sel');
- var form = popup.find('#cf' + id);
- form.submit(function(event) {
- event.preventDefault();
- addComment(form);
- });
- $('#s' + id).after(popup);
- popup.slideDown('fast', function() {
- getComments(id);
- });
- }
-
- /**
- * Hide a comment div.
- */
- function hide(id) {
- $('#ah' + id).hide();
- $('#ao' + id).show();
- var div = $('#sc' + id);
- div.slideUp('fast', function() {
- div.remove();
- });
- }
-
- /**
- * Perform an ajax request to get comments for a node
- * and insert the comments into the comments tree.
- */
- function getComments(id) {
- $.ajax({
- type: 'GET',
- url: opts.getCommentsURL,
- data: {node: id},
- success: function(data, textStatus, request) {
- var ul = $('#cl' + id);
- var speed = 100;
- $('#cf' + id)
- .find('textarea[name="proposal"]')
- .data('source', data.source);
-
- if (data.comments.length === 0) {
- ul.html('<li>No comments yet.</li>');
- ul.data('empty', true);
- } else {
- // If there are comments, sort them and put them in the list.
- var comments = sortComments(data.comments);
- speed = data.comments.length * 100;
- appendComments(comments, ul);
- ul.data('empty', false);
- }
- $('#cn' + id).slideUp(speed + 200);
- ul.slideDown(speed);
- },
- error: function(request, textStatus, error) {
- showError('Oops, there was a problem retrieving the comments.');
- },
- dataType: 'json'
- });
- }
-
- /**
- * Add a comment via ajax and insert the comment into the comment tree.
- */
- function addComment(form) {
- var node_id = form.find('input[name="node"]').val();
- var parent_id = form.find('input[name="parent"]').val();
- var text = form.find('textarea[name="comment"]').val();
- var proposal = form.find('textarea[name="proposal"]').val();
-
- if (text == '') {
- showError('Please enter a comment.');
- return;
- }
-
- // Disable the form that is being submitted.
- form.find('textarea,input').attr('disabled', 'disabled');
-
- // Send the comment to the server.
- $.ajax({
- type: "POST",
- url: opts.addCommentURL,
- dataType: 'json',
- data: {
- node: node_id,
- parent: parent_id,
- text: text,
- proposal: proposal
- },
- success: function(data, textStatus, error) {
- // Reset the form.
- if (node_id) {
- hideProposeChange(node_id);
- }
- form.find('textarea')
- .val('')
- .add(form.find('input'))
- .removeAttr('disabled');
- var ul = $('#cl' + (node_id || parent_id));
- if (ul.data('empty')) {
- $(ul).empty();
- ul.data('empty', false);
- }
- insertComment(data.comment);
- var ao = $('#ao' + node_id);
- ao.find('img').attr({'src': opts.commentBrightImage});
- if (node_id) {
- // if this was a "root" comment, remove the commenting box
- // (the user can get it back by reopening the comment popup)
- $('#ca' + node_id).slideUp();
- }
- },
- error: function(request, textStatus, error) {
- form.find('textarea,input').removeAttr('disabled');
- showError('Oops, there was a problem adding the comment.');
- }
- });
- }
-
- /**
- * Recursively append comments to the main comment list and children
- * lists, creating the comment tree.
- */
- function appendComments(comments, ul) {
- $.each(comments, function() {
- var div = createCommentDiv(this);
- ul.append($(document.createElement('li')).html(div));
- appendComments(this.children, div.find('ul.comment-children'));
- // To avoid stagnating data, don't store the comments children in data.
- this.children = null;
- div.data('comment', this);
- });
- }
-
- /**
- * After adding a new comment, it must be inserted in the correct
- * location in the comment tree.
- */
- function insertComment(comment) {
- var div = createCommentDiv(comment);
-
- // To avoid stagnating data, don't store the comments children in data.
- comment.children = null;
- div.data('comment', comment);
-
- var ul = $('#cl' + (comment.node || comment.parent));
- var siblings = getChildren(ul);
-
- var li = $(document.createElement('li'));
- li.hide();
-
- // Determine where in the parents children list to insert this comment.
- for(i=0; i < siblings.length; i++) {
- if (comp(comment, siblings[i]) <= 0) {
- $('#cd' + siblings[i].id)
- .parent()
- .before(li.html(div));
- li.slideDown('fast');
- return;
- }
- }
-
- // If we get here, this comment rates lower than all the others,
- // or it is the only comment in the list.
- ul.append(li.html(div));
- li.slideDown('fast');
- }
-
- function acceptComment(id) {
- $.ajax({
- type: 'POST',
- url: opts.acceptCommentURL,
- data: {id: id},
- success: function(data, textStatus, request) {
- $('#cm' + id).fadeOut('fast');
- $('#cd' + id).removeClass('moderate');
- },
- error: function(request, textStatus, error) {
- showError('Oops, there was a problem accepting the comment.');
- }
- });
- }
-
- function deleteComment(id) {
- $.ajax({
- type: 'POST',
- url: opts.deleteCommentURL,
- data: {id: id},
- success: function(data, textStatus, request) {
- var div = $('#cd' + id);
- if (data == 'delete') {
- // Moderator mode: remove the comment and all children immediately
- div.slideUp('fast', function() {
- div.remove();
- });
- return;
- }
- // User mode: only mark the comment as deleted
- div
- .find('span.user-id:first')
- .text('[deleted]').end()
- .find('div.comment-text:first')
- .text('[deleted]').end()
- .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
- ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
- .remove();
- var comment = div.data('comment');
- comment.username = '[deleted]';
- comment.text = '[deleted]';
- div.data('comment', comment);
- },
- error: function(request, textStatus, error) {
- showError('Oops, there was a problem deleting the comment.');
- }
- });
- }
-
- function showProposal(id) {
- $('#sp' + id).hide();
- $('#hp' + id).show();
- $('#pr' + id).slideDown('fast');
- }
-
- function hideProposal(id) {
- $('#hp' + id).hide();
- $('#sp' + id).show();
- $('#pr' + id).slideUp('fast');
- }
-
- function showProposeChange(id) {
- $('#pc' + id).hide();
- $('#hc' + id).show();
- var textarea = $('#pt' + id);
- textarea.val(textarea.data('source'));
- $.fn.autogrow.resize(textarea[0]);
- textarea.slideDown('fast');
- }
-
- function hideProposeChange(id) {
- $('#hc' + id).hide();
- $('#pc' + id).show();
- var textarea = $('#pt' + id);
- textarea.val('').removeAttr('disabled');
- textarea.slideUp('fast');
- }
-
- function toggleCommentMarkupBox(id) {
- $('#mb' + id).toggle();
- }
-
- /** Handle when the user clicks on a sort by link. */
- function handleReSort(link) {
- var classes = link.attr('class').split(/\s+/);
- for (var i=0; i<classes.length; i++) {
- if (classes[i] != 'sort-option') {
- by = classes[i].substring(2);
- }
- }
- setComparator();
- // Save/update the sortBy cookie.
- var expiration = new Date();
- expiration.setDate(expiration.getDate() + 365);
- document.cookie= 'sortBy=' + escape(by) +
- ';expires=' + expiration.toUTCString();
- $('ul.comment-ul').each(function(index, ul) {
- var comments = getChildren($(ul), true);
- comments = sortComments(comments);
- appendComments(comments, $(ul).empty());
- });
- }
-
- /**
- * Function to process a vote when a user clicks an arrow.
- */
- function handleVote(link) {
- if (!opts.voting) {
- showError("You'll need to login to vote.");
- return;
- }
-
- var id = link.attr('id');
- if (!id) {
- // Didn't click on one of the voting arrows.
- return;
- }
- // If it is an unvote, the new vote value is 0,
- // Otherwise it's 1 for an upvote, or -1 for a downvote.
- var value = 0;
- if (id.charAt(1) != 'u') {
- value = id.charAt(0) == 'u' ? 1 : -1;
- }
- // The data to be sent to the server.
- var d = {
- comment_id: id.substring(2),
- value: value
- };
-
- // Swap the vote and unvote links.
- link.hide();
- $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
- .show();
-
- // The div the comment is displayed in.
- var div = $('div#cd' + d.comment_id);
- var data = div.data('comment');
-
- // If this is not an unvote, and the other vote arrow has
- // already been pressed, unpress it.
- if ((d.value !== 0) && (data.vote === d.value * -1)) {
- $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
- $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
- }
-
- // Update the comments rating in the local data.
- data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
- data.vote = d.value;
- div.data('comment', data);
-
- // Change the rating text.
- div.find('.rating:first')
- .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
-
- // Send the vote information to the server.
- $.ajax({
- type: "POST",
- url: opts.processVoteURL,
- data: d,
- error: function(request, textStatus, error) {
- showError('Oops, there was a problem casting that vote.');
- }
- });
- }
-
- /**
- * Open a reply form used to reply to an existing comment.
- */
- function openReply(id) {
- // Swap out the reply link for the hide link
- $('#rl' + id).hide();
- $('#cr' + id).show();
-
- // Add the reply li to the children ul.
- var div = $(renderTemplate(replyTemplate, {id: id})).hide();
- $('#cl' + id)
- .prepend(div)
- // Setup the submit handler for the reply form.
- .find('#rf' + id)
- .submit(function(event) {
- event.preventDefault();
- addComment($('#rf' + id));
- closeReply(id);
- })
- .find('input[type=button]')
- .click(function() {
- closeReply(id);
- });
- div.slideDown('fast', function() {
- $('#rf' + id).find('textarea').focus();
- });
- }
-
- /**
- * Close the reply form opened with openReply.
- */
- function closeReply(id) {
- // Remove the reply div from the DOM.
- $('#rd' + id).slideUp('fast', function() {
- $(this).remove();
- });
-
- // Swap out the hide link for the reply link
- $('#cr' + id).hide();
- $('#rl' + id).show();
- }
-
- /**
- * Recursively sort a tree of comments using the comp comparator.
- */
- function sortComments(comments) {
- comments.sort(comp);
- $.each(comments, function() {
- this.children = sortComments(this.children);
- });
- return comments;
- }
-
- /**
- * Get the children comments from a ul. If recursive is true,
- * recursively include childrens' children.
- */
- function getChildren(ul, recursive) {
- var children = [];
- ul.children().children("[id^='cd']")
- .each(function() {
- var comment = $(this).data('comment');
- if (recursive)
- comment.children = getChildren($(this).find('#cl' + comment.id), true);
- children.push(comment);
- });
- return children;
- }
-
- /** Create a div to display a comment in. */
- function createCommentDiv(comment) {
- if (!comment.displayed && !opts.moderator) {
- return $('<div class="moderate">Thank you! Your comment will show up '
- + 'once it is has been approved by a moderator.</div>');
- }
- // Prettify the comment rating.
- comment.pretty_rating = comment.rating + ' point' +
- (comment.rating == 1 ? '' : 's');
- // Make a class (for displaying not yet moderated comments differently)
- comment.css_class = comment.displayed ? '' : ' moderate';
- // Create a div for this comment.
- var context = $.extend({}, opts, comment);
- var div = $(renderTemplate(commentTemplate, context));
-
- // If the user has voted on this comment, highlight the correct arrow.
- if (comment.vote) {
- var direction = (comment.vote == 1) ? 'u' : 'd';
- div.find('#' + direction + 'v' + comment.id).hide();
- div.find('#' + direction + 'u' + comment.id).show();
- }
-
- if (opts.moderator || comment.text != '[deleted]') {
- div.find('a.reply').show();
- if (comment.proposal_diff)
- div.find('#sp' + comment.id).show();
- if (opts.moderator && !comment.displayed)
- div.find('#cm' + comment.id).show();
- if (opts.moderator || (opts.username == comment.username))
- div.find('#dc' + comment.id).show();
- }
- return div;
- }
-
- /**
- * A simple template renderer. Placeholders such as <%id%> are replaced
- * by context['id'] with items being escaped. Placeholders such as <#id#>
- * are not escaped.
- */
- function renderTemplate(template, context) {
- var esc = $(document.createElement('div'));
-
- function handle(ph, escape) {
- var cur = context;
- $.each(ph.split('.'), function() {
- cur = cur[this];
- });
- return escape ? esc.text(cur || "").html() : cur;
- }
-
- return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
- return handle(arguments[2], arguments[1] == '%' ? true : false);
- });
- }
-
- /** Flash an error message briefly. */
- function showError(message) {
- $(document.createElement('div')).attr({'class': 'popup-error'})
- .append($(document.createElement('div'))
- .attr({'class': 'error-message'}).text(message))
- .appendTo('body')
- .fadeIn("slow")
- .delay(2000)
- .fadeOut("slow");
- }
-
- /** Add a link the user uses to open the comments popup. */
- $.fn.comment = function() {
- return this.each(function() {
- var id = $(this).attr('id').substring(1);
- var count = COMMENT_METADATA[id];
- var title = count + ' comment' + (count == 1 ? '' : 's');
- var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
- var addcls = count == 0 ? ' nocomment' : '';
- $(this)
- .append(
- $(document.createElement('a')).attr({
- href: '#',
- 'class': 'sphinx-comment-open' + addcls,
- id: 'ao' + id
- })
- .append($(document.createElement('img')).attr({
- src: image,
- alt: 'comment',
- title: title
- }))
- .click(function(event) {
- event.preventDefault();
- show($(this).attr('id').substring(2));
- })
- )
- .append(
- $(document.createElement('a')).attr({
- href: '#',
- 'class': 'sphinx-comment-close hidden',
- id: 'ah' + id
- })
- .append($(document.createElement('img')).attr({
- src: opts.closeCommentImage,
- alt: 'close',
- title: 'close'
- }))
- .click(function(event) {
- event.preventDefault();
- hide($(this).attr('id').substring(2));
- })
- );
- });
- };
-
- var opts = {
- processVoteURL: '/_process_vote',
- addCommentURL: '/_add_comment',
- getCommentsURL: '/_get_comments',
- acceptCommentURL: '/_accept_comment',
- deleteCommentURL: '/_delete_comment',
- commentImage: '/static/_static/comment.png',
- closeCommentImage: '/static/_static/comment-close.png',
- loadingImage: '/static/_static/ajax-loader.gif',
- commentBrightImage: '/static/_static/comment-bright.png',
- upArrow: '/static/_static/up.png',
- downArrow: '/static/_static/down.png',
- upArrowPressed: '/static/_static/up-pressed.png',
- downArrowPressed: '/static/_static/down-pressed.png',
- voting: false,
- moderator: false
- };
-
- if (typeof COMMENT_OPTIONS != "undefined") {
- opts = jQuery.extend(opts, COMMENT_OPTIONS);
- }
-
- var popupTemplate = '\
- <div class="sphinx-comments" id="sc<%id%>">\
- <p class="sort-options">\
- Sort by:\
- <a href="#" class="sort-option byrating">best rated</a>\
- <a href="#" class="sort-option byascage">newest</a>\
- <a href="#" class="sort-option byage">oldest</a>\
- </p>\
- <div class="comment-header">Comments</div>\
- <div class="comment-loading" id="cn<%id%>">\
- loading comments... <img src="<%loadingImage%>" alt="" /></div>\
- <ul id="cl<%id%>" class="comment-ul"></ul>\
- <div id="ca<%id%>">\
- <p class="add-a-comment">Add a comment\
- (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
- <div class="comment-markup-box" id="mb<%id%>">\
- reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
- <tt>``code``</tt>, \
- code blocks: <tt>::</tt> and an indented block after blank line</div>\
- <form method="post" id="cf<%id%>" class="comment-form" action="">\
- <textarea name="comment" cols="80"></textarea>\
- <p class="propose-button">\
- <a href="#" id="pc<%id%>" class="show-propose-change">\
- Propose a change &#9657;\
- </a>\
- <a href="#" id="hc<%id%>" class="hide-propose-change">\
- Propose a change &#9663;\
- </a>\
- </p>\
- <textarea name="proposal" id="pt<%id%>" cols="80"\
- spellcheck="false"></textarea>\
- <input type="submit" value="Add comment" />\
- <input type="hidden" name="node" value="<%id%>" />\
- <input type="hidden" name="parent" value="" />\
- </form>\
- </div>\
- </div>';
-
- var commentTemplate = '\
- <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
- <div class="vote">\
- <div class="arrow">\
- <a href="#" id="uv<%id%>" class="vote" title="vote up">\
- <img src="<%upArrow%>" />\
- </a>\
- <a href="#" id="uu<%id%>" class="un vote" title="vote up">\
- <img src="<%upArrowPressed%>" />\
- </a>\
- </div>\
- <div class="arrow">\
- <a href="#" id="dv<%id%>" class="vote" title="vote down">\
- <img src="<%downArrow%>" id="da<%id%>" />\
- </a>\
- <a href="#" id="du<%id%>" class="un vote" title="vote down">\
- <img src="<%downArrowPressed%>" />\
- </a>\
- </div>\
- </div>\
- <div class="comment-content">\
- <p class="tagline comment">\
- <span class="user-id"><%username%></span>\
- <span class="rating"><%pretty_rating%></span>\
- <span class="delta"><%time.delta%></span>\
- </p>\
- <div class="comment-text comment"><#text#></div>\
- <p class="comment-opts comment">\
- <a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
- <a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
- <a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
- <a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
- <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
- <span id="cm<%id%>" class="moderation hidden">\
- <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
- </span>\
- </p>\
- <pre class="proposal" id="pr<%id%>">\
-<#proposal_diff#>\
- </pre>\
- <ul class="comment-children" id="cl<%id%>"></ul>\
- </div>\
- <div class="clearleft"></div>\
- </div>\
- </div>';
-
- var replyTemplate = '\
- <li>\
- <div class="reply-div" id="rd<%id%>">\
- <form id="rf<%id%>">\
- <textarea name="comment" cols="80"></textarea>\
- <input type="submit" value="Add reply" />\
- <input type="button" value="Cancel" />\
- <input type="hidden" name="parent" value="<%id%>" />\
- <input type="hidden" name="node" value="" />\
- </form>\
- </div>\
- </li>';
-
- $(document).ready(function() {
- init();
- });
-})(jQuery);
-
-$(document).ready(function() {
- // add comment anchors for all paragraphs that are commentable
- $('.sphinx-has-comment').comment();
-
- // highlight search words in search results
- $("div.context").each(function() {
- var params = $.getQueryParameters();
- var terms = (params.q) ? params.q[0].split(/\s+/) : [];
- var result = $(this);
- $.each(terms, function() {
- result.highlightText(this.toLowerCase(), 'highlighted');
- });
- });
-
- // directly open comment window if requested
- var anchor = document.location.hash;
- if (anchor.substring(0, 9) == '#comment-') {
- $('#ao' + anchor.substring(9)).click();
- document.location.hash = '#s' + anchor.substring(9);
- }
-});
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/client.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/client.html
deleted file mode 100644
index 8b5de14b90..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/client.html
+++ /dev/null
@@ -1,404 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>client Package &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="index.html" />
- <link rel="next" title="server Package" href="server.html" />
- <link rel="prev" title="Welcome to BrowserMob Proxy’s documentation!" href="index.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="server.html" title="server Package"
- accesskey="N">next</a> |</li>
- <li class="right" >
- <a href="index.html" title="Welcome to BrowserMob Proxy’s documentation!"
- accesskey="P">previous</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <div class="toctree-wrapper compound">
-<ul class="simple">
-</ul>
-</div>
-<div class="section" id="module-browsermobproxy">
-<span id="client-package"></span><h1><tt class="xref py py-mod docutils literal"><span class="pre">client</span></tt> Package<a class="headerlink" href="#module-browsermobproxy" title="Permalink to this headline">¶</a></h1>
-<dl class="class">
-<dt id="browsermobproxy.Client">
-<em class="property">class </em><tt class="descclassname">browsermobproxy.</tt><tt class="descname">Client</tt><big>(</big><em>url</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client" title="Permalink to this definition">¶</a></dt>
-<dd><p>Initialises a new Client object</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>url</strong> &#8211; This is where the BrowserMob Proxy lives</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="browsermobproxy.Client.add_to_capabilities">
-<tt class="descname">add_to_capabilities</tt><big>(</big><em>capabilities</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.add_to_capabilities" title="Permalink to this definition">¶</a></dt>
-<dd><p>Adds an &#8216;proxy&#8217; entry to a desired capabilities dictionary with the
-BrowserMob proxy information</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>capabilities</strong> &#8211; The Desired capabilities object from Selenium WebDriver</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.basic_authentication">
-<tt class="descname">basic_authentication</tt><big>(</big><em>domain</em>, <em>username</em>, <em>password</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.basic_authentication" title="Permalink to this definition">¶</a></dt>
-<dd><p>This add automatic basic authentication</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>domain</strong> &#8211; domain to set authentication credentials for</li>
-<li><strong>username</strong> &#8211; valid username to use when authenticating</li>
-<li><strong>password</strong> &#8211; valid password to use when authenticating</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.blacklist">
-<tt class="descname">blacklist</tt><big>(</big><em>regexp</em>, <em>status_code</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.blacklist" title="Permalink to this definition">¶</a></dt>
-<dd><p>Sets a list of URL patterns to blacklist</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>regex</strong> &#8211; a comma separated list of regular expressions</li>
-<li><strong>status_code</strong> &#8211; the HTTP status code to return for URLs that do not match the blacklist</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.clear_dns_cache">
-<tt class="descname">clear_dns_cache</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Client.clear_dns_cache" title="Permalink to this definition">¶</a></dt>
-<dd><p>Clears the DNS cache associated with the proxy instance</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.close">
-<tt class="descname">close</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Client.close" title="Permalink to this definition">¶</a></dt>
-<dd><p>shuts down the proxy and closes the port</p>
-</dd></dl>
-
-<dl class="attribute">
-<dt id="browsermobproxy.Client.har">
-<tt class="descname">har</tt><a class="headerlink" href="#browsermobproxy.Client.har" title="Permalink to this definition">¶</a></dt>
-<dd><p>Gets the HAR that has been recorded</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.headers">
-<tt class="descname">headers</tt><big>(</big><em>headers</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.headers" title="Permalink to this definition">¶</a></dt>
-<dd><p>This sets the headers that will set by the proxy on all requests</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>headers</strong> &#8211; this is a dictionary of the headers to be set</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.limits">
-<tt class="descname">limits</tt><big>(</big><em>options</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.limits" title="Permalink to this definition">¶</a></dt>
-<dd><p>Limit the bandwidth through the proxy.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>options</strong> &#8211; A dictionary with all the details you want to set. downstreamKbps - Sets the downstream kbps upstreamKbps - Sets the upstream kbps latency - Add the given latency to each HTTP request</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.new_har">
-<tt class="descname">new_har</tt><big>(</big><em>ref=None</em>, <em>options={}</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.new_har" title="Permalink to this definition">¶</a></dt>
-<dd><p>This sets a new HAR to be recorded</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>ref</strong> &#8211; A reference for the HAR. Defaults to None</li>
-<li><strong>options</strong> &#8211; A dictionary that will be passed to BrowserMob Proxy with specific keywords. Keywords are: captureHeaders - Boolean, capture headers captureContent - Boolean, capture content bodies captureBinaryContent - Boolean, capture binary content</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.new_page">
-<tt class="descname">new_page</tt><big>(</big><em>ref=None</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.new_page" title="Permalink to this definition">¶</a></dt>
-<dd><p>This sets a new page to be recorded</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>ref</strong> &#8211; A reference for the new page. Defaults to None</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.remap_hosts">
-<tt class="descname">remap_hosts</tt><big>(</big><em>address</em>, <em>ip_address</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.remap_hosts" title="Permalink to this definition">¶</a></dt>
-<dd><p>Remap the hosts for a specific URL</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>address</strong> &#8211; url that you wish to remap</li>
-<li><strong>ip_address</strong> &#8211; IP Address that will handle all traffic for the address passed in</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.request_interceptor">
-<tt class="descname">request_interceptor</tt><big>(</big><em>js</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.request_interceptor" title="Permalink to this definition">¶</a></dt>
-<dd><p>Executes the javascript against each request</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>js</strong> &#8211; the javascript to execute</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.response_interceptor">
-<tt class="descname">response_interceptor</tt><big>(</big><em>js</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.response_interceptor" title="Permalink to this definition">¶</a></dt>
-<dd><p>Executes the javascript against each response</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>js</strong> &#8211; the javascript to execute</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.retry">
-<tt class="descname">retry</tt><big>(</big><em>retry_count</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.retry" title="Permalink to this definition">¶</a></dt>
-<dd><p>Retries. No idea what its used for, but its in the API...</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>retry_count</strong> &#8211; the number of retries</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.rewrite_url">
-<tt class="descname">rewrite_url</tt><big>(</big><em>match</em>, <em>replace</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.rewrite_url" title="Permalink to this definition">¶</a></dt>
-<dd><p>Rewrites the requested url.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>match</strong> &#8211; a regex to match requests with</li>
-<li><strong>replace</strong> &#8211; unicode a string to replace the matches with</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.selenium_proxy">
-<tt class="descname">selenium_proxy</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Client.selenium_proxy" title="Permalink to this definition">¶</a></dt>
-<dd><p>Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.timeouts">
-<tt class="descname">timeouts</tt><big>(</big><em>options</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.timeouts" title="Permalink to this definition">¶</a></dt>
-<dd><p>Configure various timeouts in the proxy</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>options</strong> &#8211; A dictionary with all the details you want to set. request - request timeout (in seconds) read - read timeout (in seconds) connection - connection timeout (in seconds) dns - dns lookup timeout (in seconds)</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.wait_for_traffic_to_stop">
-<tt class="descname">wait_for_traffic_to_stop</tt><big>(</big><em>quiet_period</em>, <em>timeout</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.wait_for_traffic_to_stop" title="Permalink to this definition">¶</a></dt>
-<dd><p>Waits for the network to be quiet</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>quiet_period</strong> &#8211; number of seconds the network needs to be quiet for</li>
-<li><strong>timeout</strong> &#8211; max number of seconds to wait</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.webdriver_proxy">
-<tt class="descname">webdriver_proxy</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Client.webdriver_proxy" title="Permalink to this definition">¶</a></dt>
-<dd><p>Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Client.whitelist">
-<tt class="descname">whitelist</tt><big>(</big><em>regexp</em>, <em>status_code</em><big>)</big><a class="headerlink" href="#browsermobproxy.Client.whitelist" title="Permalink to this definition">¶</a></dt>
-<dd><p>Sets a list of URL patterns to whitelist</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>regex</strong> &#8211; a comma separated list of regular expressions</li>
-<li><strong>status_code</strong> &#8211; the HTTP status code to return for URLs that do not match the whitelist</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-</dd></dl>
-
-</div>
-
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- <h4>Previous topic</h4>
- <p class="topless"><a href="index.html"
- title="previous chapter">Welcome to BrowserMob Proxy&#8217;s documentation!</a></p>
- <h4>Next topic</h4>
- <p class="topless"><a href="server.html"
- title="next chapter"><tt class="docutils literal"><span class="pre">server</span></tt> Package</a></p>
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="_sources/client.txt"
- rel="nofollow">Show Source</a></li>
- </ul>
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="server.html" title="server Package"
- >next</a> |</li>
- <li class="right" >
- <a href="index.html" title="Welcome to BrowserMob Proxy’s documentation!"
- >previous</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/genindex.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/genindex.html
deleted file mode 100644
index 6976d22e6a..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/genindex.html
+++ /dev/null
@@ -1,297 +0,0 @@
-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Index &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="index.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="#" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
-
-<h1 id="index">Index</h1>
-
-<div class="genindex-jumpbox">
- <a href="#A"><strong>A</strong></a>
- | <a href="#B"><strong>B</strong></a>
- | <a href="#C"><strong>C</strong></a>
- | <a href="#H"><strong>H</strong></a>
- | <a href="#L"><strong>L</strong></a>
- | <a href="#N"><strong>N</strong></a>
- | <a href="#R"><strong>R</strong></a>
- | <a href="#S"><strong>S</strong></a>
- | <a href="#T"><strong>T</strong></a>
- | <a href="#U"><strong>U</strong></a>
- | <a href="#W"><strong>W</strong></a>
-
-</div>
-<h2 id="A">A</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.add_to_capabilities">add_to_capabilities() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="B">B</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.basic_authentication">basic_authentication() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client.blacklist">blacklist() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#module-browsermobproxy">browsermobproxy (module)</a>, <a href="server.html#module-browsermobproxy">[1]</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="C">C</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.clear_dns_cache">clear_dns_cache() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client">Client (class in browsermobproxy)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.close">close() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="server.html#browsermobproxy.Server.create_proxy">create_proxy() (browsermobproxy.Server method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="H">H</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.har">har (browsermobproxy.Client attribute)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.headers">headers() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="L">L</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.limits">limits() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="N">N</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.new_har">new_har() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.new_page">new_page() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="R">R</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.remap_hosts">remap_hosts() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client.request_interceptor">request_interceptor() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client.response_interceptor">response_interceptor() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.retry">retry() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client.rewrite_url">rewrite_url() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="S">S</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.selenium_proxy">selenium_proxy() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="server.html#browsermobproxy.Server">Server (class in browsermobproxy)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="server.html#browsermobproxy.Server.start">start() (browsermobproxy.Server method)</a>
- </dt>
-
-
- <dt><a href="server.html#browsermobproxy.Server.stop">stop() (browsermobproxy.Server method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="T">T</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.timeouts">timeouts() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="U">U</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="server.html#browsermobproxy.Server.url">url (browsermobproxy.Server attribute)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-<h2 id="W">W</h2>
-<table style="width: 100%" class="indextable genindextable"><tr>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.wait_for_traffic_to_stop">wait_for_traffic_to_stop() (browsermobproxy.Client method)</a>
- </dt>
-
-
- <dt><a href="client.html#browsermobproxy.Client.webdriver_proxy">webdriver_proxy() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
- <td style="width: 33%" valign="top"><dl>
-
- <dt><a href="client.html#browsermobproxy.Client.whitelist">whitelist() (browsermobproxy.Client method)</a>
- </dt>
-
- </dl></td>
-</tr></table>
-
-
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
-
-
-
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="#" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/index.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/index.html
deleted file mode 100644
index 59fa22e291..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/index.html
+++ /dev/null
@@ -1,174 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Welcome to BrowserMob Proxy’s documentation! &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="#" />
- <link rel="next" title="client Package" href="client.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="client.html" title="client Package"
- accesskey="N">next</a> |</li>
- <li><a href="#">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <div class="section" id="welcome-to-browsermob-proxy-s-documentation">
-<h1>Welcome to BrowserMob Proxy&#8217;s documentation!<a class="headerlink" href="#welcome-to-browsermob-proxy-s-documentation" title="Permalink to this headline">¶</a></h1>
-<p>Python client for the BrowserMob Proxy 2.0 REST API.</p>
-<div class="section" id="how-to-install">
-<h2>How to install<a class="headerlink" href="#how-to-install" title="Permalink to this headline">¶</a></h2>
-<p>BrowserMob Proxy is available on <a class="reference external" href="http://pypi.python.org/pypi/browsermob-proxy">PyPI</a>, so you can install it with <tt class="docutils literal"><span class="pre">pip</span></tt>:</p>
-<div class="highlight-python"><div class="highlight"><pre>$ pip install browsermob-proxy
-</pre></div>
-</div>
-<p>Or with <cite>easy_install</cite>:</p>
-<div class="highlight-python"><div class="highlight"><pre>$ easy_install browsermob-proxy
-</pre></div>
-</div>
-<p>Or by cloning the repo from <a class="reference external" href="https://github.com/AutomatedTester/browsermob-proxy-py">GitHub</a>:</p>
-<div class="highlight-python"><div class="highlight"><pre>$ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git
-</pre></div>
-</div>
-<p>Then install it by running:</p>
-<div class="highlight-python"><div class="highlight"><pre>$ python setup.py install
-</pre></div>
-</div>
-</div>
-<div class="section" id="how-to-use-with-selenium-webdriver">
-<h2>How to use with selenium-webdriver<a class="headerlink" href="#how-to-use-with-selenium-webdriver" title="Permalink to this headline">¶</a></h2>
-<p>Manually:</p>
-<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">browsermobproxy</span> <span class="kn">import</span> <span class="n">Server</span>
-<span class="n">server</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="s">&quot;path/to/browsermob-proxy&quot;</span><span class="p">)</span>
-<span class="n">server</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
-<span class="n">proxy</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">create_proxy</span><span class="p">()</span>
-
-<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
-<span class="n">profile</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">FirefoxProfile</span><span class="p">()</span>
-<span class="n">profile</span><span class="o">.</span><span class="n">set_proxy</span><span class="p">(</span><span class="n">proxy</span><span class="o">.</span><span class="n">selenium_proxy</span><span class="p">())</span>
-<span class="n">driver</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Firefox</span><span class="p">(</span><span class="n">firefox_profile</span><span class="o">=</span><span class="n">profile</span><span class="p">)</span>
-
-
-<span class="n">proxy</span><span class="o">.</span><span class="n">new_har</span><span class="p">(</span><span class="s">&quot;google&quot;</span><span class="p">)</span>
-<span class="n">driver</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&quot;http://www.google.co.uk&quot;</span><span class="p">)</span>
-<span class="n">proxy</span><span class="o">.</span><span class="n">har</span> <span class="c"># returns a HAR JSON blob</span>
-
-<span class="n">server</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
-<span class="n">driver</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
-</pre></div>
-</div>
-<p>Contents:</p>
-<div class="toctree-wrapper compound">
-<ul>
-<li class="toctree-l1"><a class="reference internal" href="client.html"><tt class="docutils literal"><span class="pre">client</span></tt> Package</a></li>
-<li class="toctree-l1"><a class="reference internal" href="server.html"><tt class="docutils literal"><span class="pre">server</span></tt> Package</a></li>
-</ul>
-</div>
-</div>
-</div>
-<div class="section" id="indices-and-tables">
-<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h1>
-<ul class="simple">
-<li><a class="reference internal" href="genindex.html"><em>Index</em></a></li>
-<li><a class="reference internal" href="py-modindex.html"><em>Module Index</em></a></li>
-<li><a class="reference internal" href="search.html"><em>Search Page</em></a></li>
-</ul>
-</div>
-
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- <h3><a href="#">Table Of Contents</a></h3>
- <ul>
-<li><a class="reference internal" href="#">Welcome to BrowserMob Proxy&#8217;s documentation!</a><ul>
-<li><a class="reference internal" href="#how-to-install">How to install</a></li>
-<li><a class="reference internal" href="#how-to-use-with-selenium-webdriver">How to use with selenium-webdriver</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
-</ul>
-
- <h4>Next topic</h4>
- <p class="topless"><a href="client.html"
- title="next chapter"><tt class="docutils literal"><span class="pre">client</span></tt> Package</a></p>
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="_sources/index.txt"
- rel="nofollow">Show Source</a></li>
- </ul>
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="client.html" title="client Package"
- >next</a> |</li>
- <li><a href="#">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/objects.inv b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/objects.inv
deleted file mode 100644
index 92c3c7bbd8..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/objects.inv
+++ /dev/null
@@ -1,6 +0,0 @@
-# Sphinx inventory version 2
-# Project: BrowserMob Proxy
-# Version: 0.6.0
-# The remainder of this file is compressed using zlib.
-xÚ¥TÁnÂ0 ½ó•¶kѸrÝi‡I“ø€ÈM µ–4í®ð÷ ¤Ó€M¨dǺ~ÏñË{ ÑQçp_‰ºµ‡}U¯ªþP‡éDzÕàª×èÕ˱´Øa÷è»:!r« °m/smjÛä†7Øá¢á8
-rˆMÏqHÇX‡<÷)ø9ƒr±~¬êkÈòÙvºdüPÔP§È{|bCm£«V•Ím'¶4 Yƒ¶é‹,(Å®„§…ÓxPejÅÈMÞWX/Fž qc¤ O÷1ó#å‡çŒFc¡‡†<)¡”ÐXK€cKŠžDKÀŽ¦Ož*ŒcJ"—kǨ|(S+åÁ¸N’î¶Å²Ù#'åÌÀ¾  7m•2¸ô±üoôF 5ÛÈF¶Û”ÂdEÑØßÅ•Ct„X"3Ò3ÅnÒî<°3sw4Þ÷»_ ‡\¤zãÁ¾ß•iYËÉ/¿Í>se¥€q(³‹§@EÈóKý–^Ùçz¿/z’Ä \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/py-modindex.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/py-modindex.html
deleted file mode 100644
index 08a48fbfdb..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/py-modindex.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Python Module Index &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="index.html" />
-
-
- <script type="text/javascript">
- DOCUMENTATION_OPTIONS.COLLAPSE_INDEX = true;
- </script>
-
-
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="#" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
-
- <h1>Python Module Index</h1>
-
- <div class="modindex-jumpbox">
- <a href="#cap-b"><strong>b</strong></a>
- </div>
-
- <table class="indextable modindextable" cellspacing="0" cellpadding="2">
- <tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
- <tr class="cap" id="cap-b"><td></td><td>
- <strong>b</strong></td><td></td></tr>
- <tr>
- <td></td>
- <td>
- <a href="server.html#module-browsermobproxy"><tt class="xref">browsermobproxy</tt></a></td><td>
- <em></em></td></tr>
- </table>
-
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="#" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/search.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/search.html
deleted file mode 100644
index 9adb77d91a..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/search.html
+++ /dev/null
@@ -1,105 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>Search &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <script type="text/javascript" src="_static/searchtools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="index.html" />
- <script type="text/javascript">
- jQuery(function() { Search.loadIndex("searchindex.js"); });
- </script>
-
- <script type="text/javascript" id="searchindexloader"></script>
-
-
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <h1 id="search-documentation">Search</h1>
- <div id="fallback" class="admonition warning">
- <script type="text/javascript">$('#fallback').hide();</script>
- <p>
- Please activate JavaScript to enable the search
- functionality.
- </p>
- </div>
- <p>
- From here you can search these documents. Enter your search
- words into the box below and click "search". Note that the search
- function will automatically search for all of the words. Pages
- containing fewer words won't appear in the result list.
- </p>
- <form action="" method="get">
- <input type="text" name="q" value="" />
- <input type="submit" value="search" />
- <span id="search-progress" style="padding-left: 10px"></span>
- </form>
-
- <div id="search-results">
-
- </div>
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/searchindex.js b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/searchindex.js
deleted file mode 100644
index cf2f7d0f20..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/searchindex.js
+++ /dev/null
@@ -1 +0,0 @@
-Search.setIndex({envversion:42,terms:{all:[1,2],basic_authent:1,execut:1,whitelist:1,rest:0,bandwidth:1,code:1,comma:1,kbp:1,paramet:[1,2],profil:0,configur:1,param:[],should:2,quiet_period:1,add:1,latenc:1,dict:[],blob:0,har:[0,1],pass:1,match:1,"return":[0,1],string:1,variou:1,get:[0,1,2],read:1,browsermobproxi:[0,1,2],express:1,stop:[0,2],number:1,repo:0,capturecont:1,traffic:1,upstream:1,password:1,ip_address:1,specif:1,list:1,authent:1,server:[],separ:1,retry_count:1,api:[0,1],timeout:1,each:1,through:1,unicod:1,where:1,page:[0,1],www:0,set:[1,2],captur:1,manual:0,idea:1,second:1,remap:1,connect:[1,2],domain:1,arg:2,close:1,process:2,port:[1,2],index:0,statu:1,network:1,item:2,pattern:1,content:[0,1],rewrit:1,retri:1,max:1,"import":0,ref:1,refer:1,shut:1,run:[0,2],webdriver_proxi:1,javascript:1,bodi:1,host:1,dictionari:[1,2],address:1,path:[0,2],wait:[1,2],search:0,quiet:1,against:1,initialis:[1,2],instanc:1,request_interceptor:1,rewrite_url:1,com:0,firefox:0,status_cod:1,modul:0,easy_instal:0,automat:1,down:1,header:1,"boolean":1,empti:2,wait_for_traffic_to_stop:1,regexp:1,regex:1,quit:0,given:1,git:0,from:[0,1],interact:2,json:0,been:1,avail:0,start:[0,2],live:1,basic:1,upstreamkbp:1,until:2,more:2,automatedtest:0,desir:1,option:[1,2],python:0,blacklist:1,hold:2,capturebinarycont:1,cach:1,clear_dns_cach:1,none:1,keyword:1,"default":[1,2],wish:1,setup:0,batch:2,record:1,limit:1,can:[0,2],str:[],remap_host:1,firefoxprofil:0,new_har:[0,1],"int":[],request:1,selenium_proxi:[0,1],capturehead:1,downstreamkbp:1,need:[1,2],replac:1,file:2,pip:0,create_proxi:[0,2],mai:2,downstream:1,want:1,when:1,detail:[1,2],binari:1,valid:1,lookup:1,futur:2,"new":1,you:[0,1,2],respons:1,add_to_cap:1,http:[0,1],allow:2,usernam:1,pypi:0,clone:0,object:[1,2],driver:0,what:1,firefox_profil:0,capabl:1,regular:1,set_proxi:0,associ:1,"class":[1,2],googl:0,handl:1,github:0,response_interceptor:1,url:[1,2],entri:1,clear:1,credenti:1,inform:1,client:[],thi:[1,2],new_pag:1},objtypes:{"0":"py:module","1":"py:method","2":"py:attribute","3":"py:class"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"],"3":["py","class","Python class"]},filenames:["index","client","server"],titles:["Welcome to BrowserMob Proxy&#8217;s documentation!","<tt class=\"docutils literal\"><span class=\"pre\">client</span></tt> Package","<tt class=\"docutils literal\"><span class=\"pre\">server</span></tt> Package"],objects:{"":{browsermobproxy:[2,0,0,"-"]},browsermobproxy:{Client:[1,3,1,""],Server:[2,3,1,""]},"browsermobproxy.Server":{url:[2,2,1,""],start:[2,1,1,""],stop:[2,1,1,""],create_proxy:[2,1,1,""]},"browsermobproxy.Client":{remap_hosts:[1,1,1,""],blacklist:[1,1,1,""],selenium_proxy:[1,1,1,""],response_interceptor:[1,1,1,""],webdriver_proxy:[1,1,1,""],clear_dns_cache:[1,1,1,""],timeouts:[1,1,1,""],whitelist:[1,1,1,""],new_page:[1,1,1,""],basic_authentication:[1,1,1,""],retry:[1,1,1,""],request_interceptor:[1,1,1,""],limits:[1,1,1,""],wait_for_traffic_to_stop:[1,1,1,""],rewrite_url:[1,1,1,""],close:[1,1,1,""],har:[1,2,1,""],add_to_capabilities:[1,1,1,""],headers:[1,1,1,""],new_har:[1,1,1,""]}},titleterms:{welcom:0,packag:[1,2],browsermob:0,selenium:0,webdriv:0,server:2,how:0,client:1,indic:0,tabl:0,instal:0,document:0,proxi:0}}) \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/server.html b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/server.html
deleted file mode 100644
index 74146e4ce3..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/_build/html/server.html
+++ /dev/null
@@ -1,157 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <title>server Package &mdash; BrowserMob Proxy 0.6.0 documentation</title>
-
- <link rel="stylesheet" href="_static/default.css" type="text/css" />
- <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
-
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: './',
- VERSION: '0.6.0',
- COLLAPSE_INDEX: false,
- FILE_SUFFIX: '.html',
- HAS_SOURCE: true
- };
- </script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <link rel="top" title="BrowserMob Proxy 0.6.0 documentation" href="index.html" />
- <link rel="prev" title="client Package" href="client.html" />
- </head>
- <body>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- accesskey="I">index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="client.html" title="client Package"
- accesskey="P">previous</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
-
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body">
-
- <div class="toctree-wrapper compound">
-<ul class="simple">
-</ul>
-</div>
-<div class="section" id="module-browsermobproxy">
-<span id="server-package"></span><h1><tt class="xref py py-mod docutils literal"><span class="pre">server</span></tt> Package<a class="headerlink" href="#module-browsermobproxy" title="Permalink to this headline">¶</a></h1>
-<dl class="class">
-<dt id="browsermobproxy.Server">
-<em class="property">class </em><tt class="descclassname">browsermobproxy.</tt><tt class="descname">Server</tt><big>(</big><em>path='browsermob-proxy'</em>, <em>options={}</em><big>)</big><a class="headerlink" href="#browsermobproxy.Server" title="Permalink to this definition">¶</a></dt>
-<dd><p>Initialises a Server object</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Args:</th><td class="field-body"></td>
-</tr>
-<tr class="field-even field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>path</strong> &#8211; Path to the browsermob proxy batch file</li>
-<li><strong>options</strong> &#8211; Dictionary that can hold the port. More items will be added in the future. This defaults to an empty dictionary</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="browsermobproxy.Server.create_proxy">
-<tt class="descname">create_proxy</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Server.create_proxy" title="Permalink to this definition">¶</a></dt>
-<dd><p>Gets a client class that allow to set all the proxy details that you
-may need to.</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Server.start">
-<tt class="descname">start</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Server.start" title="Permalink to this definition">¶</a></dt>
-<dd><p>This will start the browsermob proxy and then wait until it can
-interact with it</p>
-</dd></dl>
-
-<dl class="method">
-<dt id="browsermobproxy.Server.stop">
-<tt class="descname">stop</tt><big>(</big><big>)</big><a class="headerlink" href="#browsermobproxy.Server.stop" title="Permalink to this definition">¶</a></dt>
-<dd><p>This will stop the process running the proxy</p>
-</dd></dl>
-
-<dl class="attribute">
-<dt id="browsermobproxy.Server.url">
-<tt class="descname">url</tt><a class="headerlink" href="#browsermobproxy.Server.url" title="Permalink to this definition">¶</a></dt>
-<dd><p>Gets the url that the proxy is running on. This is not the URL clients
-should connect to.</p>
-</dd></dl>
-
-</dd></dl>
-
-</div>
-
-
- </div>
- </div>
- </div>
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- <h4>Previous topic</h4>
- <p class="topless"><a href="client.html"
- title="previous chapter"><tt class="docutils literal"><span class="pre">client</span></tt> Package</a></p>
- <h3>This Page</h3>
- <ul class="this-page-menu">
- <li><a href="_sources/server.txt"
- rel="nofollow">Show Source</a></li>
- </ul>
-<div id="searchbox" style="display: none">
- <h3>Quick search</h3>
- <form class="search" action="search.html" method="get">
- <input type="text" name="q" />
- <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- Enter search terms or a module, class or function name.
- </p>
-</div>
-<script type="text/javascript">$('#searchbox').show(0);</script>
- </div>
- </div>
- <div class="clearer"></div>
- </div>
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- <li class="right" style="margin-right: 10px">
- <a href="genindex.html" title="General Index"
- >index</a></li>
- <li class="right" >
- <a href="py-modindex.html" title="Python Module Index"
- >modules</a> |</li>
- <li class="right" >
- <a href="client.html" title="client Package"
- >previous</a> |</li>
- <li><a href="index.html">BrowserMob Proxy 0.6.0 documentation</a> &raquo;</li>
- </ul>
- </div>
- <div class="footer">
- &copy; Copyright 2014, David Burns.
- Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
- </div>
- </body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/client.rst b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/client.rst
deleted file mode 100644
index 95c74fa9f3..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/client.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. toctree::
- :maxdepth: 2
-
-:mod:`client` Package
----------------------
-.. automodule:: browsermobproxy
-.. autoclass:: Client
- :members:
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/conf.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/conf.py
deleted file mode 100644
index 961c489073..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/conf.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# BrowserMob Proxy documentation build configuration file, created by
-# sphinx-quickstart on Fri May 24 12:37:12 2013.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc']
-autoclass_content = 'both'
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'BrowserMob Proxy'
-copyright = u'2014, David Burns'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.6.0'
-# The full version, including alpha/beta/rc tags.
-release = '0.6.0'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'BrowserMobProxydoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'BrowserMobProxy.tex', u'BrowserMob Proxy Documentation',
- u'David Burns', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'browsermobproxy', u'BrowserMob Proxy Documentation',
- [u'David Burns'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'BrowserMobProxy', u'BrowserMob Proxy Documentation',
- u'David Burns', 'BrowserMobProxy', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/index.rst b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/index.rst
deleted file mode 100644
index 0a568cf643..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/index.rst
+++ /dev/null
@@ -1,72 +0,0 @@
-.. BrowserMob Proxy documentation master file, created by
- sphinx-quickstart on Fri May 24 12:37:12 2013.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-.. highlightlang:: python
-
-
-
-Welcome to BrowserMob Proxy's documentation!
-============================================
-
-Python client for the BrowserMob Proxy 2.0 REST API.
-
-How to install
---------------
-
-BrowserMob Proxy is available on PyPI_, so you can install it with ``pip``::
-
- $ pip install browsermob-proxy
-
-Or with `easy_install`::
-
- $ easy_install browsermob-proxy
-
-Or by cloning the repo from GitHub_::
-
- $ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git
-
-Then install it by running::
-
- $ python setup.py install
-
-How to use with selenium-webdriver
-----------------------------------
-
-Manually::
-
- from browsermobproxy import Server
- server = Server("path/to/browsermob-proxy")
- server.start()
- proxy = server.create_proxy()
-
- from selenium import webdriver
- profile = webdriver.FirefoxProfile()
- profile.set_proxy(proxy.selenium_proxy())
- driver = webdriver.Firefox(firefox_profile=profile)
-
-
- proxy.new_har("google")
- driver.get("http://www.google.co.uk")
- proxy.har # returns a HAR JSON blob
-
- server.stop()
- driver.quit()
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- client.rst
- server.rst
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
-.. _GitHub: https://github.com/AutomatedTester/browsermob-proxy-py
-.. _PyPI: http://pypi.python.org/pypi/browsermob-proxy
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/make.bat b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/make.bat
deleted file mode 100644
index 567b0da4a0..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/make.bat
+++ /dev/null
@@ -1,190 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\BrowserMobProxy.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\BrowserMobProxy.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/server.rst b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/server.rst
deleted file mode 100644
index 8af94b70a6..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/docs/server.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. toctree::
- :maxdepth: 2
-
-:mod:`server` Package
----------------------
-.. automodule:: browsermobproxy
-.. autoclass:: Server
- :members: \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/readme.md b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/readme.md
deleted file mode 100644
index 913610f662..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/readme.md
+++ /dev/null
@@ -1,88 +0,0 @@
-browsermob-proxy-py
-===================
-
-Python client for the BrowserMob Proxy 2.0 REST API.
-
-
-
-How to use with selenium-webdriver
-----------------------------------
-
-Manually:
-
-``` python
-from browsermobproxy import Server
-server = Server("path/to/browsermob-proxy")
-server.start()
-proxy = server.create_proxy()
-
-from selenium import webdriver
-profile = webdriver.FirefoxProfile()
-profile.set_proxy(proxy.selenium_proxy())
-driver = webdriver.Firefox(firefox_profile=profile)
-
-
-proxy.new_har("google")
-driver.get("http://www.google.co.uk")
-proxy.har # returns a HAR JSON blob
-
-server.stop()
-driver.quit()
-
-```
-
-for Chrome use
-
-```
-chrome_options = webdriver.ChromeOptions()
-chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy))
-browser = webdriver.Chrome(chrome_options = chrome_options)
-```
-
-Running Tests
--------------
-To run the tests in a CI environment, disable the ones that require human
-judgement by using
-
-```bash
-$ py.test -m "not human" test
-```
-
-If you are going to watch the test, the 'human' ones should display an english
-muffin instead of the american flag on the 'pick your version' page. Or at
-least it does from Canada.
-
-
-See also
---------
-
-* http://proxy.browsermob.com/
-* https://github.com/webmetrics/browsermob-proxy
-
-Note on Patches/Pull Requests
------------------------------
-
-* Fork the project.
-* Make your feature addition or bug fix.
-* Add tests for it. This is important so I don't break it in a
- future version unintentionally.
-* Send me a pull request. Bonus points for topic branches.
-
-Copyright
----------
-
-Copyright 2011 David Burns
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/setup.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/setup.py
deleted file mode 100644
index f6581cf081..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/setup.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from setuptools import setup, find_packages
-
-setup(name='browsermob-proxy',
- version='0.6.0',
- description='A library for interacting with the Browsermob Proxy',
- author='David Burns',
- author_email='david.burns at theautomatedtester dot co dot uk',
- url='http://oss.theautomatedtester.co.uk/browsermob-proxy-py',
- classifiers=['Development Status :: 3 - Alpha',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Apache Software License',
- 'Operating System :: POSIX',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: MacOS :: MacOS X',
- 'Topic :: Software Development :: Testing',
- 'Topic :: Software Development :: Libraries',
- 'Programming Language :: Python'],
- packages = find_packages(),
- install_requires=['requests>=1.1.0'],
- )
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_client.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_client.py
deleted file mode 100644
index 8968b103fc..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_client.py
+++ /dev/null
@@ -1,247 +0,0 @@
-import os.path
-import pytest
-import sys
-
-
-def setup_module(module):
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
-class TestClient(object):
- def setup_method(self, method):
- from browsermobproxy.client import Client
- self.client = Client("localhost:9090")
-
- def teardown_method(self, method):
- self.client.close()
-
- def test_headers_type(self):
- """
- /proxy/:port/headers needs to take a dictionary
- """
- with pytest.raises(TypeError):
- self.client.headers(['foo'])
-
- def test_headers_content(self):
- """
- /proxy/:port/headers needs to take a dictionary
- and returns 200 when its successful
- """
- s = self.client.headers({'User-Agent': 'rubber ducks floating in a row'})
- assert(s == 200)
-
- def test_new_har(self):
- """
- /proxy/:port/har
- and returns 204 when creating a har with a particular name the first time
- and returns 200 and the previous har when creating one with the same name
- """
- status_code, har = self.client.new_har()
- assert(status_code == 204)
- assert(har is None)
- status_code, har = self.client.new_har()
- assert(status_code == 200)
- assert('log' in har)
-
- def test_new_har(self):
- """
- /proxy/:port/har
- and returns 204 when creating a har with a particular name the first time
- and returns 200 and the previous har when creating one with the same name
- """
- status_code, har = self.client.new_har("elephants")
- assert(status_code == 204)
- assert(har is None)
- status_code, har = self.client.new_har("elephants")
- assert(status_code == 200)
- assert('elephants' == har["log"]["pages"][0]['id'])
-
- def test_new_page_defaults(self):
- """
- /proxy/:port/pageRef
- adds a new page of 'Page N' when no page name is given
- """
- self.client.new_har()
- self.client.new_page()
- har = self.client.har
- assert(len(har["log"]["pages"]) == 2)
- assert(har["log"]["pages"][1]["id"] == "Page 2")
-
- def test_new_named_page(self):
- """
- /proxy/:port/pageRef
- adds a new page of 'buttress'
- """
- self.client.new_har()
- self.client.new_page('buttress')
- har = self.client.har
- assert(len(har["log"]["pages"]) == 2)
- assert(har["log"]["pages"][1]["id"] == "buttress")
-
- def test_single_whitelist(self):
- """
- /proxy/:port/whitelist
- adds a whitelist
- """
- status_code = self.client.whitelist("http://www\\.facebook\\.com/.*", 200)
- assert(status_code == 200)
-
- def test_multiple_whitelists(self):
- """
- /proxy/:port/whitelist
- adds a whitelist
- """
- status_code = self.client.whitelist("http://www\\.facebook\\.com/.*,http://cdn\\.twitter\\.com", 200)
- assert(status_code == 200)
-
- def test_blacklist(self):
- """
- /proxy/:port/blacklist
- adds a blacklist
- """
- status_code = self.client.blacklist("http://www\\.facebook\\.com/.*", 200)
- assert(status_code == 200)
-
- def test_basic_authentication(self):
- """
- /proxy/:port/auth/basic
- adds automatic basic authentication
- """
- status_code = self.client.basic_authentication("www.example.com", "myUsername", "myPassword")
- assert(status_code == 200)
-
- def test_limits_invalid_key(self):
- """
- /proxy/:port/limits
- pre-sending checking that the parameter is correct
- """
- with pytest.raises(KeyError):
- self.client.limits({"hurray": "explosions"})
-
- def test_limits_key_no_value(self):
- """
- /proxy/:port/limits
- pre-sending checking that a parameter exists
- """
- with pytest.raises(KeyError):
- self.client.limits({})
-
- def test_limits_all_key_values(self):
- """
- /proxy/:port/limits
- can send all 3 at once based on the proxy implementation
- """
- limits = {"upstream_kbps": 320, "downstream_kbps": 560, "latency": 30}
- status_code = self.client.limits(limits)
- assert(status_code == 200)
-
- def test_rewrite(self):
- """
- /proxy/:port/rewrite
-
- """
- match = "/foo"
- replace = "/bar"
- status_code = self.client.rewrite_url(match, replace)
- assert(status_code == 200)
-
- def test_close(self):
- """
- /proxy/:port
- close the proxy port
- """
- status_code = self.client.close()
- assert(status_code == 200)
- status_code = self.client.close()
- assert(status_code == 404)
-
- def test_response_interceptor_with_parsing_js(self):
- """
- /proxy/:port/interceptor/response
- """
- js = 'alert("foo")'
- status_code = self.client.response_interceptor(js)
- assert(status_code == 200)
-
- def test_response_interceptor_with_invalid_js(self):
- """
- /proxy/:port/interceptor/response
- """
- js = 'alert("foo"'
- status_code = self.client.response_interceptor(js)
- assert(status_code == 500)
-
- def test_request_interceptor_with_parsing_js(self):
- """
- /proxy/:port/interceptor/request
- """
- js = 'alert("foo")'
- status_code = self.client.request_interceptor(js)
- assert(status_code == 200)
-
- def test_request_interceptor_with_invalid_js(self):
- """
- /proxy/:port/interceptor/request
- """
- js = 'alert("foo"'
- status_code = self.client.request_interceptor(js)
- assert(status_code == 500)
-
- def test_timeouts_invalid_timeouts(self):
- """
- /proxy/:port/timeout
- pre-sending checking that the parameter is correct
- """
- with pytest.raises(KeyError):
- self.client.timeouts({"hurray": "explosions"})
-
- def test_timeouts_key_no_value(self):
- """
- /proxy/:port/timeout
- pre-sending checking that a parameter exists
- """
- with pytest.raises(KeyError):
- self.client.timeouts({})
-
- def test_timeouts_all_key_values(self):
- """
- /proxy/:port/timeout
- can send all 3 at once based on the proxy implementation
- """
- timeouts = {"request": 2, "read": 2, "connection": 2, "dns": 3}
- status_code = self.client.timeouts(timeouts)
- assert(status_code == 200)
-
- def test_remap_hosts(self):
- """
- /proxy/:port/hosts
- """
- status_code = self.client.remap_hosts("example.com", "1.2.3.4")
- assert(status_code == 200)
-
- def test_wait_for_traffic_to_stop(self):
- """
- /proxy/:port/wait
- """
- status_code = self.client.wait_for_traffic_to_stop(2000, 10000)
- assert(status_code == 200)
-
- def test_clear_dns_cache(self):
- """
- /proxy/:port/dns/cache
- """
- status_code = self.client.clear_dns_cache()
- assert(status_code == 200)
-
- def test_rewrite_url(self):
- """
- /proxy/:port/rewrite
- """
- status_code = self.client.rewrite_url('http://www.facebook\.com', 'http://microsoft.com')
- assert(status_code == 200)
-
- def test_retry(self):
- """
- /proxy/:port/retry
- """
- status_code = self.client.retry(4)
- assert(status_code == 200)
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_remote.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_remote.py
deleted file mode 100644
index 9a002f1090..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_remote.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from selenium import webdriver
-import selenium.webdriver.common.desired_capabilities
-import os
-import sys
-import time
-import pytest
-
-def setup_module(module):
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
-class TestRemote(object):
- def setup_method(self, method):
- from browsermobproxy.client import Client
- self.client = Client("localhost:9090")
-
- def teardown_method(self, method):
- self.client.close()
-
- @pytest.mark.human
- def test_i_want_my_remote(self):
- driver = webdriver.Remote(desired_capabilities=selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX,
- proxy=self.client)
-
- self.client.new_har("mtv")
- targetURL = "http://www.mtv.com"
- self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
-
- driver.get(targetURL)
- time.sleep(5)
-
- driver.quit()
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_webdriver.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_webdriver.py
deleted file mode 100644
index 4a35e7162c..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py/test/test_webdriver.py
+++ /dev/null
@@ -1,60 +0,0 @@
-from selenium import webdriver
-import selenium.webdriver.common.desired_capabilities
-from selenium.webdriver.common.proxy import Proxy
-import os
-import sys
-import copy
-import time
-import pytest
-
-def setup_module(module):
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
-class TestWebDriver(object):
- def setup_method(self, method):
- from browsermobproxy.client import Client
- self.client = Client("localhost:9090")
-
- def teardown_method(self, method):
- self.client.close()
-
- @pytest.mark.human
- def test_i_want_my_by_capability(self):
- capabilities = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX
- self.client.add_to_capabilities(capabilities)
- driver = webdriver.Firefox(capabilities=capabilities)
-
- self.client.new_har("mtv")
- targetURL = "http://www.mtv.com"
- self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
-
- driver.get(targetURL)
-
- time.sleep(5)
-
- driver.quit()
-
- @pytest.mark.human
- def test_i_want_my_by_proxy_object(self):
- driver = webdriver.Firefox(proxy=self.client)
-
- self.client.new_har("mtv")
- targetURL = "http://www.mtv.com"
- self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
-
- driver.get(targetURL)
-
- time.sleep(5)
-
- driver.quit()
-
- def test_what_things_look_like(self):
- bmp_capabilities = copy.deepcopy(selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX)
- self.client.add_to_capabilities(bmp_capabilities)
-
- proxy_capabilities = copy.deepcopy(selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX)
- proxy_addr = 'localhost:{}'.format(self.client.port)
- proxy = Proxy({'httpProxy': proxy_addr,'sslProxy': proxy_addr})
- proxy.add_to_capabilities(proxy_capabilities)
-
- assert bmp_capabilities == proxy_capabilities
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob.py b/testing/marionette/harness/marionette_harness/runner/mixins/browsermob.py
deleted file mode 100644
index e4c3cb5454..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/browsermob.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# 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 browsermobproxy import Server
-from marionette_harness import MarionetteTestCase
-
-
-class BrowserMobProxyArguments(object):
- name = 'Browsermob Proxy'
- args = [
- [['--browsermob-script'],
- {'help': 'path to the browsermob-proxy shell script or batch file',
- }],
- [['--browsermob-port'],
- {'type': int,
- 'help': 'port to run the browsermob proxy on',
- }],
- ]
-
- def verify_usage_handler(self, args):
- if args.browsermob_script is not None:
- if not os.path.exists(args.browsermob_script):
- raise ValueError('{} not found'.format(args.browsermob_script))
-
-
-class BrowserMobProxyTestCaseMixin(object):
-
- def __init__(self, *args, **kwargs):
- self.browsermob_server = None
- self.browsermob_port = kwargs.pop('browsermob_port')
- self.browsermob_script = kwargs.pop('browsermob_script')
-
- def setUp(self):
- options = {}
- if self.browsermob_port:
- options['port'] = self.browsermob_port
- if not self.browsermob_script:
- raise ValueError('Must specify --browsermob-script in order to '
- 'run browsermobproxy tests')
- self.browsermob_server = Server(
- self.browsermob_script, options=options)
- self.browsermob_server.start()
-
- def create_browsermob_proxy(self):
- client = self.browsermob_server.create_proxy()
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Preferences.jsm");
- Preferences.set("network.proxy.type", 1);
- Preferences.set("network.proxy.http", "localhost");
- Preferences.set("network.proxy.http_port", {port});
- Preferences.set("network.proxy.ssl", "localhost");
- Preferences.set("network.proxy.ssl_port", {port});
- """.format(port=client.port))
- return client
-
- def tearDown(self):
- if self.browsermob_server:
- self.browsermob_server.stop()
- self.browsermob_server = None
-
- __del__ = tearDown
-
-
-class BrowserMobTestCase(MarionetteTestCase, BrowserMobProxyTestCaseMixin):
-
- def __init__(self, *args, **kwargs):
- MarionetteTestCase.__init__(self, *args, **kwargs)
- BrowserMobProxyTestCaseMixin.__init__(self, *args, **kwargs)
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- BrowserMobProxyTestCaseMixin.setUp(self)
-
- def tearDown(self):
- BrowserMobProxyTestCaseMixin.tearDown(self)
- MarionetteTestCase.tearDown(self)
diff --git a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
deleted file mode 100644
index 4316c75d74..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# 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 sys
-
-from marionette_driver import By, Wait
-
-
-class WindowManagerMixin(object):
-
- _menu_item_new_tab = (By.ID, "menu_newNavigatorTab")
-
- def setUp(self):
- super(WindowManagerMixin, self).setUp()
-
- self.start_window = self.marionette.current_chrome_window_handle
- self.start_windows = self.marionette.chrome_window_handles
-
- self.start_tab = self.marionette.current_window_handle
- self.start_tabs = self.marionette.window_handles
-
- def tearDown(self):
- if len(self.marionette.chrome_window_handles) != len(self.start_windows):
- raise Exception("Not all windows as opened by the test have been closed")
-
- if len(self.marionette.window_handles) != len(self.start_tabs):
- raise Exception("Not all tabs as opened by the test have been closed")
-
- super(WindowManagerMixin, self).tearDown()
-
- def close_all_tabs(self):
- current_window_handles = self.marionette.window_handles
-
- # If the start tab is not present anymore, use the next one of the list
- if self.start_tab not in current_window_handles:
- self.start_tab = current_window_handles[0]
-
- current_window_handles.remove(self.start_tab)
- for handle in current_window_handles:
- self.marionette.switch_to_window(handle)
- self.marionette.close()
-
- # Bug 1311350 - close() doesn't wait for tab to be closed.
- Wait(self.marionette).until(
- lambda mn: handle not in mn.window_handles,
- message="Failed to close tab with handle {}".format(handle)
- )
-
- self.marionette.switch_to_window(self.start_tab)
-
- def close_all_windows(self):
- current_chrome_window_handles = self.marionette.chrome_window_handles
-
- # If the start window is not present anymore, use the next one of the list
- if self.start_window not in current_chrome_window_handles:
- self.start_window = current_chrome_window_handles[0]
- current_chrome_window_handles.remove(self.start_window)
-
- with self.marionette.using_context("chrome"):
- for handle in current_chrome_window_handles:
- self.marionette.switch_to_window(handle)
- self.marionette.close_chrome_window()
-
- # Bug 1311350 - close_chrome_window() doesn't wait for window to be closed.
- Wait(self.marionette).until(
- lambda mn: handle not in mn.chrome_window_handles,
- message="Failed to close window with handle {}".format(handle)
- )
-
- self.marionette.switch_to_window(self.start_window)
-
- def open_tab(self, trigger="menu"):
- current_tabs = self.marionette.window_handles
-
- try:
- if callable(trigger):
- trigger()
- elif trigger == 'menu':
- with self.marionette.using_context("chrome"):
- self.marionette.find_element(*self._menu_item_new_tab).click()
- except Exception:
- exc, val, tb = sys.exc_info()
- raise exc, 'Failed to trigger opening a new tab: {}'.format(val), tb
- else:
- Wait(self.marionette).until(
- lambda mn: len(mn.window_handles) == len(current_tabs) + 1,
- message="No new tab has been opened"
- )
-
- [new_tab] = list(set(self.marionette.window_handles) - set(current_tabs))
-
- return new_tab
-
- def open_window(self, trigger=None):
- current_windows = self.marionette.chrome_window_handles
-
- def loaded(handle):
- with self.marionette.using_context("chrome"):
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- let win = Services.wm.getOuterWindowWithId(Number(arguments[0]));
- return win.document.readyState == "complete";
- """, script_args=[handle])
-
- try:
- if callable(trigger):
- trigger()
- else:
- with self.marionette.using_context("chrome"):
- self.marionette.execute_script("window.open();")
- except Exception:
- exc, val, tb = sys.exc_info()
- raise exc, 'Failed to trigger opening a new window: {}'.format(val), tb
- else:
- Wait(self.marionette).until(
- lambda mn: len(mn.chrome_window_handles) == len(current_windows) + 1,
- message="No new window has been opened"
- )
-
- [new_window] = list(set(self.marionette.chrome_window_handles) - set(current_windows))
-
- # Before continuing ensure the window has been completed loading
- Wait(self.marionette).until(
- lambda _: loaded(new_window),
- message="Window with handle '{}'' did not finish loading".format(new_window))
-
- return new_window
diff --git a/testing/marionette/harness/marionette_harness/runner/serve.py b/testing/marionette/harness/marionette_harness/runner/serve.py
deleted file mode 100755
index 1969c91709..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/serve.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/env python
-
-# 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/.
-
-"""Spawns necessary HTTP servers for testing Marionette in child
-processes.
-
-"""
-
-import argparse
-import multiprocessing
-import os
-import sys
-
-from collections import defaultdict
-
-import httpd
-
-
-__all__ = ["default_doc_root",
- "iter_proc",
- "iter_url",
- "registered_servers",
- "servers",
- "start",
- "where_is"]
-here = os.path.abspath(os.path.dirname(__file__))
-
-
-class BlockingChannel(object):
-
- def __init__(self, channel):
- self.chan = channel
- self.lock = multiprocessing.Lock()
-
- def call(self, func, args=()):
- self.send((func, args))
- return self.recv()
-
- def send(self, *args):
- try:
- self.lock.acquire()
- self.chan.send(args)
- finally:
- self.lock.release()
-
- def recv(self):
- try:
- self.lock.acquire()
- payload = self.chan.recv()
- if isinstance(payload, tuple) and len(payload) == 1:
- return payload[0]
- return payload
- except KeyboardInterrupt:
- return ("stop", ())
- finally:
- self.lock.release()
-
-
-class ServerProxy(multiprocessing.Process, BlockingChannel):
-
- def __init__(self, channel, init_func, *init_args, **init_kwargs):
- multiprocessing.Process.__init__(self)
- BlockingChannel.__init__(self, channel)
- self.init_func = init_func
- self.init_args = init_args
- self.init_kwargs = init_kwargs
-
- def run(self):
- server = self.init_func(*self.init_args, **self.init_kwargs)
- server.start(block=False)
-
- try:
- while True:
- # ["func", ("arg", ...)]
- # ["prop", ()]
- sattr, fargs = self.recv()
- attr = getattr(server, sattr)
-
- # apply fargs to attr if it is a function
- if callable(attr):
- rv = attr(*fargs)
-
- # otherwise attr is a property
- else:
- rv = attr
-
- self.send(rv)
-
- if sattr == "stop":
- return
-
- except KeyboardInterrupt:
- server.stop()
-
-
-class ServerProc(BlockingChannel):
-
- def __init__(self, init_func):
- self._init_func = init_func
- self.proc = None
-
- parent_chan, self.child_chan = multiprocessing.Pipe()
- BlockingChannel.__init__(self, parent_chan)
-
- def start(self, doc_root, ssl_config, **kwargs):
- self.proc = ServerProxy(
- self.child_chan, self._init_func, doc_root, ssl_config, **kwargs)
- self.proc.daemon = True
- self.proc.start()
-
- def get_url(self, url):
- return self.call("get_url", (url,))
-
- @property
- def doc_root(self):
- return self.call("doc_root", ())
-
- def stop(self):
- self.call("stop")
- if not self.is_alive:
- return
- self.proc.join()
-
- def kill(self):
- if not self.is_alive:
- return
- self.proc.terminate()
- self.proc.join(0)
-
- @property
- def is_alive(self):
- if self.proc is not None:
- return self.proc.is_alive()
- return False
-
-
-def http_server(doc_root, ssl_config, host="127.0.0.1", **kwargs):
- return httpd.FixtureServer(doc_root, url="http://{}:0/".format(host), **kwargs)
-
-
-def https_server(doc_root, ssl_config, host="127.0.0.1", **kwargs):
- return httpd.FixtureServer(doc_root,
- url="https://{}:0/".format(host),
- ssl_key=ssl_config["key_path"],
- ssl_cert=ssl_config["cert_path"],
- **kwargs)
-
-
-def start_servers(doc_root, ssl_config, **kwargs):
- servers = defaultdict()
- for schema, builder_fn in registered_servers:
- proc = ServerProc(builder_fn)
- proc.start(doc_root, ssl_config, **kwargs)
- servers[schema] = (proc.get_url("/"), proc)
- return servers
-
-
-def start(doc_root=None, **kwargs):
- """Start all relevant test servers.
-
- If no `doc_root` is given the default
- testing/marionette/harness/marionette_harness/www directory will be used.
-
- Additional keyword arguments can be given which will be passed on
- to the individual ``FixtureServer``'s in httpd.py.
-
- """
- doc_root = doc_root or default_doc_root
- ssl_config = {"cert_path": httpd.default_ssl_cert,
- "key_path": httpd.default_ssl_key}
-
- global servers
- servers = start_servers(doc_root, ssl_config, **kwargs)
- return servers
-
-
-def where_is(uri, on="http"):
- """Returns the full URL, including scheme, hostname, and port, for
- a fixture resource from the server associated with the ``on`` key.
- It will by default look for the resource in the "http" server.
-
- """
- return servers.get(on)[1].get_url(uri)
-
-
-def iter_proc(servers):
- for _, (_, proc) in servers.iteritems():
- yield proc
-
-
-def iter_url(servers):
- for _, (url, _) in servers.iteritems():
- yield url
-
-
-default_doc_root = os.path.join(os.path.dirname(here), "www")
-registered_servers = [("http", http_server),
- ("https", https_server)]
-servers = defaultdict()
-
-
-def main(args):
- global servers
-
- parser = argparse.ArgumentParser()
- parser.add_argument("-r", dest="doc_root",
- help="Path to document root. Overrides default.")
- args = parser.parse_args()
-
- servers = start(args.doc_root)
- for url in iter_url(servers):
- print >>sys.stderr, "{}: listening on {}".format(sys.argv[0], url)
-
- try:
- while any(proc.is_alive for proc in iter_proc(servers)):
- for proc in iter_proc(servers):
- proc.proc.join(1)
- except KeyboardInterrupt:
- for proc in iter_proc(servers):
- proc.kill()
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])
diff --git a/testing/marionette/harness/marionette_harness/runner/test.cert b/testing/marionette/harness/marionette_harness/runner/test.cert
deleted file mode 100644
index 3fd1cba2b7..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/test.cert
+++ /dev/null
@@ -1,86 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=web-platform-tests
- Validity
- Not Before: Dec 22 12:09:16 2014 GMT
- Not After : Dec 21 12:09:16 2024 GMT
- Subject: CN=web-platform.test
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b3:84:d6:8b:01:59:18:85:d1:dc:32:df:38:f7:
- 90:85:1b:3e:a5:5e:81:3e:2f:fc:3a:5f:7f:77:ef:
- 23:bb:3a:88:27:0f:be:25:46:cd:63:7d:cb:95:d8:
- a5:50:10:d2:a2:d2:b7:97:d1:0d:6c:fb:f9:05:e8:
- 6f:a8:4b:bd:95:67:9e:7b:94:58:a9:6d:93:fd:e0:
- 12:c5:cd:b4:8a:64:52:31:5f:0e:e3:89:84:71:da:
- 98:dd:4b:ec:02:25:a5:7d:35:fe:63:da:b3:ac:ec:
- a5:46:0f:0d:64:23:5c:6d:f3:ec:cc:28:63:23:c0:
- 4b:9a:ec:8f:c1:ee:b1:a2:3e:72:4d:70:b5:09:c1:
- eb:b4:10:55:3c:8b:ea:1b:94:7e:4b:74:e6:f4:9f:
- 4f:a6:45:30:b5:f0:b8:b4:d1:59:50:65:0a:86:53:
- ea:4c:9f:9e:f4:58:6c:31:f5:17:3a:6f:57:8b:cb:
- 5f:f0:28:0b:45:92:8d:30:20:49:ff:52:e6:2c:cb:
- 18:9a:d7:e6:ee:3e:4f:34:35:15:13:c5:02:da:c5:
- 5f:be:fb:5b:ce:8d:bf:b5:35:76:3c:7c:e6:9c:3b:
- 26:87:4d:8d:80:e6:16:c6:27:f2:50:49:b6:72:74:
- 43:49:49:44:38:bb:78:43:23:ee:16:3e:d9:62:e6:
- a5:d7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- X509v3 Subject Key Identifier:
- 2D:98:A3:99:39:1C:FE:E9:9A:6D:17:94:D2:3A:96:EE:C8:9E:04:22
- X509v3 Authority Key Identifier:
- keyid:6A:AB:53:64:92:36:87:23:34:B3:1D:6F:85:4B:F5:DF:5A:5C:74:8F
-
- X509v3 Key Usage:
- Digital Signature, Non Repudiation, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication
- X509v3 Subject Alternative Name:
- DNS:web-platform.test, DNS:www.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www2.web-platform.test, DNS:www1.web-platform.test
- Signature Algorithm: sha256WithRSAEncryption
- 33:db:f7:f0:f6:92:16:4f:2d:42:bc:b8:aa:e6:ab:5e:f9:b9:
- b0:48:ae:b5:8d:cc:02:7b:e9:6f:4e:75:f7:17:a0:5e:7b:87:
- 06:49:48:83:c5:bb:ca:95:07:37:0e:5d:e3:97:de:9e:0c:a4:
- 82:30:11:81:49:5d:50:29:72:92:a5:ca:17:b1:7c:f1:32:11:
- 17:57:e6:59:c1:ac:e3:3b:26:d2:94:97:50:6a:b9:54:88:84:
- 9b:6f:b1:06:f5:80:04:22:10:14:b1:f5:97:25:fc:66:d6:69:
- a3:36:08:85:23:ff:8e:3c:2b:e0:6d:e7:61:f1:00:8f:61:3d:
- b0:87:ad:72:21:f6:f0:cc:4f:c9:20:bf:83:11:0f:21:f4:b8:
- c0:dd:9c:51:d7:bb:27:32:ec:ab:a4:62:14:28:32:da:f2:87:
- 80:68:9c:ea:ac:eb:f5:7f:f5:de:f4:c0:39:91:c8:76:a4:ee:
- d0:a8:50:db:c1:4b:f9:c4:3d:d9:e8:8e:b6:3f:c0:96:79:12:
- d8:fa:4d:0a:b3:36:76:aa:4e:b2:82:2f:a2:d4:0d:db:fd:64:
- 77:6f:6e:e9:94:7f:0f:c8:3a:3c:96:3d:cd:4d:6c:ba:66:95:
- f7:b4:9d:a4:94:9f:97:b3:9a:0d:dc:18:8c:11:0b:56:65:8e:
- 46:4c:e6:5e
------BEGIN CERTIFICATE-----
-MIID2jCCAsKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJ3ZWIt
-cGxhdGZvcm0tdGVzdHMwHhcNMTQxMjIyMTIwOTE2WhcNMjQxMjIxMTIwOTE2WjAc
-MRowGAYDVQQDExF3ZWItcGxhdGZvcm0udGVzdDCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALOE1osBWRiF0dwy3zj3kIUbPqVegT4v/Dpff3fvI7s6iCcP
-viVGzWN9y5XYpVAQ0qLSt5fRDWz7+QXob6hLvZVnnnuUWKltk/3gEsXNtIpkUjFf
-DuOJhHHamN1L7AIlpX01/mPas6zspUYPDWQjXG3z7MwoYyPAS5rsj8HusaI+ck1w
-tQnB67QQVTyL6huUfkt05vSfT6ZFMLXwuLTRWVBlCoZT6kyfnvRYbDH1FzpvV4vL
-X/AoC0WSjTAgSf9S5izLGJrX5u4+TzQ1FRPFAtrFX777W86Nv7U1djx85pw7JodN
-jYDmFsYn8lBJtnJ0Q0lJRDi7eEMj7hY+2WLmpdcCAwEAAaOCASQwggEgMAkGA1Ud
-EwQCMAAwHQYDVR0OBBYEFC2Yo5k5HP7pmm0XlNI6lu7IngQiMB8GA1UdIwQYMBaA
-FGqrU2SSNocjNLMdb4VL9d9aXHSPMAsGA1UdDwQEAwIF4DATBgNVHSUEDDAKBggr
-BgEFBQcDATCBsAYDVR0RBIGoMIGlghF3ZWItcGxhdGZvcm0udGVzdIIVd3d3Lndl
-Yi1wbGF0Zm9ybS50ZXN0gil4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxh
-dGZvcm0udGVzdIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0ghZ3d3cy
-LndlYi1wbGF0Zm9ybS50ZXN0ghZ3d3cxLndlYi1wbGF0Zm9ybS50ZXN0MA0GCSqG
-SIb3DQEBCwUAA4IBAQAz2/fw9pIWTy1CvLiq5qte+bmwSK61jcwCe+lvTnX3F6Be
-e4cGSUiDxbvKlQc3Dl3jl96eDKSCMBGBSV1QKXKSpcoXsXzxMhEXV+ZZwazjOybS
-lJdQarlUiISbb7EG9YAEIhAUsfWXJfxm1mmjNgiFI/+OPCvgbedh8QCPYT2wh61y
-IfbwzE/JIL+DEQ8h9LjA3ZxR17snMuyrpGIUKDLa8oeAaJzqrOv1f/Xe9MA5kch2
-pO7QqFDbwUv5xD3Z6I62P8CWeRLY+k0KszZ2qk6ygi+i1A3b/WR3b27plH8PyDo8
-lj3NTWy6ZpX3tJ2klJ+Xs5oN3BiMEQtWZY5GTOZe
------END CERTIFICATE----- \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runner/test.key b/testing/marionette/harness/marionette_harness/runner/test.key
deleted file mode 100644
index 194a49ec42..0000000000
--- a/testing/marionette/harness/marionette_harness/runner/test.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCzhNaLAVkYhdHc
-Mt8495CFGz6lXoE+L/w6X3937yO7OognD74lRs1jfcuV2KVQENKi0reX0Q1s+/kF
-6G+oS72VZ557lFipbZP94BLFzbSKZFIxXw7jiYRx2pjdS+wCJaV9Nf5j2rOs7KVG
-Dw1kI1xt8+zMKGMjwEua7I/B7rGiPnJNcLUJweu0EFU8i+oblH5LdOb0n0+mRTC1
-8Li00VlQZQqGU+pMn570WGwx9Rc6b1eLy1/wKAtFko0wIEn/UuYsyxia1+buPk80
-NRUTxQLaxV+++1vOjb+1NXY8fOacOyaHTY2A5hbGJ/JQSbZydENJSUQ4u3hDI+4W
-Ptli5qXXAgMBAAECggEBAIcwDQSnIjo2ZECHytQykpG6X6XXEksLhc1Lp0lhPC49
-uNR5pX6a4AcBb3PLr0opMQZO2tUoKA0ff3t0e8loKD+/xXhY0Z/dlioEOP7elwv0
-2nS1mhe9spCuxpk4GGXRhdtR8t2tj8s0do3YvgPgITXoEDX6YBZHNGhZpzSrFPgQ
-/c3eGCVmzWYuLFfdj5OPQ9bwTaY4JSvDLZT0/WTgiica7VySwfz3HP1fFqNykTiK
-ACQREvtxfk5Ym2nT6oni7CM2zOEJL9SXicXI5HO4bERH0ZYh//F3g6mwGiFXUJPd
-NKgaTM1oT9kRGkUaEYsRWrddwR8d5mXLvBuTJbgIsSECgYEA1+2uJSYRW1OqbhYP
-ms59YQHSs3VjpJpnCV2zNa2Wixs57KS2cOH7B6KrQCogJFLtgCDVLtyoErfVkD7E
-FivTgYr1pVCRppJddQzXik31uOINOBVffr7/09g3GcRN+ubHPZPq3K+dD6gHa3Aj
-0nH1EjEEV0QpSTQFn87OF2mc9wcCgYEA1NVqMbbzd+9Xft5FXuSbX6E+S02dOGat
-SgpnkTM80rjqa6eHdQzqk3JqyteHPgdi1vdYRlSPOj/X+6tySY0Ej9sRnYOfddA2
-kpiDiVkmiqVolyJPY69Utj+E3TzJ1vhCQuYknJmB7zP9tDcTxMeq0l/NaWvGshEK
-yC4UTQog1rECgYASOFILfGzWgfbNlzr12xqlRtwanHst9oFfPvLSQrWDQ2bd2wAy
-Aj+GY2mD3oobxouX1i1m6OOdwLlalJFDNauBMNKNgoDnx03vhIfjebSURy7KXrNS
-JJe9rm7n07KoyzRgs8yLlp3wJkOKA0pihY8iW9R78JpzPNqEo5SsURMXnQKBgBlV
-gfuC9H4tPjP6zzUZbyk1701VYsaI6k2q6WMOP0ox+q1v1p7nN7DvaKjWeOG4TVqb
-PKW6gQYE/XeWk9cPcyCQigs+1KdYbnaKsvWRaBYO1GFREzQhdarv6qfPCZOOH40J
-Cgid+Sp4/NULzU2aGspJ3xCSZKdjge4MFhyJfRkxAoGBAJlwqY4nue0MBLGNpqcs
-WwDtSasHvegKAcxGBKL5oWPbLBk7hk+hdqc8f6YqCkCNqv/ooBspL15ESItL+6yT
-zt0YkK4oH9tmLDb+rvqZ7ZdXbWSwKITMoCyyHUtT6OKt/RtA0Vdy9LPnP27oSO/C
-dk8Qf7KgKZLWo0ZNkvw38tEC
------END PRIVATE KEY----- \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/runtests.py b/testing/marionette/harness/marionette_harness/runtests.py
deleted file mode 100644
index 3d3d09375f..0000000000
--- a/testing/marionette/harness/marionette_harness/runtests.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# 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 sys
-
-import mozlog
-
-from marionette_driver import __version__ as driver_version
-
-from marionette_harness import (
- __version__,
- BaseMarionetteTestRunner,
- BaseMarionetteArguments,
- BrowserMobProxyArguments,
- MarionetteTestCase,
-)
-
-
-class MarionetteTestRunner(BaseMarionetteTestRunner):
- def __init__(self, **kwargs):
- BaseMarionetteTestRunner.__init__(self, **kwargs)
- self.test_handlers = [MarionetteTestCase]
-
-
-class MarionetteArguments(BaseMarionetteArguments):
- def __init__(self, **kwargs):
- BaseMarionetteArguments.__init__(self, **kwargs)
- self.register_argument_container(BrowserMobProxyArguments())
-
-
-class MarionetteHarness(object):
- def __init__(self,
- runner_class=MarionetteTestRunner,
- parser_class=MarionetteArguments,
- testcase_class=MarionetteTestCase,
- args=None):
- self._runner_class = runner_class
- self._parser_class = parser_class
- self._testcase_class = testcase_class
- self.args = args or self.parse_args()
-
- def parse_args(self, logger_defaults=None):
- parser = self._parser_class(
- usage='%(prog)s [options] test_file_or_dir <test_file_or_dir> ...')
- parser.add_argument('--version', action='version',
- help="Show version information.",
- version="%(prog)s {version}"
- " (using marionette-driver: {driver_version}, ".format(
- version=__version__,
- driver_version=driver_version
- ))
- mozlog.commandline.add_logging_group(parser)
- args = parser.parse_args()
- parser.verify_usage(args)
-
- logger = mozlog.commandline.setup_logging(
- args.logger_name, args, logger_defaults or {"tbpl": sys.stdout})
-
- args.logger = logger
- return vars(args)
-
- def process_args(self):
- if self.args.get('pydebugger'):
- self._testcase_class.pydebugger = __import__(self.args['pydebugger'])
-
- def run(self):
- self.process_args()
- tests = self.args.pop('tests')
- runner = self._runner_class(**self.args)
- runner.run_tests(tests)
- return runner.failed + runner.crashed
-
-
-def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
- harness_class=MarionetteHarness, testcase_class=MarionetteTestCase, args=None):
- """
- Call the harness to parse args and run tests.
-
- The following exit codes are expected:
- - Test failures: 10
- - Harness/other failures: 1
- - Success: 0
- """
- logger = mozlog.commandline.setup_logging('Marionette test runner', {})
- try:
- harness_instance = harness_class(runner_class, parser_class, testcase_class,
- args=args)
- failed = harness_instance.run()
- if failed > 0:
- sys.exit(10)
- except Exception:
- logger.error('Failure during harness execution', exc_info=True)
- sys.exit(1)
- sys.exit(0)
-
-if __name__ == "__main__":
- cli()
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/conftest.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/conftest.py
deleted file mode 100644
index 6dc0a89a17..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/conftest.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# 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 pytest
-
-from mock import Mock, MagicMock
-
-from marionette_driver.marionette import Marionette
-
-from marionette_harness.runner.httpd import FixtureServer
-
-
-@pytest.fixture(scope='module')
-def logger():
- """
- Fake logger to help with mocking out other runner-related classes.
- """
- import mozlog
- return Mock(spec=mozlog.structuredlog.StructuredLogger)
-
-
-@pytest.fixture
-def mach_parsed_kwargs(logger):
- """
- Parsed and verified dictionary used during simplest
- call to mach marionette-test
- """
- return {
- 'adb_path': None,
- 'addons': None,
- 'address': None,
- 'app': None,
- 'app_args': [],
- 'avd': None,
- 'avd_home': None,
- 'binary': u'/path/to/firefox',
- 'browsermob_port' : None,
- 'browsermob_script' : None,
- 'device_serial': None,
- 'e10s': True,
- 'emulator': False,
- 'emulator_bin': None,
- 'gecko_log': None,
- 'jsdebugger': False,
- 'log_errorsummary': None,
- 'log_html': None,
- 'log_mach': None,
- 'log_mach_buffer': None,
- 'log_mach_level': None,
- 'log_mach_verbose': None,
- 'log_raw': None,
- 'log_raw_level': None,
- 'log_tbpl': None,
- 'log_tbpl_buffer': None,
- 'log_tbpl_compact': None,
- 'log_tbpl_level': None,
- 'log_unittest': None,
- 'log_xunit': None,
- 'logger_name': 'Marionette-based Tests',
- 'prefs': {},
- 'prefs_args': None,
- 'prefs_files': None,
- 'profile': None,
- 'pydebugger': None,
- 'repeat': 0,
- 'server_root': None,
- 'shuffle': False,
- 'shuffle_seed': 2276870381009474531,
- 'socket_timeout': 60.0,
- 'startup_timeout': 60,
- 'symbols_path': None,
- 'test_tags': None,
- 'tests': [u'/path/to/unit-tests.ini'],
- 'testvars': None,
- 'this_chunk': None,
- 'timeout': None,
- 'total_chunks': None,
- 'verbose': None,
- 'workspace': None,
- 'logger': logger,
- }
-
-
-@pytest.fixture
-def mock_httpd(request):
- """ Mock httpd instance """
- httpd = MagicMock(spec=FixtureServer)
- return httpd
-
-
-@pytest.fixture
-def mock_marionette(request):
- """ Mock marionette instance """
- marionette_class = MagicMock(spec=Marionette)
- if 'has_crashed' in request.funcargnames:
- marionette_class.check_for_crash.return_value = request.getfuncargvalue(
- 'has_crashed'
- )
- return marionette_class
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_httpd.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_httpd.py
deleted file mode 100644
index bd86b2fffb..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_httpd.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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 json
-import os
-import types
-import urllib2
-
-import pytest
-
-from wptserve.handlers import json_handler
-
-from marionette_harness.runner import httpd
-
-here = os.path.abspath(os.path.dirname(__file__))
-parent = os.path.dirname(here)
-default_doc_root = os.path.join(os.path.dirname(parent), "www")
-
-
-@pytest.yield_fixture
-def server():
- server = httpd.FixtureServer(default_doc_root)
- yield server
- server.stop()
-
-
-def test_ctor():
- with pytest.raises(ValueError):
- httpd.FixtureServer("foo")
- httpd.FixtureServer(default_doc_root)
-
-
-def test_start_stop(server):
- server.start()
- server.stop()
-
-
-def test_get_url(server):
- server.start()
- url = server.get_url("/")
- assert isinstance(url, types.StringTypes)
- assert "http://" in url
-
- server.stop()
- with pytest.raises(httpd.NotAliveError):
- server.get_url("/")
-
-
-def test_doc_root(server):
- server.start()
- assert isinstance(server.doc_root, types.StringTypes)
- server.stop()
- assert isinstance(server.doc_root, types.StringTypes)
-
-
-def test_router(server):
- assert server.router is not None
-
-
-def test_routes(server):
- assert server.routes is not None
-
-
-def test_is_alive(server):
- assert server.is_alive == False
- server.start()
- assert server.is_alive == True
-
-
-def test_handler(server):
- counter = 0
-
- @json_handler
- def handler(request, response):
- return {"count": counter}
-
- route = ("GET", "/httpd/test_handler", handler)
- server.router.register(*route)
- server.start()
-
- url = server.get_url("/httpd/test_handler")
- body = urllib2.urlopen(url).read()
- res = json.loads(body)
- assert res["count"] == counter
-
-
-if __name__ == "__main__":
- import sys
- sys.exit(pytest.main(["--verbose", __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py
deleted file mode 100644
index 1a0687028c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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 pytest
-
-from marionette_harness.runtests import MarionetteArguments
-
-
-@pytest.mark.parametrize("socket_timeout", ['A', '10', '1B-', '1C2', '44.35'])
-def test_parse_arg_socket_timeout(socket_timeout):
- argv = ['marionette', '--socket-timeout', socket_timeout]
- parser = MarionetteArguments()
-
- def _is_float_convertible(value):
- try:
- float(value)
- return True
- except:
- return False
-
- if not _is_float_convertible(socket_timeout):
- with pytest.raises(SystemExit) as ex:
- parser.parse_args(args=argv)
- assert ex.value.code == 2
- else:
- args = parser.parse_args(args=argv)
- assert hasattr(args, 'socket_timeout') and args.socket_timeout == float(socket_timeout)
-
-
-if __name__ == '__main__':
- import sys
- sys.exit(pytest.main(['--verbose', __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_harness.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_harness.py
deleted file mode 100644
index dfbbfb7882..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_harness.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# 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 pytest
-
-from mock import Mock, patch, sentinel
-
-import marionette_harness.marionette_test as marionette_test
-
-from marionette_harness.runtests import MarionetteTestRunner, MarionetteHarness, cli
-
-
-@pytest.fixture
-def harness_class(request):
- """
- Mock based on MarionetteHarness whose run method just returns a number of
- failures according to the supplied test parameter
- """
- if 'num_fails_crashed' in request.funcargnames:
- num_fails_crashed = request.getfuncargvalue('num_fails_crashed')
- else:
- num_fails_crashed = (0, 0)
- harness_cls = Mock(spec=MarionetteHarness)
- harness = harness_cls.return_value
- if num_fails_crashed is None:
- harness.run.side_effect = Exception
- else:
- harness.run.return_value = sum(num_fails_crashed)
- return harness_cls
-
-
-@pytest.fixture
-def runner_class(request):
- """
- Mock based on MarionetteTestRunner, wherein the runner.failed,
- runner.crashed attributes are provided by a test parameter
- """
- if 'num_fails_crashed' in request.funcargnames:
- failures, crashed = request.getfuncargvalue('num_fails_crashed')
- else:
- failures = 0
- crashed = 0
- mock_runner_class = Mock(spec=MarionetteTestRunner)
- runner = mock_runner_class.return_value
- runner.failed = failures
- runner.crashed = crashed
- return mock_runner_class
-
-
-@pytest.mark.parametrize(
- "num_fails_crashed,exit_code",
- [((0, 0), 0), ((1, 0), 10), ((0, 1), 10), (None, 1)],
-)
-def test_cli_exit_code(num_fails_crashed, exit_code, harness_class):
- with pytest.raises(SystemExit) as err:
- cli(harness_class=harness_class)
- assert err.value.code == exit_code
-
-
-@pytest.mark.parametrize("num_fails_crashed", [(0, 0), (1, 0), (1, 1)])
-def test_call_harness_with_parsed_args_yields_num_failures(mach_parsed_kwargs,
- runner_class,
- num_fails_crashed):
- with patch(
- 'marionette_harness.runtests.MarionetteHarness.parse_args'
- ) as parse_args:
- failed_or_crashed = MarionetteHarness(runner_class,
- args=mach_parsed_kwargs).run()
- parse_args.assert_not_called()
- assert failed_or_crashed == sum(num_fails_crashed)
-
-
-def test_call_harness_with_no_args_yields_num_failures(runner_class):
- with patch(
- 'marionette_harness.runtests.MarionetteHarness.parse_args',
- return_value={'tests': []}
- ) as parse_args:
- failed_or_crashed = MarionetteHarness(runner_class).run()
- assert parse_args.call_count == 1
- assert failed_or_crashed == 0
-
-
-def test_args_passed_to_runner_class(mach_parsed_kwargs, runner_class):
- arg_list = mach_parsed_kwargs.keys()
- arg_list.remove('tests')
- mach_parsed_kwargs.update([(a, getattr(sentinel, a)) for a in arg_list])
- harness = MarionetteHarness(runner_class, args=mach_parsed_kwargs)
- harness.process_args = Mock()
- harness.run()
- for arg in arg_list:
- assert harness._runner_class.call_args[1][arg] is getattr(sentinel, arg)
-
-
-def test_harness_sets_up_default_test_handlers(mach_parsed_kwargs):
- """
- If the necessary TestCase is not in test_handlers,
- tests are omitted silently
- """
- harness = MarionetteHarness(args=mach_parsed_kwargs)
- mach_parsed_kwargs.pop('tests')
- runner = harness._runner_class(**mach_parsed_kwargs)
- assert marionette_test.MarionetteTestCase in runner.test_handlers
-
-
-if __name__ == '__main__':
- import sys
- sys.exit(pytest.main(['--verbose', __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
deleted file mode 100644
index 79bdc824e7..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
+++ /dev/null
@@ -1,442 +0,0 @@
-# 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 manifestparser
-import pytest
-
-from mock import Mock, patch, mock_open, sentinel, DEFAULT
-
-from marionette_harness.runtests import MarionetteTestRunner
-
-
-@pytest.fixture
-def runner(mach_parsed_kwargs):
- """
- MarionetteTestRunner instance initialized with default options.
- """
- return MarionetteTestRunner(**mach_parsed_kwargs)
-
-
-@pytest.fixture
-def mock_runner(runner, mock_marionette, monkeypatch):
- """
- MarionetteTestRunner instance with mocked-out
- self.marionette and other properties,
- to enable testing runner.run_tests().
- """
- runner.driverclass = mock_marionette
- for attr in ['run_test_set', '_capabilities']:
- setattr(runner, attr, Mock())
- runner._appName = 'fake_app'
- # simulate that browser runs with e10s by default
- runner._appinfo = {'browserTabsRemoteAutostart': True}
- monkeypatch.setattr('marionette_harness.runner.base.mozversion', Mock())
- return runner
-
-
-@pytest.fixture
-def build_kwargs_using(mach_parsed_kwargs):
- '''Helper function for test_build_kwargs_* functions'''
- def kwarg_builder(new_items, return_socket=False):
- mach_parsed_kwargs.update(new_items)
- runner = MarionetteTestRunner(**mach_parsed_kwargs)
- with patch('marionette_harness.runner.base.socket') as socket:
- built_kwargs = runner._build_kwargs()
- if return_socket:
- return built_kwargs, socket
- return built_kwargs
- return kwarg_builder
-
-
-@pytest.fixture
-def expected_driver_args(runner):
- '''Helper fixture for tests of _build_kwargs
- with binary/emulator.
- Provides a dictionary of certain arguments
- related to binary/emulator settings
- which we expect to be passed to the
- driverclass constructor. Expected values can
- be updated in tests as needed.
- Provides convenience methods for comparing the
- expected arguments to the argument dictionary
- created by _build_kwargs. '''
-
- class ExpectedDict(dict):
- def assert_matches(self, actual):
- for (k, v) in self.items():
- assert actual[k] == v
-
- def assert_keys_not_in(self, actual):
- for k in self.keys():
- assert k not in actual
-
- expected = ExpectedDict(host=None, port=None, bin=None)
- for attr in ['app', 'app_args', 'profile', 'addons', 'gecko_log']:
- expected[attr] = getattr(runner, attr)
- return expected
-
-
-class ManifestFixture:
- def __init__(self, name='mock_manifest',
- tests=[{'path': u'test_something.py', 'expected': 'pass'}]):
- self.filepath = "/path/to/fake/manifest.ini"
- self.n_disabled = len([t for t in tests if 'disabled' in t])
- self.n_enabled = len(tests) - self.n_disabled
- mock_manifest = Mock(spec=manifestparser.TestManifest,
- active_tests=Mock(return_value=tests))
- self.manifest_class = Mock(return_value=mock_manifest)
- self.__repr__ = lambda: "<ManifestFixture {}>".format(name)
-
-@pytest.fixture
-def manifest():
- return ManifestFixture()
-
-@pytest.fixture(params=['enabled', 'disabled', 'enabled_disabled', 'empty'])
-def manifest_with_tests(request):
- '''
- Fixture for the contents of mock_manifest, where a manifest
- can include enabled tests, disabled tests, both, or neither (empty)
- '''
- included = []
- if 'enabled' in request.param:
- included += [(u'test_expected_pass.py', 'pass'),
- (u'test_expected_fail.py', 'fail')]
- if 'disabled' in request.param:
- included += [(u'test_pass_disabled.py', 'pass', 'skip-if: true'),
- (u'test_fail_disabled.py', 'fail', 'skip-if: true')]
- keys = ('path', 'expected', 'disabled')
- active_tests = [dict(zip(keys, values)) for values in included]
-
- return ManifestFixture(request.param, active_tests)
-
-
-def test_args_passed_to_driverclass(mock_runner):
- built_kwargs = {'arg1': 'value1', 'arg2': 'value2'}
- mock_runner._build_kwargs = Mock(return_value=built_kwargs)
- with pytest.raises(IOError):
- mock_runner.run_tests(['fake_tests.ini'])
- assert mock_runner.driverclass.call_args[1] == built_kwargs
-
-
-def test_build_kwargs_basic_args(build_kwargs_using):
- '''Test the functionality of runner._build_kwargs:
- make sure that basic arguments (those which should
- always be included, irrespective of the runner's settings)
- get passed to the call to runner.driverclass'''
-
- basic_args = ['socket_timeout', 'prefs',
- 'startup_timeout', 'verbose', 'symbols_path']
- args_dict = {a: getattr(sentinel, a) for a in basic_args}
- # Mock an update method to work with calls to MarionetteTestRunner()
- args_dict['prefs'].update = Mock(return_value={})
- built_kwargs = build_kwargs_using([(a, getattr(sentinel, a)) for a in basic_args])
- for arg in basic_args:
- assert built_kwargs[arg] is getattr(sentinel, arg)
-
-
-@pytest.mark.parametrize('workspace', ['path/to/workspace', None])
-def test_build_kwargs_with_workspace(build_kwargs_using, workspace):
- built_kwargs = build_kwargs_using({'workspace': workspace})
- if workspace:
- assert built_kwargs['workspace'] == workspace
- else:
- assert 'workspace' not in built_kwargs
-
-
-@pytest.mark.parametrize('address', ['host:123', None])
-def test_build_kwargs_with_address(build_kwargs_using, address):
- built_kwargs, socket = build_kwargs_using(
- {'address': address, 'binary': None, 'emulator': None},
- return_socket=True
- )
- assert 'connect_to_running_emulator' not in built_kwargs
- if address is not None:
- host, port = address.split(":")
- assert built_kwargs['host'] == host and built_kwargs['port'] == int(port)
- socket.socket().connect.assert_called_with((host, int(port)))
- assert socket.socket().close.called
- else:
- assert not socket.socket.called
-
-
-@pytest.mark.parametrize('address', ['host:123', None])
-@pytest.mark.parametrize('binary', ['path/to/bin', None])
-def test_build_kwargs_with_binary_or_address(expected_driver_args, build_kwargs_using,
- binary, address):
- built_kwargs = build_kwargs_using({'binary': binary, 'address': address, 'emulator': None})
- if binary:
- expected_driver_args['bin'] = binary
- if address:
- host, port = address.split(":")
- expected_driver_args.update({'host': host, 'port': int(port)})
- else:
- expected_driver_args.update({'host': 'localhost', 'port': 2828})
- expected_driver_args.assert_matches(built_kwargs)
- elif address is None:
- expected_driver_args.assert_keys_not_in(built_kwargs)
-
-
-@pytest.mark.parametrize('address', ['host:123', None])
-@pytest.mark.parametrize('emulator', [True, False, None])
-def test_build_kwargs_with_emulator_or_address(expected_driver_args, build_kwargs_using,
- emulator, address):
- emulator_props = [(a, getattr(sentinel, a)) for a in ['avd_home', 'adb_path', 'emulator_bin']]
- built_kwargs = build_kwargs_using(
- [('emulator', emulator), ('address', address), ('binary', None)] + emulator_props
- )
- if emulator:
- expected_driver_args.update(emulator_props)
- expected_driver_args['emulator_binary'] = expected_driver_args.pop('emulator_bin')
- expected_driver_args['bin'] = True
- if address:
- expected_driver_args['connect_to_running_emulator'] = True
- host, port = address.split(":")
- expected_driver_args.update({'host': host, 'port': int(port)})
- else:
- expected_driver_args.update({'host': 'localhost', 'port': 2828})
- assert 'connect_to_running_emulator' not in built_kwargs
- expected_driver_args.assert_matches(built_kwargs)
- elif not address:
- expected_driver_args.assert_keys_not_in(built_kwargs)
-
-
-def test_parsing_testvars(mach_parsed_kwargs):
- mach_parsed_kwargs.pop('tests')
- testvars_json_loads = [
- {"wifi": {"ssid": "blah", "keyManagement": "WPA-PSK", "psk": "foo"}},
- {"wifi": {"PEAP": "bar"}, "device": {"stuff": "buzz"}}
- ]
- expected_dict = {
- "wifi": {
- "ssid": "blah",
- "keyManagement": "WPA-PSK",
- "psk": "foo",
- "PEAP": "bar"
- },
- "device": {"stuff": "buzz"}
- }
- with patch(
- 'marionette_harness.runtests.MarionetteTestRunner._load_testvars',
- return_value=testvars_json_loads
- ) as load:
- runner = MarionetteTestRunner(**mach_parsed_kwargs)
- assert runner.testvars == expected_dict
- assert load.call_count == 1
-
-
-def test_load_testvars_throws_expected_errors(mach_parsed_kwargs):
- mach_parsed_kwargs['testvars'] = ['some_bad_path.json']
- runner = MarionetteTestRunner(**mach_parsed_kwargs)
- with pytest.raises(IOError) as io_exc:
- runner._load_testvars()
- assert 'does not exist' in io_exc.value.message
- with patch('os.path.exists', return_value=True):
- with patch('__builtin__.open', mock_open(read_data='[not {valid JSON]')):
- with pytest.raises(Exception) as json_exc:
- runner._load_testvars()
- assert 'not properly formatted' in json_exc.value.message
-
-
-def _check_crash_counts(has_crashed, runner, mock_marionette):
- if has_crashed:
- assert mock_marionette.check_for_crash.call_count == 1
- assert runner.crashed == 1
- else:
- assert runner.crashed == 0
-
-
-@pytest.mark.parametrize("has_crashed", [True, False])
-def test_increment_crash_count_in_run_test_set(runner, has_crashed,
- mock_marionette):
- fake_tests = [{'filepath': i,
- 'expected': 'pass'} for i in 'abc']
-
- with patch.multiple(runner, run_test=DEFAULT, marionette=mock_marionette):
- runner.run_test_set(fake_tests)
- if not has_crashed:
- assert runner.marionette.check_for_crash.call_count == len(fake_tests)
- _check_crash_counts(has_crashed, runner, runner.marionette)
-
-
-@pytest.mark.parametrize("has_crashed", [True, False])
-def test_record_crash(runner, has_crashed, mock_marionette):
- with patch.object(runner, 'marionette', mock_marionette):
- assert runner.record_crash() == has_crashed
- _check_crash_counts(has_crashed, runner, runner.marionette)
-
-
-def test_add_test_module(runner):
- tests = ['test_something.py', 'testSomething.js', 'bad_test.py']
- assert len(runner.tests) == 0
- for test in tests:
- with patch('os.path.abspath', return_value=test) as abspath:
- runner.add_test(test)
- assert abspath.called
- expected = {'filepath': test, 'expected': 'pass'}
- assert expected in runner.tests
- # add_test doesn't validate module names; 'bad_test.py' gets through
- assert len(runner.tests) == 3
-
-
-def test_add_test_directory(runner):
- test_dir = 'path/to/tests'
- dir_contents = [
- (test_dir, ('subdir',), ('test_a.py', 'test_a.js', 'bad_test_a.py', 'bad_test_a.js')),
- (test_dir + '/subdir', (), ('test_b.py', 'test_b.js', 'bad_test_b.py', 'bad_test_b.js')),
- ]
- tests = list(dir_contents[0][2] + dir_contents[1][2])
- assert len(runner.tests) == 0
- # Need to use side effect to make isdir return True for test_dir and False for tests
- with patch('os.path.isdir', side_effect=[True] + [False for t in tests]) as isdir:
- with patch('os.walk', return_value=dir_contents) as walk:
- runner.add_test(test_dir)
- assert isdir.called and walk.called
- for test in runner.tests:
- assert test_dir in test['filepath']
- assert len(runner.tests) == 4
-
-
-@pytest.mark.parametrize("test_files_exist", [True, False])
-def test_add_test_manifest(mock_runner, manifest_with_tests, monkeypatch, test_files_exist):
- monkeypatch.setattr('marionette_harness.runner.base.TestManifest',
- manifest_with_tests.manifest_class)
- mock_runner.marionette = mock_runner.driverclass()
- with patch('marionette_harness.runner.base.os.path.exists', return_value=test_files_exist):
- if test_files_exist or manifest_with_tests.n_enabled == 0:
- mock_runner.add_test(manifest_with_tests.filepath)
- assert len(mock_runner.tests) == manifest_with_tests.n_enabled
- assert len(mock_runner.manifest_skipped_tests) == manifest_with_tests.n_disabled
- for test in mock_runner.tests:
- assert test['filepath'].endswith(test['expected'] + '.py')
- else:
- pytest.raises(IOError, "mock_runner.add_test(manifest_with_tests.filepath)")
- assert manifest_with_tests.manifest_class().read.called
- assert manifest_with_tests.manifest_class().active_tests.called
-
-
-def get_kwargs_passed_to_manifest(mock_runner, manifest, monkeypatch, **kwargs):
- '''Helper function for test_manifest_* tests.
- Returns the kwargs passed to the call to manifest.active_tests.'''
- monkeypatch.setattr('marionette_harness.runner.base.TestManifest', manifest.manifest_class)
- monkeypatch.setattr('marionette_harness.runner.base.mozinfo.info',
- {'mozinfo_key': 'mozinfo_val'})
- for attr in kwargs:
- setattr(mock_runner, attr, kwargs[attr])
- mock_runner.marionette = mock_runner.driverclass()
- with patch('marionette_harness.runner.base.os.path.exists', return_value=True):
- mock_runner.add_test(manifest.filepath)
- call_args, call_kwargs = manifest.manifest_class().active_tests.call_args
- return call_kwargs
-
-
-def test_manifest_basic_args(mock_runner, manifest, monkeypatch):
- kwargs = get_kwargs_passed_to_manifest(mock_runner, manifest, monkeypatch)
- assert kwargs['exists'] is False
- assert kwargs['disabled'] is True
- assert kwargs['appname'] == 'fake_app'
- assert 'mozinfo_key' in kwargs and kwargs['mozinfo_key'] == 'mozinfo_val'
-
-
-@pytest.mark.parametrize('e10s', (True, False))
-def test_manifest_with_e10s(mock_runner, manifest, monkeypatch, e10s):
- kwargs = get_kwargs_passed_to_manifest(mock_runner, manifest, monkeypatch, e10s=e10s)
- assert kwargs['e10s'] == e10s
-
-
-@pytest.mark.parametrize('test_tags', (None, ['tag', 'tag2']))
-def test_manifest_with_test_tags(mock_runner, manifest, monkeypatch, test_tags):
- kwargs = get_kwargs_passed_to_manifest(mock_runner, manifest, monkeypatch, test_tags=test_tags)
- if test_tags is None:
- assert kwargs['filters'] == []
- else:
- assert len(kwargs['filters']) == 1 and kwargs['filters'][0].tags == test_tags
-
-
-def test_cleanup_with_manifest(mock_runner, manifest_with_tests, monkeypatch):
- monkeypatch.setattr('marionette_harness.runner.base.TestManifest',
- manifest_with_tests.manifest_class)
- if manifest_with_tests.n_enabled > 0:
- context = patch('marionette_harness.runner.base.os.path.exists', return_value=True)
- else:
- context = pytest.raises(Exception)
- with context:
- mock_runner.run_tests([manifest_with_tests.filepath])
- assert mock_runner.marionette is None
- assert mock_runner.fixture_servers == {}
-
-
-def test_reset_test_stats(mock_runner):
- def reset_successful(runner):
- stats = ['passed', 'failed', 'unexpected_successes', 'todo', 'skipped', 'failures']
- return all([((s in vars(runner)) and (not vars(runner)[s])) for s in stats])
- assert reset_successful(mock_runner)
- mock_runner.passed = 1
- mock_runner.failed = 1
- mock_runner.failures.append(['TEST-UNEXPECTED-FAIL'])
- assert not reset_successful(mock_runner)
- mock_runner.run_tests([u'test_fake_thing.py'])
- assert reset_successful(mock_runner)
-
-
-def test_initialize_test_run(mock_runner):
- tests = [u'test_fake_thing.py']
- mock_runner.reset_test_stats = Mock()
- mock_runner.run_tests(tests)
- assert mock_runner.reset_test_stats.called
- with pytest.raises(AssertionError) as test_exc:
- mock_runner.run_tests([])
- assert "len(tests)" in str(test_exc.traceback[-1].statement)
- with pytest.raises(AssertionError) as hndl_exc:
- mock_runner.test_handlers = []
- mock_runner.run_tests(tests)
- assert "test_handlers" in str(hndl_exc.traceback[-1].statement)
- assert mock_runner.reset_test_stats.call_count == 1
-
-
-def test_add_tests(mock_runner):
- assert len(mock_runner.tests) == 0
- fake_tests = ["test_" + i + ".py" for i in "abc"]
- mock_runner.run_tests(fake_tests)
- assert len(mock_runner.tests) == 3
- for (test_name, added_test) in zip(fake_tests, mock_runner.tests):
- assert added_test['filepath'].endswith(test_name)
-
-
-def test_catch_invalid_test_names(runner):
- good_tests = [u'test_ok.py', u'test_is_ok.py', u'test_is_ok.js', u'testIsOk.js']
- bad_tests = [u'bad_test.py', u'testbad.py', u'_test_bad.py', u'testBad.notjs',
- u'test_bad.notpy', u'test_bad', u'testbad.js', u'badtest.js',
- u'test.py', u'test_.py', u'test.js', u'test_.js']
- with pytest.raises(Exception) as exc:
- runner._add_tests(good_tests + bad_tests)
- msg = exc.value.message
- assert "Test file names must be of the form" in msg
- for bad_name in bad_tests:
- assert bad_name in msg
- for good_name in good_tests:
- assert good_name not in msg
-
-@pytest.mark.parametrize('e10s', (True, False))
-def test_e10s_option_sets_prefs(mach_parsed_kwargs, e10s):
- mach_parsed_kwargs['e10s'] = e10s
- runner = MarionetteTestRunner(**mach_parsed_kwargs)
- e10s_prefs = {
- 'browser.tabs.remote.autostart': True,
- 'browser.tabs.remote.force-enable': True,
- 'extensions.e10sBlocksEnabling': False
- }
- for k,v in e10s_prefs.iteritems():
- if k == 'extensions.e10sBlocksEnabling' and not e10s:
- continue
- assert runner.prefs.get(k, False) == (v and e10s)
-
-def test_e10s_option_clash_raises(mock_runner):
- mock_runner.e10s = False
- with pytest.raises(AssertionError) as e:
- mock_runner.run_tests([u'test_fake_thing.py'])
- assert "configuration (self.e10s) does not match browser appinfo" in e.value.message
-
-if __name__ == '__main__':
- import sys
- sys.exit(pytest.main(['--verbose', __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_test_result.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_test_result.py
deleted file mode 100644
index a69b072cd5..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_test_result.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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 pytest
-
-from marionette_harness import MarionetteTestResult
-
-
-@pytest.fixture
-def empty_marionette_testcase():
- """ Testable MarionetteTestCase class """
- from marionette_harness import MarionetteTestCase
-
- class EmptyTestCase(MarionetteTestCase):
- def test_nothing(self):
- pass
-
- return EmptyTestCase
-
-
-@pytest.fixture
-def empty_marionette_test(mock_marionette, empty_marionette_testcase):
- return empty_marionette_testcase(lambda: mock_marionette, lambda: mock_httpd,
- 'test_nothing')
-
-
-@pytest.mark.parametrize("has_crashed", [True, False])
-def test_crash_is_recorded_as_error(empty_marionette_test,
- logger,
- has_crashed):
- """ Number of errors is incremented by stopTest iff has_crashed is true """
- # collect results from the empty test
- result = MarionetteTestResult(
- marionette=empty_marionette_test._marionette_weakref(),
- logger=logger, verbosity=None,
- stream=None, descriptions=None,
- )
- result.startTest(empty_marionette_test)
- assert len(result.errors) == 0
- assert len(result.failures) == 0
- assert result.testsRun == 1
- assert result.shouldStop is False
- result.stopTest(empty_marionette_test)
- assert result.shouldStop == has_crashed
- if has_crashed:
- assert len(result.errors) == 1
- else:
- assert len(result.errors) == 0
-
-
-if __name__ == '__main__':
- import sys
- sys.exit(pytest.main(['--verbose', __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_serve.py b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_serve.py
deleted file mode 100644
index 73684c0d63..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_serve.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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 types
-
-import pytest
-
-from marionette_harness.runner import serve
-from marionette_harness.runner.serve import iter_proc, iter_url
-
-
-def teardown_function(func):
- for server in [server for server in iter_proc(serve.servers) if server.is_alive]:
- server.stop()
- server.kill()
-
-
-def test_registered_servers():
- # [(name, factory), ...]
- assert serve.registered_servers[0][0] == "http"
- assert serve.registered_servers[1][0] == "https"
-
-
-def test_globals():
- assert serve.default_doc_root is not None
- assert serve.registered_servers is not None
- assert serve.servers is not None
-
-
-def test_start():
- serve.start()
- assert len(serve.servers) == 2
- assert "http" in serve.servers
- assert "https" in serve.servers
- for url in iter_url(serve.servers):
- assert isinstance(url, types.StringTypes)
-
-
-def test_start_with_custom_root(tmpdir_factory):
- tdir = tmpdir_factory.mktemp("foo")
- serve.start(str(tdir))
- for server in iter_proc(serve.servers):
- assert server.doc_root == tdir
-
-
-def test_iter_proc():
- serve.start()
- for server in iter_proc(serve.servers):
- server.stop()
-
-
-def test_iter_url():
- serve.start()
- for url in iter_url(serve.servers):
- assert isinstance(url, types.StringTypes)
-
-
-def test_where_is():
- serve.start()
- assert serve.where_is("/") == serve.servers["http"][1].get_url("/")
- assert serve.where_is("/", on="https") == serve.servers["https"][1].get_url("/")
-
-
-if __name__ == "__main__":
- import sys
- sys.exit(pytest.main(["-s", "--verbose", __file__]))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit-tests.ini b/testing/marionette/harness/marionette_harness/tests/unit-tests.ini
deleted file mode 100644
index 8d806afeae..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit-tests.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-; marionette unit tests
-[include:unit/unit-tests.ini]
-
-; layout tests
-[include:../../../../../layout/base/tests/marionette/manifest.ini]
-
-; microformats tests
-[include:../../../../../toolkit/components/microformats/manifest.ini]
-
-; migration tests
-[include:../../../../../browser/components/migration/tests/marionette/manifest.ini]
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/importanotherscript.js b/testing/marionette/harness/marionette_harness/tests/unit/importanotherscript.js
deleted file mode 100644
index fa6a1fa7c3..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/importanotherscript.js
+++ /dev/null
@@ -1 +0,0 @@
-var testAnotherFunc = function() { return "i'm yet another test function!";};
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/importscript.js b/testing/marionette/harness/marionette_harness/tests/unit/importscript.js
deleted file mode 100644
index 5a5dd8a186..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/importscript.js
+++ /dev/null
@@ -1 +0,0 @@
-var testFunc = function() { return "i'm a test function!";};
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/mn-restartless-unsigned.xpi b/testing/marionette/harness/marionette_harness/tests/unit/mn-restartless-unsigned.xpi
deleted file mode 100644
index c8877b55de..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/mn-restartless-unsigned.xpi
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/single_finger_functions.py b/testing/marionette/harness/marionette_harness/tests/unit/single_finger_functions.py
deleted file mode 100644
index c2daf9d54c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/single_finger_functions.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from marionette_driver.marionette import Actions
-from marionette_driver.errors import TimeoutException
-from marionette_driver.by import By
-
-
-def wait_for_condition_else_raise(marionette, wait_for_condition, expected, script):
- try:
- wait_for_condition(lambda m: expected in m.execute_script(script))
- except TimeoutException as e:
- raise TimeoutException("{0} got {1} instead of {2}".format(
- e.message, marionette.execute_script(script), expected))
-
-def press_release(marionette, times, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- action = Actions(marionette)
- button = marionette.find_element(By.ID, "button1")
- action.press(button).release()
- # Insert wait between each press and release chain.
- for _ in range(times-1):
- action.wait(0.1)
- action.press(button).release()
- action.perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def move_element(marionette, wait_for_condition, expected1, expected2):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- ele = marionette.find_element(By.ID, "button1")
- drop = marionette.find_element(By.ID, "button2")
- action = Actions(marionette)
- action.press(ele).move(drop).release()
- action.perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;")
- wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('button2').innerHTML;")
-
-def move_element_offset(marionette, wait_for_condition, expected1, expected2):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- ele = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.press(ele).move_by_offset(0,150).move_by_offset(0, 150).release()
- action.perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;")
- wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('button2').innerHTML;")
-
-def chain(marionette, wait_for_condition, expected1, expected2):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- marionette.timeout.implicit = 15
- action = Actions(marionette)
- button1 = marionette.find_element(By.ID, "button1")
- action.press(button1).perform()
- button2 = marionette.find_element(By.ID, "delayed")
- wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;")
- action.move(button2).release().perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('delayed').innerHTML;")
-
-def chain_flick(marionette, wait_for_condition, expected1, expected2):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.flick(button, 0, 0, 0, 200).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected1,"return document.getElementById('button1').innerHTML;")
- wait_for_condition_else_raise(marionette, wait_for_condition, expected2,"return document.getElementById('buttonFlick').innerHTML;")
-
-
-def wait(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- action = Actions(marionette)
- button = marionette.find_element(By.ID, "button1")
- action.press(button).wait().release().perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def wait_with_value(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.press(button).wait(0.01).release()
- action.perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def context_menu(marionette, wait_for_condition, expected1, expected2):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.press(button).wait(5).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected1, "return document.getElementById('button1').innerHTML;")
- action.release().perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected2, "return document.getElementById('button1').innerHTML;")
-
-def long_press_action(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.long_press(button, 5).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def long_press_on_xy_action(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- html = marionette.find_element(By.TAG_NAME, "html")
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
-
- # Press the center of the button with respect to html.
- x = button.rect['x'] + button.rect['width'] / 2.0
- y = button.rect['y'] + button.rect['height'] / 2.0
- action.long_press(html, 5, x, y).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def single_tap(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.tap(button).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
-
-def double_tap(marionette, wait_for_condition, expected):
- testAction = marionette.absolute_url("testAction.html")
- marionette.navigate(testAction)
- button = marionette.find_element(By.ID, "button1")
- action = Actions(marionette)
- action.double_tap(button).perform()
- wait_for_condition_else_raise(marionette, wait_for_condition, expected, "return document.getElementById('button1').innerHTML;")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_about_pages.py b/testing/marionette/harness/marionette_harness/tests/unit/test_about_pages.py
deleted file mode 100644
index e9992f8a56..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_about_pages.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from marionette_driver import By, Wait
-from marionette_driver.keys import Keys
-
-from marionette_harness import MarionetteTestCase, skip, skip_if_mobile, WindowManagerMixin
-
-
-class TestAboutPages(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAboutPages, self).setUp()
-
- if self.marionette.session_capabilities['platformName'] == 'darwin':
- self.mod_key = Keys.META
- else:
- self.mod_key = Keys.CONTROL
-
- self.remote_uri = self.marionette.absolute_url("windowHandles.html")
-
- def tearDown(self):
- self.close_all_tabs()
-
- super(TestAboutPages, self).tearDown()
-
- def open_tab_with_link(self):
- with self.marionette.using_context("content"):
- self.marionette.navigate(self.remote_uri)
-
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- @skip_if_mobile("Bug 1333209 - Process killed because of connection loss")
- def test_back_forward(self):
- # Bug 1311041 - Prevent changing of window handle by forcing the test
- # to be run in a new tab.
- new_tab = self.open_tab(trigger=self.open_tab_with_link)
- self.marionette.switch_to_window(new_tab)
-
- self.marionette.navigate("about:blank")
- self.marionette.navigate(self.remote_uri)
- self.marionette.navigate("about:support")
-
- self.marionette.go_back()
- self.assertEqual(self.marionette.get_url(), self.remote_uri)
-
- self.marionette.go_forward()
- self.assertEqual(self.marionette.get_url(), "about:support")
-
- self.marionette.close()
- self.marionette.switch_to_window(self.start_tab)
-
- @skip_if_mobile("Bug 1333209 - Process killed because of connection loss")
- def test_navigate_non_remote_about_pages(self):
- # Bug 1311041 - Prevent changing of window handle by forcing the test
- # to be run in a new tab.
- new_tab = self.open_tab(trigger=self.open_tab_with_link)
- self.marionette.switch_to_window(new_tab)
-
- self.marionette.navigate("about:blank")
- self.assertEqual(self.marionette.get_url(), "about:blank")
- self.marionette.navigate("about:support")
- self.assertEqual(self.marionette.get_url(), "about:support")
-
- self.marionette.close()
- self.marionette.switch_to_window(self.start_tab)
-
- @skip_if_mobile("On Android no shortcuts are available")
- def test_navigate_shortcut_key(self):
- def open_with_shortcut():
- self.marionette.navigate(self.remote_uri)
- with self.marionette.using_context("chrome"):
- main_win = self.marionette.find_element(By.ID, "main-window")
- main_win.send_keys(self.mod_key, Keys.SHIFT, 'a')
-
- new_tab = self.open_tab(trigger=open_with_shortcut)
- self.marionette.switch_to_window(new_tab)
-
- Wait(self.marionette).until(lambda mn: mn.get_url() == "about:addons",
- message="'about:addons' hasn't been loaded")
-
- self.marionette.close()
- self.marionette.switch_to_window(self.start_tab)
-
- @skip("Bug 1334137 - Intermittent: Process killed because of hang in getCurrentUrl()")
- @skip_if_mobile("Interacting with chrome elements not available for Fennec")
- def test_type_to_non_remote_tab(self):
- # Bug 1311041 - Prevent changing of window handle by forcing the test
- # to be run in a new tab.
- new_tab = self.open_tab(trigger=self.open_tab_with_link)
- self.marionette.switch_to_window(new_tab)
-
- with self.marionette.using_context("chrome"):
- urlbar = self.marionette.find_element(By.ID, 'urlbar')
- urlbar.send_keys(self.mod_key + 'a')
- urlbar.send_keys(self.mod_key + 'x')
- urlbar.send_keys('about:support' + Keys.ENTER)
- Wait(self.marionette).until(lambda mn: mn.get_url() == "about:support",
- message="'about:support' hasn't been loaded")
-
- self.marionette.close()
- self.marionette.switch_to_window(self.start_tab)
-
- @skip_if_mobile("Interacting with chrome elements not available for Fennec")
- def test_type_to_remote_tab(self):
- # Bug 1311041 - Prevent changing of window handle by forcing the test
- # to be run in a new tab.
- new_tab = self.open_tab(trigger=self.open_tab_with_link)
- self.marionette.switch_to_window(new_tab)
-
- # about:blank keeps remoteness from remote_uri
- self.marionette.navigate("about:blank")
- with self.marionette.using_context("chrome"):
- urlbar = self.marionette.find_element(By.ID, 'urlbar')
- urlbar.send_keys(self.mod_key + 'a')
- urlbar.send_keys(self.mod_key + 'x')
- urlbar.send_keys(self.remote_uri + Keys.ENTER)
-
- Wait(self.marionette).until(lambda mn: mn.get_url() == self.remote_uri,
- message="'{}' hasn't been loaded".format(self.remote_uri))
-
- @skip_if_mobile("Needs application independent method to open a new tab")
- def test_hang(self):
- # Bug 1311041 - Prevent changing of window handle by forcing the test
- # to be run in a new tab.
- new_tab = self.open_tab(trigger=self.open_tab_with_link)
-
- # Close the start tab
- self.marionette.close()
- self.marionette.switch_to_window(new_tab)
-
- self.marionette.navigate(self.remote_uri)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_accessibility.py b/testing/marionette/harness/marionette_harness/tests/unit/test_accessibility.py
deleted file mode 100644
index 0d8d9dca52..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_accessibility.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import (
- ElementNotAccessibleException,
- ElementNotInteractableException
-)
-
-from marionette_harness import MarionetteTestCase
-
-
-
-class TestAccessibility(MarionetteTestCase):
- def setUp(self):
- super(TestAccessibility, self).setUp()
- with self.marionette.using_context("chrome"):
- self.marionette.set_pref("dom.ipc.processCount", 1)
-
- def tearDown(self):
- with self.marionette.using_context("chrome"):
- self.marionette.clear_pref("dom.ipc.processCount")
-
- # Elements that are accessible with and without the accessibliity API
- valid_elementIDs = [
- # Button1 is an accessible button with a valid accessible name
- # computed from subtree
- "button1",
- # Button2 is an accessible button with a valid accessible name
- # computed from aria-label
- "button2",
- # Button13 is an accessible button that is implemented via role="button"
- # and is explorable using tabindex="0"
- "button13",
- # button17 is an accessible button that overrides parent's
- # pointer-events:none; property with its own pointer-events:all;
- "button17"
- ]
-
- # Elements that are not accessible with the accessibility API
- invalid_elementIDs = [
- # Button3 does not have an accessible object
- "button3",
- # Button4 does not support any accessible actions
- "button4",
- # Button5 does not have a correct accessibility role and may not be
- # manipulated via the accessibility API
- "button5",
- # Button6 is missing an accesible name
- "button6",
- # Button7 is not currently visible via the accessibility API and may
- # not be manipulated by it
- "button7",
- # Button8 is not currently visible via the accessibility API and may
- # not be manipulated by it (in hidden subtree)
- "button8",
- # Button14 is accessible button but is not explorable because of lack
- # of tabindex that would make it focusable.
- "button14"
- ]
-
- # Elements that are either accessible to accessibility API or not accessible
- # at all
- falsy_elements = [
- # Element is only visible to the accessibility API and may be
- # manipulated by it
- "button9",
- # Element is not currently visible
- "button10"
- ]
-
- displayed_elementIDs = [
- "button1", "button2", "button3", "button4", "button5", "button6",
- "button9", "no_accessible_but_displayed"
- ]
-
- displayed_but_a11y_hidden_elementIDs = ["button7", "button8"]
-
- disabled_elementIDs = ["button11", "no_accessible_but_disabled"]
-
- # Elements that are enabled but otherwise disabled or not explorable via the accessibility API
- disabled_accessibility_elementIDs = ["button12", "button15", "button16"]
-
- # Elements that are reporting selected state
- valid_option_elementIDs = ["option1", "option2"]
-
- def run_element_test(self, ids, testFn):
- for id in ids:
- element = self.marionette.find_element(By.ID, id)
- testFn(element)
-
- def setup_accessibility(self, enable_a11y_checks=True, navigate=True):
- self.marionette.delete_session()
- self.marionette.start_session(
- {"requiredCapabilities": {"moz:accessibilityChecks": enable_a11y_checks}})
- self.assertEqual(
- self.marionette.session_capabilities["moz:accessibilityChecks"],
- enable_a11y_checks)
-
- # Navigate to test_accessibility.html
- if navigate:
- test_accessibility = self.marionette.absolute_url("test_accessibility.html")
- self.marionette.navigate(test_accessibility)
-
- def test_valid_single_tap(self):
- self.setup_accessibility()
- # No exception should be raised
- self.run_element_test(self.valid_elementIDs, lambda button: button.tap())
-
- def test_single_tap_raises_element_not_accessible(self):
- self.setup_accessibility()
- self.run_element_test(self.invalid_elementIDs,
- lambda button: self.assertRaises(ElementNotAccessibleException,
- button.tap))
- self.run_element_test(self.falsy_elements,
- lambda button: self.assertRaises(ElementNotInteractableException,
- button.tap))
-
- def test_single_tap_raises_no_exceptions(self):
- self.setup_accessibility(False, True)
- # No exception should be raised
- self.run_element_test(self.invalid_elementIDs, lambda button: button.tap())
- # Elements are invisible
- self.run_element_test(self.falsy_elements,
- lambda button: self.assertRaises(ElementNotInteractableException,
- button.tap))
-
- def test_valid_click(self):
- self.setup_accessibility()
- # No exception should be raised
- self.run_element_test(self.valid_elementIDs, lambda button: button.click())
-
- def test_click_raises_element_not_accessible(self):
- self.setup_accessibility()
- self.run_element_test(self.invalid_elementIDs,
- lambda button: self.assertRaises(ElementNotAccessibleException,
- button.click))
- self.run_element_test(self.falsy_elements,
- lambda button: self.assertRaises(ElementNotInteractableException,
- button.click))
-
- def test_click_raises_no_exceptions(self):
- self.setup_accessibility(False, True)
- # No exception should be raised
- self.run_element_test(self.invalid_elementIDs, lambda button: button.click())
- # Elements are invisible
- self.run_element_test(self.falsy_elements,
- lambda button: self.assertRaises(ElementNotInteractableException,
- button.click))
-
- def test_element_visible_but_not_visible_to_accessbility(self):
- self.setup_accessibility()
- # Elements are displayed but hidden from accessibility API
- self.run_element_test(self.displayed_but_a11y_hidden_elementIDs,
- lambda element: self.assertRaises(ElementNotAccessibleException,
- element.is_displayed))
-
- def test_element_is_visible_to_accessibility(self):
- self.setup_accessibility()
- # No exception should be raised
- self.run_element_test(self.displayed_elementIDs, lambda element: element.is_displayed())
-
- def test_element_is_not_enabled_to_accessbility(self):
- self.setup_accessibility()
- # Buttons are enabled but disabled/not-explorable via the accessibility API
- self.run_element_test(self.disabled_accessibility_elementIDs,
- lambda element: self.assertRaises(ElementNotAccessibleException,
- element.is_enabled))
-
- # Buttons are enabled but disabled/not-explorable via the accessibility API and thus are not
- # clickable via the accessibility API
- self.run_element_test(self.disabled_accessibility_elementIDs,
- lambda element: self.assertRaises(ElementNotAccessibleException,
- element.click))
-
- self.setup_accessibility(False, False)
- self.run_element_test(self.disabled_accessibility_elementIDs,
- lambda element: element.is_enabled())
- self.run_element_test(self.disabled_accessibility_elementIDs,
- lambda element: element.click())
-
- def test_element_is_enabled_to_accessibility(self):
- self.setup_accessibility()
- # No exception should be raised
- self.run_element_test(self.disabled_elementIDs, lambda element: element.is_enabled())
-
- def test_send_keys_raises_no_exception(self):
- self.setup_accessibility()
- # Sending keys to valid input should not raise any exceptions
- self.run_element_test(['input1'], lambda element: element.send_keys("a"))
-
- self.setup_accessibility(False, False)
- # Sending keys to invalid element should not raise any exceptions when raising accessibility
- # exceptions is disabled
- self.run_element_test(['button5'], lambda element: element.send_keys("abc"))
-
- def test_send_keys_raises_element_not_accessible(self):
- self.setup_accessibility()
- # Sending keys to invalid element should raise an exception
- self.run_element_test(['button5'],
- lambda element: self.assertRaises(ElementNotAccessibleException,
- element.send_keys))
-
- def test_is_selected_raises_no_exception(self):
- self.setup_accessibility()
- # No exception should be raised for valid options
- self.run_element_test(self.valid_option_elementIDs, lambda element: element.is_selected())
- # No exception should be raised for non-selectable elements
- self.run_element_test(self.valid_elementIDs, lambda element: element.is_selected())
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_addons.py b/testing/marionette/harness/marionette_harness/tests/unit/test_addons.py
deleted file mode 100644
index 25f1c05abd..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_addons.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# 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_driver.addons import Addons, AddonInstallException
-from marionette_harness import MarionetteTestCase, skip
-
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-
-class TestAddons(MarionetteTestCase):
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.addons = Addons(self.marionette)
-
- @property
- def all_addon_ids(self):
- with self.marionette.using_context('chrome'):
- addons = self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/AddonManager.jsm");
- AddonManager.getAllAddons(function(addons){
- let ids = addons.map(function(x) {
- return x.id;
- });
- marionetteScriptFinished(ids);
- });
- """)
-
- return addons
-
- def test_install_and_remove_temporary_unsigned_addon(self):
- addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
-
- addon_id = self.addons.install(addon_path, temp=True)
- self.assertIn(addon_id, self.all_addon_ids)
-
- self.addons.uninstall(addon_id)
- self.assertNotIn(addon_id, self.all_addon_ids)
-
- def test_install_unsigned_addon(self):
- addon_path = os.path.join(here, 'mn-restartless-unsigned.xpi')
-
- with self.assertRaises(AddonInstallException):
- self.addons.install(addon_path)
-
- @skip("Need to get the test extension signed")
- def test_install_and_remove_signed_addon(self):
- addon_path = os.path.join(here, 'mn-restartless-signed.xpi')
-
- addon_id = self.addons.install(addon_path)
- self.assertIn(addon_id, self.all_addon_ids)
-
- self.addons.uninstall(addon_id)
- self.assertNotIn(addon_id, self.all_addon_ids)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py b/testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py
deleted file mode 100644
index 1e77796618..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_anonymous_content.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import NoSuchElementException
-from marionette_driver.marionette import HTMLElement
-
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestAnonymousNodes(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestAnonymousNodes, self).setUp()
- self.marionette.set_context("chrome")
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test_anonymous_content.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(new_window)
-
- def tearDown(self):
- self.close_all_windows()
-
- super(TestAnonymousNodes, self).tearDown()
-
- def test_switch_to_anonymous_frame(self):
- self.marionette.find_element(By.ID, "testAnonymousContentBox")
- anon_browser_el = self.marionette.find_element(By.ID, "browser")
- self.assertTrue("test_anonymous_content.xul" in self.marionette.get_url())
- self.marionette.switch_to_frame(anon_browser_el)
- self.assertTrue("test.xul" in self.marionette.get_url())
- self.marionette.find_element(By.ID, "testXulBox")
- self.assertRaises(NoSuchElementException,
- self.marionette.find_element, By.ID, "testAnonymousContentBox")
-
- def test_switch_to_anonymous_iframe(self):
- self.marionette.find_element(By.ID, "testAnonymousContentBox")
- el = self.marionette.find_element(By.ID, "container2")
- anon_iframe_el = el.find_element(By.ANON_ATTRIBUTE, {"anonid": "iframe"})
- self.marionette.switch_to_frame(anon_iframe_el)
- self.assertTrue("test.xul" in self.marionette.get_url())
- self.marionette.find_element(By.ID, "testXulBox")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID,
- "testAnonymousContentBox")
-
- def test_find_anonymous_element_by_attribute(self):
- accept_button = (By.ANON_ATTRIBUTE, {"dlgtype": "accept"},)
- not_existent = (By.ANON_ATTRIBUTE, {"anonid": "notexistent"},)
-
- # By using the window document element
- start_node = self.marionette.find_element(By.CSS_SELECTOR, ":root")
- button = start_node.find_element(*accept_button)
- self.assertEquals(HTMLElement, type(button))
- with self.assertRaises(NoSuchElementException):
- start_node.find_element(*not_existent)
-
- # By using the default start node
- self.assertEquals(button, self.marionette.find_element(*accept_button))
- with self.assertRaises(NoSuchElementException):
- self.marionette.find_element(*not_existent)
-
- def test_find_anonymous_elements_by_attribute(self):
- dialog_buttons = (By.ANON_ATTRIBUTE, {"anonid": "buttons"},)
- not_existent = (By.ANON_ATTRIBUTE, {"anonid": "notexistent"},)
-
- # By using the window document element
- start_node = self.marionette.find_element(By.CSS_SELECTOR, ":root")
- buttons = start_node.find_elements(*dialog_buttons)
- self.assertEquals(1, len(buttons))
- self.assertEquals(HTMLElement, type(buttons[0]))
- self.assertListEqual([], start_node.find_elements(*not_existent))
-
- # By using the default start node
- self.assertListEqual(buttons, self.marionette.find_elements(*dialog_buttons))
- self.assertListEqual([], self.marionette.find_elements(*not_existent))
-
- def test_find_anonymous_children(self):
- self.assertEquals(HTMLElement, type(self.marionette.find_element(By.ANON, None)))
- self.assertEquals(2, len(self.marionette.find_elements(By.ANON, None)))
-
- frame = self.marionette.find_element(By.ID, "framebox")
- with self.assertRaises(NoSuchElementException):
- frame.find_element(By.ANON, None)
- self.assertListEqual([], frame.find_elements(By.ANON, None))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_browsermobproxy.py b/testing/marionette/harness/marionette_harness/tests/unit/test_browsermobproxy.py
deleted file mode 100644
index 64b3d1a778..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_browsermobproxy.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import datetime
-
-from marionette_harness.runner import BrowserMobTestCase
-
-
-class TestBrowserMobProxy(BrowserMobTestCase):
- """To run this test, you'll need to download the browsermob-proxy from
- http://bmp.lightbody.net/, and then pass the path to the startup
- script (typically /path/to/browsermob-proxy-2.0.0/bin/browsermob-proxy)
- as the --browsermob-script argument when running runtests.py.
-
- You can additionally pass --browsermob-port to specify the port that
- the proxy will run on; it defaults to 8080.
-
- This test is NOT run in CI, as bmp and dependencies aren't available
- there.
- """
-
- def test_browsermob_proxy_limits(self):
- """This illustrates the use of download limits in the proxy,
- and verifies that it's slower to load a page @100kbps
- than it is to download the same page @1000kbps.
- """
- proxy = self.create_browsermob_proxy()
- proxy.limits({'downstream_kbps': 1000})
- time1 = datetime.datetime.now()
- self.marionette.navigate('http://forecast.weather.gov')
- time2 = datetime.datetime.now()
- proxy.limits({'downstream_kbps': 100})
- time3 = datetime.datetime.now()
- self.marionette.refresh()
- time4 = datetime.datetime.now()
- self.assertTrue(time4 - time3 > time2 - time1,
- "page load @ 100kbps not slower than page load @ 1000kbps")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py b/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
deleted file mode 100644
index d3386316d2..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
+++ /dev/null
@@ -1,253 +0,0 @@
-# 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 SessionNotCreatedException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestCapabilities(MarionetteTestCase):
-
- def setUp(self):
- super(TestCapabilities, self).setUp()
- self.caps = self.marionette.session_capabilities
- with self.marionette.using_context("chrome"):
- self.appinfo = self.marionette.execute_script(
- "return Services.appinfo")
- self.os_name = self.marionette.execute_script(
- "return Services.sysinfo.getProperty('name')").lower()
- self.os_version = self.marionette.execute_script(
- "return Services.sysinfo.getProperty('version')")
-
- def test_mandated_capabilities(self):
- self.assertIn("browserName", self.caps)
- self.assertIn("browserVersion", self.caps)
- self.assertIn("platformName", self.caps)
- self.assertIn("platformVersion", self.caps)
- self.assertIn("acceptInsecureCerts", self.caps)
- self.assertIn("timeouts", self.caps)
-
- self.assertEqual(self.caps["browserName"], self.appinfo["name"].lower())
- self.assertEqual(self.caps["browserVersion"], self.appinfo["version"])
- self.assertEqual(self.caps["platformName"], self.os_name)
- self.assertEqual(self.caps["platformVersion"], self.os_version)
- self.assertFalse(self.caps["acceptInsecureCerts"])
- self.assertDictEqual(self.caps["timeouts"],
- {"implicit": 0,
- "page load": 300000,
- "script": 30000})
-
- def test_supported_features(self):
- self.assertIn("rotatable", self.caps)
-
- def test_additional_capabilities(self):
- self.assertIn("moz:processID", self.caps)
- self.assertEqual(self.caps["moz:processID"], self.appinfo["processID"])
- self.assertEqual(self.marionette.process_id, self.appinfo["processID"])
-
- self.assertIn("moz:profile", self.caps)
- if self.marionette.instance is not None:
- if self.caps["browserName"] == "fennec":
- current_profile = self.marionette.instance.runner.device.app_ctx.remote_profile
- else:
- current_profile = self.marionette.instance.runner.profile.profile
- self.assertEqual(self.caps["moz:profile"], current_profile)
- self.assertEqual(self.marionette.profile, current_profile)
-
- self.assertIn("moz:accessibilityChecks", self.caps)
- self.assertFalse(self.caps["moz:accessibilityChecks"])
- self.assertIn("specificationLevel", self.caps)
- self.assertEqual(self.caps["specificationLevel"], 0)
-
- def test_set_specification_level(self):
- self.marionette.delete_session()
- self.marionette.start_session({"desiredCapabilities": {"specificationLevel": 2}})
- caps = self.marionette.session_capabilities
- self.assertEqual(2, caps["specificationLevel"])
-
- self.marionette.delete_session()
- self.marionette.start_session({"requiredCapabilities": {"specificationLevel": 3}})
- caps = self.marionette.session_capabilities
- self.assertEqual(3, caps["specificationLevel"])
-
- def test_we_can_pass_in_required_capabilities_on_session_start(self):
- self.marionette.delete_session()
- capabilities = {"requiredCapabilities": {"browserName": self.appinfo["name"].lower()}}
- self.marionette.start_session(capabilities)
- caps = self.marionette.session_capabilities
- self.assertIn("browserName", caps)
-
- # Start a new session just to make sure we leave the browser in the
- # same state it was before it started the test
- self.marionette.start_session()
-
- def test_capability_types(self):
- for value in ["", "invalid", True, 42, []]:
- print("testing value {}".format(value))
- with self.assertRaises(SessionNotCreatedException):
- print(" with desiredCapabilities")
- self.marionette.delete_session()
- self.marionette.start_session({"desiredCapabilities": value})
- with self.assertRaises(SessionNotCreatedException):
- print(" with requiredCapabilities")
- self.marionette.delete_session()
- self.marionette.start_session({"requiredCapabilities": value})
-
- def test_we_get_valid_uuid4_when_creating_a_session(self):
- self.assertNotIn("{", self.marionette.session_id,
- "Session ID has {{}} in it: {}".format(
- self.marionette.session_id))
-
-
-class TestCapabilityMatching(MarionetteTestCase):
- allowed = [None, "*"]
- disallowed = ["", 42, True, {}, []]
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.browser_name = self.marionette.session_capabilities["browserName"]
- self.platform_name = self.marionette.session_capabilities["platformName"]
- self.delete_session()
-
- def delete_session(self):
- if self.marionette.session is not None:
- self.marionette.delete_session()
-
- def test_browser_name_desired(self):
- self.marionette.start_session({"desiredCapabilities": {"browserName": self.browser_name}})
- self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
-
- def test_browser_name_required(self):
- self.marionette.start_session({"requiredCapabilities": {"browserName": self.browser_name}})
- self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
-
- def test_browser_name_desired_allowed_types(self):
- for typ in self.allowed:
- self.delete_session()
- self.marionette.start_session({"desiredCapabilities": {"browserName": typ}})
- self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
-
- def test_browser_name_desired_disallowed_types(self):
- for typ in self.disallowed:
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({"desiredCapabilities": {"browserName": typ}})
-
- def test_browser_name_required_allowed_types(self):
- for typ in self.allowed:
- self.delete_session()
- self.marionette.start_session({"requiredCapabilities": {"browserName": typ}})
- self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
-
- def test_browser_name_requried_disallowed_types(self):
- for typ in self.disallowed:
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({"requiredCapabilities": {"browserName": typ}})
-
- def test_browser_name_prefers_required(self):
- caps = {"desiredCapabilities": {"browserName": "invalid"},
- "requiredCapabilities": {"browserName": "*"}}
- self.marionette.start_session(caps)
-
- def test_browser_name_error_on_invalid_required(self):
- with self.assertRaises(SessionNotCreatedException):
- caps = {"desiredCapabilities": {"browserName": "*"},
- "requiredCapabilities": {"browserName": "invalid"}}
- self.marionette.start_session(caps)
-
- # TODO(ato): browser version comparison not implemented yet
-
- def test_platform_name_desired(self):
- self.marionette.start_session({"desiredCapabilities": {"platformName": self.platform_name}})
- self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
-
- def test_platform_name_required(self):
- self.marionette.start_session({"requiredCapabilities": {"platformName": self.platform_name}})
- self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
-
- def test_platform_name_desired_allowed_types(self):
- for typ in self.allowed:
- self.delete_session()
- self.marionette.start_session({"desiredCapabilities": {"platformName": typ}})
- self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
-
- def test_platform_name_desired_disallowed_types(self):
- for typ in self.disallowed:
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({"desiredCapabilities": {"platformName": typ}})
-
- def test_platform_name_required_allowed_types(self):
- for typ in self.allowed:
- self.delete_session()
- self.marionette.start_session({"requiredCapabilities": {"platformName": typ}})
- self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
-
- def test_platform_name_requried_disallowed_types(self):
- for typ in self.disallowed:
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({"requiredCapabilities": {"platformName": typ}})
-
- def test_platform_name_prefers_required(self):
- caps = {"desiredCapabilities": {"platformName": "invalid"},
- "requiredCapabilities": {"platformName": "*"}}
- self.marionette.start_session(caps)
-
- def test_platform_name_error_on_invalid_required(self):
- with self.assertRaises(SessionNotCreatedException):
- caps = {"desiredCapabilities": {"platformName": "*"},
- "requiredCapabilities": {"platformName": "invalid"}}
- self.marionette.start_session(caps)
-
- # TODO(ato): platform version comparison not imlpemented yet
-
- def test_accept_insecure_certs(self):
- for capability_type in ["desiredCapabilities", "requiredCapabilities"]:
- print("testing {}".format(capability_type))
- for value in ["", 42, {}, []]:
- print(" type {}".format(type(value)))
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({capability_type: {"acceptInsecureCerts": value}})
-
- self.delete_session()
- self.marionette.start_session({"desiredCapabilities": {"acceptInsecureCerts": True}})
- self.assertTrue(self.marionette.session_capabilities["acceptInsecureCerts"])
- self.delete_session()
- self.marionette.start_session({"requiredCapabilities": {"acceptInsecureCerts": True}})
-
- self.assertTrue(self.marionette.session_capabilities["acceptInsecureCerts"])
-
- def test_page_load_strategy(self):
- for strategy in ["none", "eager", "normal"]:
- print("valid strategy {}".format(strategy))
- self.delete_session()
- self.marionette.start_session({"desiredCapabilities": {"pageLoadStrategy": strategy}})
- self.assertEqual(self.marionette.session_capabilities["pageLoadStrategy"], strategy)
-
- for value in ["", "EAGER", True, 42, {}, []]:
- print("invalid strategy {}".format(value))
- with self.assertRaises(SessionNotCreatedException):
- self.marionette.start_session({"desiredCapabilities": {"pageLoadStrategy": value}})
-
- def test_proxy_default(self):
- self.marionette.start_session()
- self.assertNotIn("proxy", self.marionette.session_capabilities)
-
- def test_proxy_desired(self):
- self.marionette.start_session({"desiredCapabilities": {"proxy": {"proxyType": "manual"}}})
- self.assertIn("proxy", self.marionette.session_capabilities)
- self.assertEqual(self.marionette.session_capabilities["proxy"]["proxyType"], "manual")
- self.assertEqual(self.marionette.get_pref("network.proxy.type"), 1)
-
- def test_proxy_required(self):
- self.marionette.start_session({"requiredCapabilities": {"proxy": {"proxyType": "manual"}}})
- self.assertIn("proxy", self.marionette.session_capabilities)
- self.assertEqual(self.marionette.session_capabilities["proxy"]["proxyType"], "manual")
- self.assertEqual(self.marionette.get_pref("network.proxy.type"), 1)
-
- def test_timeouts(self):
- timeouts = {u"implicit": 123, u"page load": 456, u"script": 789}
- caps = {"desiredCapabilities": {"timeouts": timeouts}}
- self.marionette.start_session(caps)
- self.assertIn("timeouts", self.marionette.session_capabilities)
- self.assertDictEqual(self.marionette.session_capabilities["timeouts"], timeouts)
- self.assertDictEqual(self.marionette._send_message("getTimeouts"), timeouts)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox.py b/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox.py
deleted file mode 100644
index 8709d6e325..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestCheckbox(MarionetteTestCase):
- def test_selected(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- box = self.marionette.find_element(By.NAME, "myCheckBox")
- self.assertFalse(box.is_selected())
- box.click()
- self.assertTrue(box.is_selected())
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox_chrome.py
deleted file mode 100644
index 8d800f9394..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_checkbox_chrome.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestSelectedChrome(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSelectedChrome, self).setUp()
-
- self.marionette.set_context("chrome")
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- '_blank', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(new_window)
-
- def tearDown(self):
- try:
- self.close_all_windows()
- finally:
- super(TestSelectedChrome, self).tearDown()
-
- def test_selected(self):
- box = self.marionette.find_element(By.ID, "testBox")
- self.assertFalse(box.is_selected())
- self.assertFalse(self.marionette.execute_script("arguments[0].checked = true;", [box]))
- self.assertTrue(box.is_selected())
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_chrome.py
deleted file mode 100644
index 8a9e53bd66..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#Copyright 2007-2009 WebDriver committers
-#Copyright 2007-2009 Google Inc.
-#
-#Licensed under the Apache License, Version 2.0 (the "License");
-#you may not use this file except in compliance with the License.
-#You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-#Unless required by applicable law or agreed to in writing, software
-#distributed under the License is distributed on an "AS IS" BASIS,
-#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#See the License for the specific language governing permissions and
-#limitations under the License.
-
-from marionette_driver import By
-
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class ChromeTests(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(ChromeTests, self).setUp()
-
- self.marionette.set_context('chrome')
-
- def tearDown(self):
- self.close_all_windows()
- super(ChromeTests, self).tearDown()
-
- def test_hang_until_timeout(self):
- def open_with_menu():
- menu = self.marionette.find_element(By.ID, 'aboutName')
- menu.click()
-
- new_window = self.open_window(trigger=open_with_menu)
- self.marionette.switch_to_window(new_window)
-
- try:
- try:
- # Raise an exception type which should not be thrown by Marionette
- # while running this test. Otherwise it would mask eg. IOError as
- # thrown for a socket timeout.
- raise NotImplementedError('Exception should not cause a hang when '
- 'closing the chrome window')
- finally:
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
- except NotImplementedError:
- pass
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js b/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js
deleted file mode 100644
index 8d2df3ac26..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js
+++ /dev/null
@@ -1,6 +0,0 @@
-MARIONETTE_TIMEOUT = 60000;
-MARIONETTE_CONTEXT = "chrome";
-ok(true);
-(function () {
- finish();
-})();
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_element_css.py b/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_element_css.py
deleted file mode 100644
index fde7e8373c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_element_css.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestChromeElementCSS(MarionetteTestCase):
-
- def test_we_can_get_css_value_on_chrome_element(self):
- self.marionette.navigate("about:blank")
- with self.marionette.using_context("chrome"):
- element = self.marionette.find_element(By.ID, "identity-icon")
- favicon_image = element.value_of_css_property("list-style-image")
-
- self.assertIn("identity-icon.svg", favicon_image)
-
- element = self.marionette.find_element(By.ID, "identity-box")
- background_colour = element.value_of_css_property("background-color")
-
- self.assertEqual("transparent", background_colour)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_clearing.py b/testing/marionette/harness/marionette_harness/tests/unit/test_clearing.py
deleted file mode 100644
index 3fcad45fca..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_clearing.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import InvalidElementStateException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestClear(MarionetteTestCase):
- def testWriteableTextInputShouldClear(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "writableTextInput")
- element.clear()
- self.assertEqual("", element.get_property("value"))
-
- def testTextInputShouldNotClearWhenReadOnly(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID,"readOnlyTextInput")
- try:
- element.clear()
- self.fail("Should not have been able to clear")
- except InvalidElementStateException:
- pass
-
- def testWritableTextAreaShouldClear(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID,"writableTextArea")
- element.clear()
- self.assertEqual("", element.get_property("value"))
-
- def testTextAreaShouldNotClearWhenDisabled(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID,"textAreaNotenabled")
- try:
- element.clear()
- self.fail("Should not have been able to clear")
- except InvalidElementStateException:
- pass
-
- def testTextAreaShouldNotClearWhenReadOnly(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID,"textAreaReadOnly")
- try:
- element.clear()
- self.fail("Should not have been able to clear")
- except InvalidElementStateException:
- pass
-
- def testContentEditableAreaShouldClear(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID,"content-editable")
- element.clear()
- self.assertEqual("", element.text)
-
- def testTextInputShouldNotClearWhenDisabled(self):
- test_html = self.marionette.absolute_url("test_clearing.html")
- self.marionette.navigate(test_html)
- try:
- element = self.marionette.find_element(By.ID,"textInputnotenabled")
- self.assertFalse(element.is_enabled())
- element.clear()
- self.fail("Should not have been able to clear")
- except InvalidElementStateException:
- pass
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py b/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
deleted file mode 100644
index 06019834a3..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click.py
+++ /dev/null
@@ -1,271 +0,0 @@
-# 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 urllib
-
-from marionette_driver.by import By
-from marionette_driver import errors
-from marionette_driver.wait import Wait
-
-from marionette_harness import MarionetteTestCase
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
-
-
-# The <a> element in the following HTML is not interactable because it
-# is hidden by an overlay when scrolled into the top of the viewport.
-# It should be interactable when scrolled in at the bottom of the
-# viewport.
-fixed_overlay = inline("""
-<style>
-* { margin: 0; padding: 0; }
-body { height: 300vh }
-div, a { display: block }
-div {
- background-color: pink;
- position: fixed;
- width: 100%;
- height: 40px;
- top: 0;
-}
-a {
- margin-top: 1000px;
-}
-</style>
-
-<div>overlay</div>
-<a href=#>link</a>
-
-<script>
-window.clicked = false;
-
-let link = document.querySelector("a");
-link.addEventListener("click", () => window.clicked = true);
-</script>
-""")
-
-
-obscured_overlay = inline("""
-<style>
-* { margin: 0; padding: 0; }
-body { height: 100vh }
-#overlay {
- background-color: pink;
- position: absolute;
- width: 100%;
- height: 100%;
-}
-</style>
-
-<div id=overlay></div>
-<a id=obscured href=#>link</a>
-
-<script>
-window.clicked = false;
-
-let link = document.querySelector("#obscured");
-link.addEventListener("click", () => window.clicked = true);
-</script>
-""")
-
-
-class TestLegacyClick(MarionetteTestCase):
- """Uses legacy Selenium element displayedness checks."""
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.delete_session()
- self.marionette.start_session()
-
- def test_click(self):
- self.marionette.navigate(inline("""
- <button>click me</button>
- <script>
- window.clicks = 0;
- let button = document.querySelector("button");
- button.addEventListener("click", () => window.clicks++);
- </script>
- """))
- button = self.marionette.find_element(By.TAG_NAME, "button")
- button.click()
- self.assertEqual(1, self.marionette.execute_script("return window.clicks", sandbox=None))
-
- def test_click_number_link(self):
- test_html = self.marionette.absolute_url("clicks.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.LINK_TEXT, "333333").click()
- Wait(self.marionette, timeout=30, ignored_exceptions=errors.NoSuchElementException).until(
- lambda m: m.find_element(By.ID, "username"))
- self.assertEqual(self.marionette.title, "XHTML Test Page")
-
- def test_clicking_an_element_that_is_not_displayed_raises(self):
- test_html = self.marionette.absolute_url("hidden.html")
- self.marionette.navigate(test_html)
-
- with self.assertRaises(errors.ElementNotInteractableException):
- self.marionette.find_element(By.ID, "child").click()
-
- def test_clicking_on_a_multiline_link(self):
- test_html = self.marionette.absolute_url("clicks.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.ID, "overflowLink").click()
- self.wait_for_condition(lambda mn: self.marionette.title == "XHTML Test Page")
-
- def test_scroll_into_view_near_end(self):
- self.marionette.navigate(fixed_overlay)
- link = self.marionette.find_element(By.TAG_NAME, "a")
- link.click()
- self.assertTrue(self.marionette.execute_script("return window.clicked", sandbox=None))
-
-
-class TestClick(TestLegacyClick):
- """Uses WebDriver specification compatible element interactability
- checks.
- """
-
- def setUp(self):
- TestLegacyClick.setUp(self)
- self.marionette.delete_session()
- self.marionette.start_session(
- {"requiredCapabilities": {"specificationLevel": 1}})
-
- def test_click_element_obscured_by_absolute_positioned_element(self):
- self.marionette.navigate(obscured_overlay)
- overlay = self.marionette.find_element(By.ID, "overlay")
- obscured = self.marionette.find_element(By.ID, "obscured")
-
- overlay.click()
- with self.assertRaises(errors.ElementClickInterceptedException):
- obscured.click()
-
- def test_centre_outside_viewport_vertically(self):
- self.marionette.navigate(inline("""
- <style>
- * { margin: 0; padding: 0; }
- div {
- display: block;
- position: absolute;
- background-color: blue;
- width: 200px;
- height: 200px;
-
- /* move centre point off viewport vertically */
- top: -105px;
- }
- </style>
-
- <div></div>"""))
-
- self.marionette.find_element(By.TAG_NAME, "div").click()
-
- def test_centre_outside_viewport_horizontally(self):
- self.marionette.navigate(inline("""
- <style>
- * { margin: 0; padding: 0; }
- div {
- display: block;
- position: absolute;
- background-color: blue;
- width: 200px;
- height: 200px;
-
- /* move centre point off viewport horizontally */
- left: -105px;
- }
- </style>
-
- <div></div>"""))
-
- self.marionette.find_element(By.TAG_NAME, "div").click()
-
- def test_centre_outside_viewport(self):
- self.marionette.navigate(inline("""
- <style>
- * { margin: 0; padding: 0; }
- div {
- display: block;
- position: absolute;
- background-color: blue;
- width: 200px;
- height: 200px;
-
- /* move centre point off viewport */
- left: -105px;
- top: -105px;
- }
- </style>
-
- <div></div>"""))
-
- self.marionette.find_element(By.TAG_NAME, "div").click()
-
- def test_css_transforms(self):
- self.marionette.navigate(inline("""
- <style>
- * { margin: 0; padding: 0; }
- div {
- display: block;
- background-color: blue;
- width: 200px;
- height: 200px;
-
- transform: translateX(-105px);
- }
- </style>
-
- <div></div>"""))
-
- self.marionette.find_element(By.TAG_NAME, "div").click()
-
- def test_input_file(self):
- self.marionette.navigate(inline("<input type=file>"))
- with self.assertRaises(errors.InvalidArgumentException):
- self.marionette.find_element(By.TAG_NAME, "input").click()
-
- def test_container_element(self):
- self.marionette.navigate(inline("""
- <select>
- <option>foo</option>
- </select>"""))
- option = self.marionette.find_element(By.TAG_NAME, "option")
- option.click()
- self.assertTrue(option.get_property("selected"))
-
- def test_container_element_outside_view(self):
- self.marionette.navigate(inline("""
- <select style="margin-top: 100vh">
- <option>foo</option>
- </select>"""))
- option = self.marionette.find_element(By.TAG_NAME, "option")
- option.click()
- self.assertTrue(option.get_property("selected"))
-
- def test_obscured_element(self):
- self.marionette.navigate(obscured_overlay)
- overlay = self.marionette.find_element(By.ID, "overlay")
- obscured = self.marionette.find_element(By.ID, "obscured")
-
- overlay.click()
- with self.assertRaises(errors.ElementClickInterceptedException):
- obscured.click()
- self.assertFalse(self.marionette.execute_script("return window.clicked", sandbox=None))
-
- def test_pointer_events_none(self):
- self.marionette.navigate(inline("""
- <button style="pointer-events: none">click me</button>
- <script>
- window.clicked = false;
- let button = document.querySelector("button");
- button.addEventListener("click", () => window.clicked = true);
- </script>
- """))
- button = self.marionette.find_element(By.TAG_NAME, "button")
- self.assertEqual("none", button.value_of_css_property("pointer-events"))
-
- with self.assertRaisesRegexp(errors.ElementClickInterceptedException,
- "does not have pointer events enabled"):
- button.click()
- self.assertFalse(self.marionette.execute_script("return window.clicked", sandbox=None))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py
deleted file mode 100644
index d16b4f1054..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click_chrome.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestClickChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.root_window = self.marionette.current_window_handle
- self.marionette.set_context("chrome")
- self.marionette.execute_script(
- "window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen')")
- self.marionette.switch_to_window("foo")
- self.assertNotEqual(self.root_window, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.root_window, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close()")
- self.marionette.switch_to_window(self.root_window)
- MarionetteTestCase.tearDown(self)
-
- def test_click(self):
- def checked():
- return self.marionette.execute_script(
- "return arguments[0].checked",
- script_args=[box])
-
- box = self.marionette.find_element(By.ID, "testBox")
- self.assertFalse(checked())
- box.click()
- self.assertTrue(checked())
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py b/testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py
deleted file mode 100644
index 437c15e702..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import MoveTargetOutOfBoundsException
-
-from marionette_harness import MarionetteTestCase, skip, skip_if_mobile
-
-
-class TestClickScrolling(MarionetteTestCase):
-
-
- def test_clicking_on_anchor_scrolls_page(self):
- scrollScript = """
- var pageY;
- if (typeof(window.pageYOffset) == 'number') {
- pageY = window.pageYOffset;
- } else {
- pageY = document.documentElement.scrollTop;
- }
- return pageY;"""
-
- test_html = self.marionette.absolute_url("macbeth.html")
- self.marionette.navigate(test_html)
-
- self.marionette.find_element(By.PARTIAL_LINK_TEXT, "last speech").click()
- y_offset = self.marionette.execute_script(scrollScript)
-
- # Focusing on to click, but not actually following,
- # the link will scroll it in to view, which is a few
- # pixels further than 0
-
- self.assertTrue(y_offset > 300)
-
- def test_should_scroll_to_click_on_an_element_hidden_by_overflow(self):
- test_html = self.marionette.absolute_url("click_out_of_bounds_overflow.html")
- self.marionette.navigate(test_html)
-
- link = self.marionette.find_element(By.ID, "link")
- try:
- link.click()
- except MoveTargetOutOfBoundsException:
- self.fail("Should not be out of bounds")
-
- @skip("Bug 1200197 - Cannot interact with elements hidden inside overflow:scroll")
- def test_should_be_able_to_click_on_an_element_hidden_by_overflow(self):
- test_html = self.marionette.absolute_url("scroll.html")
- self.marionette.navigate(test_html)
-
- link = self.marionette.find_element(By.ID, "line8")
- link.click()
- self.assertEqual("line8", self.marionette.find_element(By.ID, "clicked").text)
-
- def test_should_not_scroll_overflow_elements_which_are_visible(self):
- test_html = self.marionette.absolute_url("scroll2.html")
- self.marionette.navigate(test_html)
-
- list_el = self.marionette.find_element(By.TAG_NAME, "ul")
- item = list_el.find_element(By.ID, "desired")
- item.click()
- y_offset = self.marionette.execute_script("return arguments[0].scrollTop;", script_args=[list_el])
- self.assertEqual(0, y_offset)
-
- def test_should_not_scroll_if_already_scrolled_and_element_is_in_view(self):
- test_html = self.marionette.absolute_url("scroll3.html")
- self.marionette.navigate(test_html)
-
- button1 = self.marionette.find_element(By.ID, "button1")
- button2 = self.marionette.find_element(By.ID, "button2")
-
- button2.click()
- scroll_top = self.marionette.execute_script("return document.body.scrollTop;")
- button1.click()
-
- self.assertEqual(scroll_top, self.marionette.execute_script("return document.body.scrollTop;"))
-
- def test_should_be_able_to_click_radio_button_scrolled_into_view(self):
- test_html = self.marionette.absolute_url("scroll4.html")
- self.marionette.navigate(test_html)
-
- # If we dont throw we are good
- self.marionette.find_element(By.ID, "radio").click()
-
- def test_should_scroll_elements_if_click_point_is_out_of_view_but_element_is_in_view(self):
- test_html = self.marionette.absolute_url("element_outside_viewport.html")
-
- for s in ["top", "bottom"]:
- self.marionette.navigate(test_html)
- scroll_y = self.marionette.execute_script("return window.scrollY;")
- self.marionette.find_element(By.ID, "{}-70".format(s)).click()
- self.assertNotEqual(scroll_y, self.marionette.execute_script("return window.scrollY;"))
-
- for s in ["left", "right"]:
- self.marionette.navigate(test_html)
- scroll_x = self.marionette.execute_script("return window.scrollX;")
- self.marionette.find_element(By.ID, "{}-70".format(s)).click()
- self.assertNotEqual(scroll_x, self.marionette.execute_script("return window.scrollX;"))
-
- @skip_if_mobile("Bug 1293855 - Lists differ: [70, 70] != [70, 120]")
- def test_should_not_scroll_elements_if_click_point_is_in_view(self):
- test_html = self.marionette.absolute_url("element_outside_viewport.html")
-
- for s in ["top", "right", "bottom", "left"]:
- for p in ["50", "30"]:
- self.marionette.navigate(test_html)
- scroll = self.marionette.execute_script("return [window.scrollX, window.scrollY];")
- self.marionette.find_element(By.ID, "{0}-{1}".format(s, p)).click()
- self.assertEqual(scroll, self.marionette.execute_script("return [window.scrollX, window.scrollY];"))
-
- @skip("Bug 1003687")
- def test_should_scroll_overflow_elements_if_click_point_is_out_of_view_but_element_is_in_view(self):
- test_html = self.marionette.absolute_url("scroll5.html")
- self.marionette.navigate(test_html)
-
- self.marionette.find_element(By.ID, "inner").click()
- self.assertEqual("clicked", self.marionette.find_element(By.ID, "clicked").text)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_cookies.py b/testing/marionette/harness/marionette_harness/tests/unit/test_cookies.py
deleted file mode 100644
index f7841c73e0..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_cookies.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# 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 calendar
-import random
-import time
-
-from marionette_driver.errors import UnsupportedOperationException
-from marionette_harness import MarionetteTestCase
-
-
-class CookieTest(MarionetteTestCase):
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- test_url = self.marionette.absolute_url('test.html')
- self.marionette.navigate(test_url)
- self.COOKIE_A = {"name": "foo",
- "value": "bar",
- "path": "/",
- "secure": False}
-
- def tearDown(self):
- self.marionette.delete_all_cookies()
- MarionetteTestCase.tearDown(self)
-
- def test_add_cookie(self):
- self.marionette.add_cookie(self.COOKIE_A)
- cookie_returned = str(self.marionette.execute_script("return document.cookie"))
- self.assertTrue(self.COOKIE_A["name"] in cookie_returned)
-
- def test_adding_a_cookie_that_expired_in_the_past(self):
- cookie = self.COOKIE_A.copy()
- cookie["expiry"] = calendar.timegm(time.gmtime()) - 1
- self.marionette.add_cookie(cookie)
- cookies = self.marionette.get_cookies()
- self.assertEquals(0, len(cookies))
-
- def test_chrome_error(self):
- with self.marionette.using_context("chrome"):
- self.assertRaises(UnsupportedOperationException,
- self.marionette.add_cookie, self.COOKIE_A)
- self.assertRaises(UnsupportedOperationException,
- self.marionette.delete_cookie, self.COOKIE_A)
- self.assertRaises(UnsupportedOperationException,
- self.marionette.delete_all_cookies)
- self.assertRaises(UnsupportedOperationException,
- self.marionette.get_cookies)
-
- def test_delete_all_cookie(self):
- self.marionette.add_cookie(self.COOKIE_A)
- cookie_returned = str(self.marionette.execute_script("return document.cookie"))
- print cookie_returned
- self.assertTrue(self.COOKIE_A["name"] in cookie_returned)
- self.marionette.delete_all_cookies()
- self.assertFalse(self.marionette.get_cookies())
-
- def test_delete_cookie(self):
- self.marionette.add_cookie(self.COOKIE_A)
- cookie_returned = str(self.marionette.execute_script("return document.cookie"))
- self.assertTrue(self.COOKIE_A["name"] in cookie_returned)
- self.marionette.delete_cookie("foo")
- cookie_returned = str(self.marionette.execute_script("return document.cookie"))
- self.assertFalse(self.COOKIE_A["name"] in cookie_returned)
-
- def test_should_get_cookie_by_name(self):
- key = "key_{}".format(int(random.random()*10000000))
- self.marionette.execute_script("document.cookie = arguments[0] + '=set';", [key])
-
- cookie = self.marionette.get_cookie(key)
- self.assertEquals("set", cookie["value"])
-
- def test_get_all_cookies(self):
- key1 = "key_{}".format(int(random.random()*10000000))
- key2 = "key_{}".format(int(random.random()*10000000))
-
- cookies = self.marionette.get_cookies()
- count = len(cookies)
-
- one = {"name" :key1,
- "value": "value"}
- two = {"name":key2,
- "value": "value"}
-
- self.marionette.add_cookie(one)
- self.marionette.add_cookie(two)
-
- test_url = self.marionette.absolute_url('test.html')
- self.marionette.navigate(test_url)
- cookies = self.marionette.get_cookies()
- self.assertEquals(count + 2, len(cookies))
-
- def test_should_not_delete_cookies_with_a_similar_name(self):
- cookieOneName = "fish"
- cookie1 = {"name" :cookieOneName,
- "value":"cod"}
- cookie2 = {"name" :cookieOneName + "x",
- "value": "earth"}
- self.marionette.add_cookie(cookie1)
- self.marionette.add_cookie(cookie2)
-
- self.marionette.delete_cookie(cookieOneName)
- cookies = self.marionette.get_cookies()
-
- self.assertFalse(cookie1["name"] == cookies[0]["name"], msg=str(cookies))
- self.assertEquals(cookie2["name"] , cookies[0]["name"], msg=str(cookies))
-
- def test_we_get_required_elements_when_available(self):
- self.marionette.add_cookie(self.COOKIE_A)
- cookies = self.marionette.get_cookies()
-
- self.assertIn("name", cookies[0], 'name not available')
- self.assertIn("value", cookies[0], 'value not available')
- self.assertIn("httpOnly", cookies[0], 'httpOnly not available')
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_crash.py b/testing/marionette/harness/marionette_harness/tests/unit/test_crash.py
deleted file mode 100644
index 7e74f0857a..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_crash.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# 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 glob
-import shutil
-
-from marionette_driver.errors import MarionetteException
-# Import runner module to monkey patch mozcrash module
-from mozrunner.base import runner
-
-from marionette_harness import MarionetteTestCase, expectedFailure, run_if_e10s
-
-
-class MockMozCrash(object):
- """Mock object to replace original mozcrash methods."""
-
- def __init__(self, marionette):
- self.marionette = marionette
-
- with self.marionette.using_context('chrome'):
- self.crash_reporter_enabled = self.marionette.execute_script("""
- try {
- Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
- getService(Components.interfaces.nsICrashReporter);
- return true;
- } catch (exc) {
- return false;
- }
- """)
-
- def check_for_crashes(self, dump_directory, *args, **kwargs):
- minidump_files = glob.glob('{}/*.dmp'.format(dump_directory))
- shutil.rmtree(dump_directory, ignore_errors=True)
-
- if self.crash_reporter_enabled:
- return len(minidump_files)
- else:
- return len(minidump_files) == 0
-
- def log_crashes(self, logger, dump_directory, *args, **kwargs):
- return self.check_for_crashes(dump_directory, *args, **kwargs)
-
-
-class BaseCrashTestCase(MarionetteTestCase):
-
- # Reduce the timeout for faster processing of the tests
- socket_timeout = 10
-
- def setUp(self):
- super(BaseCrashTestCase, self).setUp()
-
- self.mozcrash_mock = MockMozCrash(self.marionette)
- self.crash_count = self.marionette.crashed
- self.pid = self.marionette.process_id
- self.remote_uri = self.marionette.absolute_url("javascriptPage.html")
-
- def tearDown(self):
- self.marionette.crashed = self.crash_count
-
- super(BaseCrashTestCase, self).tearDown()
-
- def crash(self, chrome=True):
- context = 'chrome' if chrome else 'content'
- sandbox = None if chrome else 'system'
-
- # Monkey patch mozcrash to avoid crash info output only for our triggered crashes.
- mozcrash = runner.mozcrash
- runner.mozcrash = self.mozcrash_mock
-
- socket_timeout = self.marionette.client.socket_timeout
-
- self.marionette.set_context(context)
- try:
- self.marionette.client.socket_timeout = self.socket_timeout
- self.marionette.execute_script("""
- // Copied from crash me simple
- Components.utils.import("resource://gre/modules/ctypes.jsm");
-
- // ctypes checks for NULL pointer derefs, so just go near-NULL.
- var zero = new ctypes.intptr_t(8);
- var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
- var crash = badptr.contents;
- """, sandbox=sandbox)
- finally:
- runner.mozcrash = mozcrash
- self.marionette.client.socket_timeout = socket_timeout
-
-
-class TestCrash(BaseCrashTestCase):
-
- def test_crash_chrome_process(self):
- self.assertRaisesRegexp(IOError, 'Process crashed',
- self.crash, chrome=True)
- self.assertEqual(self.marionette.crashed, 1)
- self.assertIsNone(self.marionette.session)
- self.assertRaisesRegexp(MarionetteException, 'Please start a session',
- self.marionette.get_url)
-
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- # TODO: Bug 1314594 - Causes a hang for the communication between the
- # chrome and frame script.
- # self.marionette.get_url()
-
- @run_if_e10s("Content crashes only exist in e10s mode")
- def test_crash_content_process(self):
- # If e10s is disabled the chrome process crashes
- self.marionette.navigate(self.remote_uri)
-
- self.assertRaisesRegexp(IOError, 'Content process crashed',
- self.crash, chrome=False)
- self.assertEqual(self.marionette.crashed, 1)
- self.assertIsNone(self.marionette.session)
- self.assertRaisesRegexp(MarionetteException, 'Please start a session',
- self.marionette.get_url)
-
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.process_id, self.pid)
- self.marionette.get_url()
-
- @expectedFailure
- def test_unexpected_crash(self):
- self.crash(chrome=True)
-
-
-class TestCrashInSetUp(BaseCrashTestCase):
-
- def setUp(self):
- super(TestCrashInSetUp, self).setUp()
-
- self.assertRaisesRegexp(IOError, 'Process crashed',
- self.crash, chrome=True)
- self.assertEqual(self.marionette.crashed, 1)
- self.assertIsNone(self.marionette.session)
-
- def test_crash_in_setup(self):
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
-
-class TestCrashInTearDown(BaseCrashTestCase):
-
- def tearDown(self):
- try:
- self.assertRaisesRegexp(IOError, 'Process crashed',
- self.crash, chrome=True)
- finally:
- self.assertEqual(self.marionette.crashed, 1)
- self.assertIsNone(self.marionette.session)
- super(TestCrashInTearDown, self).tearDown()
-
- def test_crash_in_teardown(self):
- pass
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_data_driven.py b/testing/marionette/harness/marionette_harness/tests/unit/test_data_driven.py
deleted file mode 100644
index 8e4ae0d323..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_data_driven.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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_harness.marionette_test import (
- parameterized,
- with_parameters,
- MetaParameterized,
- MarionetteTestCase
-)
-
-class Parameterizable(object):
- __metaclass__ = MetaParameterized
-
-class TestDataDriven(MarionetteTestCase):
- def test_parameterized(self):
- class Test(Parameterizable):
- def __init__(self):
- self.parameters = []
-
- @parameterized('1', 'thing', named=43)
- @parameterized('2', 'thing2')
- def test(self, thing, named=None):
- self.parameters.append((thing, named))
-
- self.assertFalse(hasattr(Test, 'test'))
- self.assertTrue(hasattr(Test, 'test_1'))
- self.assertTrue(hasattr(Test, 'test_2'))
-
- test = Test()
- test.test_1()
- test.test_2()
-
- self.assertEquals(test.parameters, [('thing', 43), ('thing2', None)])
-
- def test_with_parameters(self):
- DATA = [('1', ('thing',), {'named': 43}),
- ('2', ('thing2',), {'named': None})]
-
- class Test(Parameterizable):
- def __init__(self):
- self.parameters = []
-
- @with_parameters(DATA)
- def test(self, thing, named=None):
- self.parameters.append((thing, named))
-
- self.assertFalse(hasattr(Test, 'test'))
- self.assertTrue(hasattr(Test, 'test_1'))
- self.assertTrue(hasattr(Test, 'test_2'))
-
- test = Test()
- test.test_1()
- test.test_2()
-
- self.assertEquals(test.parameters, [('thing', 43), ('thing2', None)])
-
- def test_parameterized_same_name_raises_error(self):
- with self.assertRaises(KeyError):
- class Test(Parameterizable):
- @parameterized('1', 'thing', named=43)
- @parameterized('1', 'thing2')
- def test(self, thing, named=None):
- pass
-
- def test_marionette_test_case_is_parameterizable(self):
- self.assertTrue(issubclass(MarionetteTestCase.__metaclass__, MetaParameterized))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_date_time_value.py b/testing/marionette/harness/marionette_harness/tests/unit/test_date_time_value.py
deleted file mode 100644
index 2d224fff29..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_date_time_value.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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 datetime import datetime
-
-from marionette_driver.by import By
-from marionette_driver.date_time_value import DateTimeValue
-from marionette_harness import MarionetteTestCase
-
-
-class TestDateTime(MarionetteTestCase):
- def test_set_date(self):
- test_html = self.marionette.absolute_url("datetimePage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "date-test")
- dt_value = DateTimeValue(element)
- dt_value.date = datetime(1998, 6, 2)
- self.assertEqual("1998-06-02", element.get_property("value"))
-
- def test_set_time(self):
- test_html = self.marionette.absolute_url("datetimePage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "time-test")
- dt_value = DateTimeValue(element)
- dt_value.time = datetime(1998, 11, 19, 9, 8, 7)
- self.assertEqual("09:08:07", element.get_property("value"))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_element_retrieval.py b/testing/marionette/harness/marionette_harness/tests/unit/test_element_retrieval.py
deleted file mode 100644
index 9023a84ab1..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_element_retrieval.py
+++ /dev/null
@@ -1,483 +0,0 @@
-# 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 re
-import urllib
-
-from marionette_driver.by import By
-from marionette_driver.errors import NoSuchElementException, InvalidSelectorException
-from marionette_driver.marionette import HTMLElement
-
-from marionette_harness import MarionetteTestCase, skip
-
-
-def inline(doc, doctype="html"):
- if doctype == "html":
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
- elif doctype == "xhtml":
- return "data:application/xhtml+xml,{}".format(urllib.quote(
-r"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>XHTML might be the future</title>
- </head>
-
- <body>
- {}
- </body>
-</html>""".format(doc)))
-
-
-id_html = inline("<p id=foo></p>", doctype="html")
-id_xhtml = inline('<p id="foo"></p>', doctype="xhtml")
-parent_child_html = inline("<div id=parent><p id=child></p></div>", doctype="html")
-parent_child_xhtml = inline('<div id="parent"><p id="child"></p></div>', doctype="xhtml")
-children_html = inline("<div><p>foo <p>bar</div>", doctype="html")
-children_xhtml = inline("<div><p>foo</p> <p>bar</p></div>", doctype="xhtml")
-class_html = inline("<p class='foo bar'>", doctype="html")
-class_xhtml = inline('<p class="foo bar"></p>', doctype="xhtml")
-name_html = inline("<p name=foo>", doctype="html")
-name_xhtml = inline('<p name="foo"></p>', doctype="xhtml")
-link_html = inline("<p><a href=#>foo bar</a>", doctype="html")
-link_html_with_trailing_space = inline("<p><a href=#>a link with a trailing space </a>")
-link_xhtml = inline('<p><a href="#">foo bar</a></p>', doctype="xhtml")
-
-
-class TestFindElementHTML(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.timeout.implicit = 0
-
- def test_id(self):
- self.marionette.navigate(id_html)
- expected = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.ID, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(expected, found)
-
- def test_child_element(self):
- self.marionette.navigate(parent_child_html)
- parent = self.marionette.find_element(By.ID, "parent")
- child = self.marionette.find_element(By.ID, "child")
- found = parent.find_element(By.TAG_NAME, "p")
- self.assertEqual(found.tag_name, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(child, found)
-
- def test_tag_name(self):
- self.marionette.navigate(children_html)
- el = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.TAG_NAME, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_class_name(self):
- self.marionette.navigate(class_html)
- el = self.marionette.execute_script("return document.querySelector('.foo')")
- found = self.marionette.find_element(By.CLASS_NAME, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_by_name(self):
- self.marionette.navigate(name_html)
- el = self.marionette.execute_script("return document.querySelector('[name=foo]')")
- found = self.marionette.find_element(By.NAME, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_css_selector(self):
- self.marionette.navigate(children_html)
- el = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.CSS_SELECTOR, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_invalid_css_selector_should_throw(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_element(By.CSS_SELECTOR, "#")
-
- def test_link_text(self):
- self.marionette.navigate(link_html)
- el = self.marionette.execute_script("return document.querySelector('a')")
- found = self.marionette.find_element(By.LINK_TEXT, "foo bar")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_link_text_with_trailing_space(self):
- self.marionette.navigate(link_html_with_trailing_space)
- el = self.marionette.execute_script("return document.querySelector('a')")
- found = self.marionette.find_element(By.LINK_TEXT, "a link with a trailing space")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_partial_link_text(self):
- self.marionette.navigate(link_html)
- el = self.marionette.execute_script("return document.querySelector('a')")
- found = self.marionette.find_element(By.PARTIAL_LINK_TEXT, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_xpath(self):
- self.marionette.navigate(id_html)
- el = self.marionette.execute_script("return document.querySelector('#foo')")
- found = self.marionette.find_element(By.XPATH, "id('foo')")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_not_found(self):
- self.marionette.timeout.implicit = 0
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.CLASS_NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.CSS_SELECTOR, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.PARTIAL_LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.TAG_NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.XPATH, "cheese")
-
- def test_not_found_implicit_wait(self):
- self.marionette.timeout.implicit = 0.5
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.CLASS_NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.CSS_SELECTOR, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.PARTIAL_LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.TAG_NAME, "cheese")
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.XPATH, "cheese")
-
- def test_not_found_from_element(self):
- self.marionette.timeout.implicit = 0
- self.marionette.navigate(id_html)
- el = self.marionette.find_element(By.ID, "foo")
- self.assertRaises(NoSuchElementException, el.find_element, By.CLASS_NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.CSS_SELECTOR, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.ID, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.PARTIAL_LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.TAG_NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.XPATH, "cheese")
-
- def test_not_found_implicit_wait_from_element(self):
- self.marionette.timeout.implicit = 0.5
- self.marionette.navigate(id_html)
- el = self.marionette.find_element(By.ID, "foo")
- self.assertRaises(NoSuchElementException, el.find_element, By.CLASS_NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.CSS_SELECTOR, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.ID, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.PARTIAL_LINK_TEXT, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.TAG_NAME, "cheese")
- self.assertRaises(NoSuchElementException, el.find_element, By.XPATH, "cheese")
-
- def test_css_selector_scope_doesnt_start_at_rootnode(self):
- self.marionette.navigate(parent_child_html)
- el = self.marionette.find_element(By.ID, "child")
- parent = self.marionette.find_element(By.ID, "parent")
- found = parent.find_element(By.CSS_SELECTOR, "p")
- self.assertEqual(el, found)
-
- def test_unknown_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_elements("foo", "bar")
-
- def test_element_id_is_valid_uuid(self):
- self.marionette.navigate(id_html)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- uuid_regex = re.compile('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')
- self.assertIsNotNone(re.search(uuid_regex, el.id),
- 'UUID for the WebElement is not valid. ID is {}'\
- .format(el.id))
-
- def test_invalid_xpath_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_element(By.XPATH, "count(//input)")
- with self.assertRaises(InvalidSelectorException):
- parent = self.marionette.execute_script("return document.documentElement")
- parent.find_element(By.XPATH, "count(//input)")
-
- def test_invalid_css_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_element(By.CSS_SELECTOR, "")
- with self.assertRaises(InvalidSelectorException):
- parent = self.marionette.execute_script("return document.documentElement")
- parent.find_element(By.CSS_SELECTOR, "")
-
- def test_finding_active_element_returns_element(self):
- self.marionette.navigate(id_html)
- active = self.marionette.execute_script("return document.activeElement")
- self.assertEqual(active, self.marionette.get_active_element())
-
-
-class TestFindElementXHTML(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.timeout.implicit = 0
-
- def test_id(self):
- self.marionette.navigate(id_xhtml)
- expected = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.ID, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(expected, found)
-
- def test_child_element(self):
- self.marionette.navigate(parent_child_xhtml)
- parent = self.marionette.find_element(By.ID, "parent")
- child = self.marionette.find_element(By.ID, "child")
- found = parent.find_element(By.TAG_NAME, "p")
- self.assertEqual(found.tag_name, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(child, found)
-
- def test_tag_name(self):
- self.marionette.navigate(children_xhtml)
- el = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.TAG_NAME, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_class_name(self):
- self.marionette.navigate(class_xhtml)
- el = self.marionette.execute_script("return document.querySelector('.foo')")
- found = self.marionette.find_element(By.CLASS_NAME, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_by_name(self):
- self.marionette.navigate(name_xhtml)
- el = self.marionette.execute_script("return document.querySelector('[name=foo]')")
- found = self.marionette.find_element(By.NAME, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_css_selector(self):
- self.marionette.navigate(children_xhtml)
- el = self.marionette.execute_script("return document.querySelector('p')")
- found = self.marionette.find_element(By.CSS_SELECTOR, "p")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_link_text(self):
- self.marionette.navigate(link_xhtml)
- el = self.marionette.execute_script("return document.querySelector('a')")
- found = self.marionette.find_element(By.LINK_TEXT, "foo bar")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_partial_link_text(self):
- self.marionette.navigate(link_xhtml)
- el = self.marionette.execute_script("return document.querySelector('a')")
- found = self.marionette.find_element(By.PARTIAL_LINK_TEXT, "foo")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_xpath(self):
- self.marionette.navigate(id_xhtml)
- el = self.marionette.execute_script("return document.querySelector('#foo')")
- found = self.marionette.find_element(By.XPATH, "id('foo')")
- self.assertIsInstance(found, HTMLElement)
- self.assertEqual(el, found)
-
- def test_css_selector_scope_does_not_start_at_rootnode(self):
- self.marionette.navigate(parent_child_xhtml)
- el = self.marionette.find_element(By.ID, "child")
- parent = self.marionette.find_element(By.ID, "parent")
- found = parent.find_element(By.CSS_SELECTOR, "p")
- self.assertEqual(el, found)
-
- def test_active_element(self):
- self.marionette.navigate(id_xhtml)
- active = self.marionette.execute_script("return document.activeElement")
- self.assertEqual(active, self.marionette.get_active_element())
-
-
-class TestFindElementsHTML(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.timeout.implicit = 0
-
- def assertItemsIsInstance(self, items, typ):
- for item in items:
- self.assertIsInstance(item, typ)
-
- def test_child_elements(self):
- self.marionette.navigate(children_html)
- parent = self.marionette.find_element(By.TAG_NAME, "div")
- children = self.marionette.find_elements(By.TAG_NAME, "p")
- found = parent.find_elements(By.TAG_NAME, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(found, children)
-
- def test_tag_name(self):
- self.marionette.navigate(children_html)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.TAG_NAME, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_class_name(self):
- self.marionette.navigate(class_html)
- els = self.marionette.execute_script("return document.querySelectorAll('.foo')")
- found = self.marionette.find_elements(By.CLASS_NAME, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_by_name(self):
- self.marionette.navigate(name_html)
- els = self.marionette.execute_script("return document.querySelectorAll('[name=foo]')")
- found = self.marionette.find_elements(By.NAME, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_css_selector(self):
- self.marionette.navigate(children_html)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.CSS_SELECTOR, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_invalid_css_selector_should_throw(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_elements(By.CSS_SELECTOR, "#")
-
- def test_link_text(self):
- self.marionette.navigate(link_html)
- els = self.marionette.execute_script("return document.querySelectorAll('a')")
- found = self.marionette.find_elements(By.LINK_TEXT, "foo bar")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_link_text_with_trailing_space(self):
- self.marionette.navigate(link_html_with_trailing_space)
- els = self.marionette.execute_script("return document.querySelectorAll('a')")
- found = self.marionette.find_elements(By.LINK_TEXT, "a link with a trailing space")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
-
- def test_partial_link_text(self):
- self.marionette.navigate(link_html)
- els = self.marionette.execute_script("return document.querySelectorAll('a')")
- found = self.marionette.find_elements(By.PARTIAL_LINK_TEXT, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_xpath(self):
- self.marionette.navigate(children_html)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.XPATH, ".//p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_css_selector_scope_doesnt_start_at_rootnode(self):
- self.marionette.navigate(parent_child_html)
- els = self.marionette.find_elements(By.ID, "child")
- parent = self.marionette.find_element(By.ID, "parent")
- found = parent.find_elements(By.CSS_SELECTOR, "p")
- self.assertSequenceEqual(els, found)
-
- def test_unknown_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_element("foo", "bar")
-
- def test_element_id_is_valid_uuid(self):
- self.marionette.navigate(id_html)
- els = self.marionette.find_elements(By.TAG_NAME, "p")
- uuid_regex = re.compile('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')
- self.assertIsNotNone(re.search(uuid_regex, els[0].id),
- 'UUID for the WebElement is not valid. ID is {}'\
- .format(els[0].id))
-
- def test_invalid_xpath_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_elements(By.XPATH, "count(//input)")
- with self.assertRaises(InvalidSelectorException):
- parent = self.marionette.execute_script("return document.documentElement")
- parent.find_elements(By.XPATH, "count(//input)")
-
- def test_invalid_css_selector(self):
- with self.assertRaises(InvalidSelectorException):
- self.marionette.find_elements(By.CSS_SELECTOR, "")
- with self.assertRaises(InvalidSelectorException):
- parent = self.marionette.execute_script("return document.documentElement")
- parent.find_elements(By.CSS_SELECTOR, "")
-
-
-class TestFindElementsXHTML(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.timeout.implicit = 0
-
- def assertItemsIsInstance(self, items, typ):
- for item in items:
- self.assertIsInstance(item, typ)
-
- def test_child_elements(self):
- self.marionette.navigate(children_xhtml)
- parent = self.marionette.find_element(By.TAG_NAME, "div")
- children = self.marionette.find_elements(By.TAG_NAME, "p")
- found = parent.find_elements(By.TAG_NAME, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(found, children)
-
- def test_tag_name(self):
- self.marionette.navigate(children_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.TAG_NAME, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_class_name(self):
- self.marionette.navigate(class_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('.foo')")
- found = self.marionette.find_elements(By.CLASS_NAME, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_by_name(self):
- self.marionette.navigate(name_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('[name=foo]')")
- found = self.marionette.find_elements(By.NAME, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_css_selector(self):
- self.marionette.navigate(children_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.CSS_SELECTOR, "p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_link_text(self):
- self.marionette.navigate(link_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('a')")
- found = self.marionette.find_elements(By.LINK_TEXT, "foo bar")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_partial_link_text(self):
- self.marionette.navigate(link_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('a')")
- found = self.marionette.find_elements(By.PARTIAL_LINK_TEXT, "foo")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- @skip("XHTML namespace not yet supported")
- def test_xpath(self):
- self.marionette.navigate(children_xhtml)
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- found = self.marionette.find_elements(By.XPATH, "//xhtml:p")
- self.assertItemsIsInstance(found, HTMLElement)
- self.assertSequenceEqual(els, found)
-
- def test_css_selector_scope_doesnt_start_at_rootnode(self):
- self.marionette.navigate(parent_child_xhtml)
- els = self.marionette.find_elements(By.ID, "child")
- parent = self.marionette.find_element(By.ID, "parent")
- found = parent.find_elements(By.CSS_SELECTOR, "p")
- self.assertSequenceEqual(els, found)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_element_state.py b/testing/marionette/harness/marionette_harness/tests/unit/test_element_state.py
deleted file mode 100644
index 0344b4b9ce..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_element_state.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# 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 types
-import urllib
-
-from marionette_driver.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-boolean_attributes = {
- "audio": ["autoplay", "controls", "loop", "muted"],
- "button": ["autofocus", "disabled", "formnovalidate"],
- "details": ["open"],
- "dialog": ["open"],
- "fieldset": ["disabled"],
- "form": ["novalidate"],
- "iframe": ["allowfullscreen"],
- "img": ["ismap"],
- "input": ["autofocus", "checked", "disabled", "formnovalidate", "multiple", "readonly", "required"],
- "menuitem": ["checked", "default", "disabled"],
- "object": ["typemustmatch"],
- "ol": ["reversed"],
- "optgroup": ["disabled"],
- "option": ["disabled", "selected"],
- "script": ["async", "defer"],
- "select": ["autofocus", "disabled", "multiple", "required"],
- "textarea": ["autofocus", "disabled", "readonly", "required"],
- "track": ["default"],
- "video": ["autoplay", "controls", "loop", "muted"],
-}
-
-
-def inline(doc, doctype="html"):
- if doctype == "html":
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
- elif doctype == "xhtml":
- return "data:application/xhtml+xml,{}".format(urllib.quote(
-r"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>XHTML might be the future</title>
- </head>
-
- <body>
- {}
- </body>
-</html>""".format(doc)))
-
-
-attribute = inline("<input foo=bar>")
-input = inline("<input>")
-disabled = inline("<input disabled=baz>")
-check = inline("<input type=checkbox>")
-
-
-class TestIsElementEnabled(MarionetteTestCase):
- def test_is_enabled(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- l = self.marionette.find_element(By.NAME, "myCheckBox")
- self.assertTrue(l.is_enabled())
- self.marionette.execute_script("arguments[0].disabled = true;", [l])
- self.assertFalse(l.is_enabled())
-
-
-class TestIsElementDisplayed(MarionetteTestCase):
- def test_is_displayed(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- l = self.marionette.find_element(By.NAME, "myCheckBox")
- self.assertTrue(l.is_displayed())
- self.marionette.execute_script("arguments[0].hidden = true;", [l])
- self.assertFalse(l.is_displayed())
-
-
-class TestGetElementAttribute(MarionetteTestCase):
- def test_normal_attribute(self):
- self.marionette.navigate(inline("<p style=foo>"))
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("style")
- self.assertIsInstance(attr, types.StringTypes)
- self.assertEqual("foo", attr)
-
- def test_boolean_attributes(self):
- for tag, attrs in boolean_attributes.iteritems():
- for attr in attrs:
- print("testing boolean attribute <{0} {1}>".format(tag, attr))
- doc = inline("<{0} {1}>".format(tag, attr))
- self.marionette.navigate(doc)
- el = self.marionette.find_element(By.TAG_NAME, tag)
- res = el.get_attribute(attr)
- self.assertIsInstance(res, types.StringTypes)
- self.assertEqual("true", res)
-
- def test_global_boolean_attributes(self):
- self.marionette.navigate(inline("<p hidden>foo"))
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("hidden")
- self.assertIsInstance(attr, types.StringTypes)
- self.assertEqual("true", attr)
-
- self.marionette.navigate(inline("<p>foo"))
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("hidden")
- self.assertIsNone(attr)
-
- self.marionette.navigate(inline("<p itemscope>foo"))
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("itemscope")
- self.assertIsInstance(attr, types.StringTypes)
- self.assertEqual("true", attr)
-
- self.marionette.navigate(inline("<p>foo"))
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("itemscope")
- self.assertIsNone(attr)
-
- # TODO(ato): Test for custom elements
-
- def test_xhtml(self):
- doc = inline("<p hidden=\"true\">foo</p>", doctype="xhtml")
- self.marionette.navigate(doc)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- attr = el.get_attribute("hidden")
- self.assertIsInstance(attr, types.StringTypes)
- self.assertEqual("true", attr)
-
-
-class TestGetElementProperty(MarionetteTestCase):
- def test_get(self):
- self.marionette.navigate(disabled)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- prop = el.get_property("disabled")
- self.assertIsInstance(prop, bool)
- self.assertTrue(prop)
-
- def test_missing_property_returns_default(self):
- self.marionette.navigate(input)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- prop = el.get_property("checked")
- self.assertIsInstance(prop, bool)
- self.assertFalse(prop)
-
- def test_attribute_not_returned(self):
- self.marionette.navigate(attribute)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- self.assertEqual(el.get_property("foo"), None)
-
- def test_manipulated_element(self):
- self.marionette.navigate(check)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- self.assertEqual(el.get_property("checked"), False)
-
- el.click()
- self.assertEqual(el.get_property("checked"), True)
-
- el.click()
- self.assertEqual(el.get_property("checked"), False)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py
deleted file mode 100644
index 01ed355c48..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_element_state_chrome.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase, skip
-
-
-class TestIsElementEnabledChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_enabled(self):
- l = self.marionette.find_element(By.ID, "textInput")
- self.assertTrue(l.is_enabled())
- self.marionette.execute_script("arguments[0].disabled = true;", [l])
- self.assertFalse(l.is_enabled())
- self.marionette.execute_script("arguments[0].disabled = false;", [l])
-
- def test_can_get_element_rect(self):
- l = self.marionette.find_element(By.ID, "textInput")
- rect = l.rect
- self.assertTrue(rect['x'] > 0)
- self.assertTrue(rect['y'] > 0)
-
-
-@skip("Switched off in bug 896043, and to be turned on in bug 896046")
-class TestIsElementDisplayed(MarionetteTestCase):
- def test_isDisplayed(self):
- l = self.marionette.find_element(By.ID, "textInput")
- self.assertTrue(l.is_displayed())
- self.marionette.execute_script("arguments[0].hidden = true;", [l])
- self.assertFalse(l.is_displayed())
- self.marionette.execute_script("arguments[0].hidden = false;", [l])
-
-
-class TestGetElementAttributeChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_get(self):
- el = self.marionette.execute_script("return window.document.getElementById('textInput');")
- self.assertEqual(el.get_attribute("id"), "textInput")
-
-class TestGetElementProperty(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_get(self):
- el = self.marionette.execute_script("return window.document.getElementById('textInput');")
- self.assertEqual(el.get_property("id"), "textInput")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize.py b/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize.py
deleted file mode 100644
index ebabd3344b..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestElementSize(MarionetteTestCase):
- def testShouldReturnTheSizeOfALink(self):
- test_html = self.marionette.absolute_url("testSize.html")
- self.marionette.navigate(test_html)
- shrinko = self.marionette.find_element(By.ID, 'linkId')
- size = shrinko.rect
- self.assertTrue(size['width'] > 0)
- self.assertTrue(size['height'] > 0)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize_chrome.py
deleted file mode 100644
index e2bb347155..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_elementsize_chrome.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestElementSizeChrome(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestElementSizeChrome, self).setUp()
-
- self.marionette.set_context("chrome")
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test2.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(new_window)
-
- def tearDown(self):
- self.close_all_windows()
- super(TestElementSizeChrome, self).tearDown()
-
- def testShouldReturnTheSizeOfAnInput(self):
- shrinko = self.marionette.find_element(By.ID, 'textInput')
- size = shrinko.rect
- self.assertTrue(size['width'] > 0)
- self.assertTrue(size['height'] > 0)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_errors.py b/testing/marionette/harness/marionette_harness/tests/unit/test_errors.py
deleted file mode 100644
index f6a9c285c2..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_errors.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# 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 sys
-
-from marionette_driver import errors
-
-from marionette_harness import marionette_test
-
-
-def fake_cause():
- try:
- raise ValueError("bar")
- except ValueError as e:
- return sys.exc_info()
-
-message = "foo"
-cause = fake_cause()
-stacktrace = "first\nsecond"
-
-class TestErrors(marionette_test.MarionetteTestCase):
- def test_defaults(self):
- exc = errors.MarionetteException()
- self.assertIsNone(exc.message)
- self.assertIsNone(exc.cause)
- self.assertIsNone(exc.stacktrace)
-
- def test_construction(self):
- exc = errors.MarionetteException(
- message=message, cause=cause, stacktrace=stacktrace)
- self.assertEquals(exc.message, message)
- self.assertEquals(exc.cause, cause)
- self.assertEquals(exc.stacktrace, stacktrace)
-
- def test_str(self):
- exc = errors.MarionetteException(
- message=message, cause=cause, stacktrace=stacktrace)
- r = str(exc)
- self.assertIn(message, r)
- self.assertIn(", caused by {0!r}".format(cause[0]), r)
- self.assertIn("\nstacktrace:\n\tfirst\n\tsecond", r)
-
- def test_cause_string(self):
- exc = errors.MarionetteException(cause="foo")
- self.assertEqual(exc.cause, "foo")
- r = str(exc)
- self.assertIn(", caused by foo", r)
-
- def test_cause_tuple(self):
- exc = errors.MarionetteException(cause=cause)
- self.assertEqual(exc.cause, cause)
- r = str(exc)
- self.assertIn(", caused by {0!r}".format(cause[0]), r)
-
-
-class TestLookup(marionette_test.MarionetteTestCase):
- def test_by_unknown_number(self):
- self.assertEqual(errors.MarionetteException, errors.lookup(123456))
-
- def test_by_known_string(self):
- self.assertEqual(errors.NoSuchElementException,
- errors.lookup("no such element"))
-
- def test_by_unknown_string(self):
- self.assertEqual(errors.MarionetteException, errors.lookup("barbera"))
-
- def test_by_known_unicode_string(self):
- self.assertEqual(errors.NoSuchElementException,
- errors.lookup(u"no such element"))
-
-
-class TestAllErrors(marionette_test.MarionetteTestCase):
- def test_properties(self):
- for exc in errors.es_:
- self.assertTrue(hasattr(exc, "status"),
- "expected exception to have attribute `status'")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_async_script.py b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_async_script.py
deleted file mode 100644
index 8a5472b3a8..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_async_script.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# 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 (
- JavascriptException,
- ScriptTimeoutException,
-)
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestExecuteAsyncContent(MarionetteTestCase):
- def setUp(self):
- super(TestExecuteAsyncContent, self).setUp()
- self.marionette.timeout.script = 1
-
- def test_execute_async_simple(self):
- self.assertEqual(1, self.marionette.execute_async_script("arguments[arguments.length-1](1);"))
-
- def test_execute_async_ours(self):
- self.assertEqual(1, self.marionette.execute_async_script("marionetteScriptFinished(1);"))
-
- def test_execute_async_timeout(self):
- self.assertRaises(ScriptTimeoutException, self.marionette.execute_async_script, "var x = 1;")
-
- def test_execute_async_unique_timeout(self):
- self.assertEqual(2, self.marionette.execute_async_script("setTimeout(function() {marionetteScriptFinished(2);}, 2000);", script_timeout=5000))
- self.assertRaises(ScriptTimeoutException, self.marionette.execute_async_script, "setTimeout(function() {marionetteScriptFinished(3);}, 2000);")
-
- def test_no_timeout(self):
- self.marionette.timeout.script = 10
- self.assertTrue(self.marionette.execute_async_script("""
- var callback = arguments[arguments.length - 1];
- setTimeout(function() { callback(true); }, 500);
- """))
-
- def test_execute_async_unload(self):
- self.marionette.timeout.script = 5
- unload = """
- window.location.href = "about:blank";
- """
- self.assertRaises(JavascriptException, self.marionette.execute_async_script, unload)
-
- def test_check_window(self):
- self.assertTrue(self.marionette.execute_async_script("marionetteScriptFinished(window !=null && window != undefined);"))
-
- def test_same_context(self):
- var1 = 'testing'
- self.assertEqual(self.marionette.execute_script("""
- this.testvar = '{}';
- return this.testvar;
- """.format(var1)), var1)
- self.assertEqual(self.marionette.execute_async_script(
- "marionetteScriptFinished(this.testvar);", new_sandbox=False), var1)
-
- def test_execute_no_return(self):
- self.assertEqual(self.marionette.execute_async_script("marionetteScriptFinished()"), None)
-
- def test_execute_js_exception(self):
- try:
- self.marionette.execute_async_script("""
- let a = 1;
- foo(bar);
- """)
- self.assertFalse(True)
- except JavascriptException, inst:
- self.assertTrue('foo(bar)' in inst.stacktrace)
-
- def test_execute_async_js_exception(self):
- self.assertRaises(JavascriptException,
- self.marionette.execute_async_script, """
- var callback = arguments[arguments.length - 1];
- callback(foo());
- """)
-
- def test_script_finished(self):
- self.assertTrue(self.marionette.execute_async_script("""
- marionetteScriptFinished(true);
- """))
-
- def test_execute_permission(self):
- self.assertRaises(JavascriptException, self.marionette.execute_async_script, """
-let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-marionetteScriptFinished(4);
-""")
-
- def test_sandbox_reuse(self):
- # Sandboxes between `execute_script()` invocations are shared.
- self.marionette.execute_async_script("this.foobar = [23, 42];"
- "marionetteScriptFinished();")
- self.assertEqual(self.marionette.execute_async_script(
- "marionetteScriptFinished(this.foobar);", new_sandbox=False), [23, 42])
-
- self.marionette.execute_async_script("global.barfoo = [42, 23];"
- "marionetteScriptFinished();")
- self.assertEqual(self.marionette.execute_async_script(
- "marionetteScriptFinished(global.barfoo);", new_sandbox=False), [42, 23])
-
- def test_sandbox_refresh_arguments(self):
- self.marionette.execute_async_script("this.foobar = [arguments[0], arguments[1]];"
- "marionetteScriptFinished();",
- script_args=[23, 42])
- self.assertEqual(self.marionette.execute_async_script(
- "marionetteScriptFinished(this.foobar);", new_sandbox=False),
- [23, 42])
-
- self.marionette.execute_async_script("global.barfoo = [arguments[0], arguments[1]];"
- "marionetteScriptFinished()",
- script_args=[42, 23], new_sandbox=False)
- self.assertEqual(self.marionette.execute_async_script(
- "marionetteScriptFinished(global.barfoo);", new_sandbox=False),
- [42, 23])
-
- # Functions defined in higher privilege scopes, such as the privileged
- # content frame script listener.js runs in, cannot be accessed from
- # content. This tests that it is possible to introspect the objects on
- # `arguments` without getting permission defined errors. This is made
- # possible because the last argument is always the callback/complete
- # function.
- #
- # See bug 1290966.
- def test_introspection_of_arguments(self):
- self.marionette.execute_async_script(
- "arguments[0].cheese; __webDriverCallback();",
- script_args=[], sandbox=None)
-
-
-class TestExecuteAsyncChrome(TestExecuteAsyncContent):
- def setUp(self):
- super(TestExecuteAsyncChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- def test_execute_async_unload(self):
- pass
-
- def test_execute_permission(self):
- self.assertEqual(5, self.marionette.execute_async_script("""
-var c = Components.classes;
-marionetteScriptFinished(5);
-"""))
-
- def test_execute_async_js_exception(self):
- # Javascript exceptions are not propagated in chrome code
- self.marionette.timeout.script = 0.2
- self.assertRaises(ScriptTimeoutException,
- self.marionette.execute_async_script, """
- var callback = arguments[arguments.length - 1];
- setTimeout("callback(foo())", 50);
- """)
- self.assertRaises(JavascriptException,
- self.marionette.execute_async_script, """
- var callback = arguments[arguments.length - 1];
- setTimeout("callback(foo())", 50);
- """, debug_script=True)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_isolate.py b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_isolate.py
deleted file mode 100644
index 7e09451e4d..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_isolate.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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 ScriptTimeoutException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestExecuteIsolationContent(MarionetteTestCase):
- def setUp(self):
- super(TestExecuteIsolationContent, self).setUp()
- self.content = True
-
- def test_execute_async_isolate(self):
- # Results from one execute call that has timed out should not
- # contaminate a future call.
- multiplier = "*3" if self.content else "*1"
- self.marionette.timeout.script = 0.5
- self.assertRaises(ScriptTimeoutException,
- self.marionette.execute_async_script,
- ("setTimeout(function() {{ marionetteScriptFinished(5{}); }}, 3000);"
- .format(multiplier)))
-
- self.marionette.timeout.script = 6
- result = self.marionette.execute_async_script("""
- setTimeout(function() {{ marionetteScriptFinished(10{}); }}, 5000);
- """.format(multiplier))
- self.assertEqual(result, 30 if self.content else 10)
-
-class TestExecuteIsolationChrome(TestExecuteIsolationContent):
- def setUp(self):
- super(TestExecuteIsolationChrome, self).setUp()
- self.marionette.set_context("chrome")
- self.content = False
-
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_sandboxes.py b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_sandboxes.py
deleted file mode 100644
index d7cb0444bc..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_sandboxes.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# 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 JavascriptException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestExecuteSandboxes(MarionetteTestCase):
- def setUp(self):
- super(TestExecuteSandboxes, self).setUp()
-
- def test_execute_system_sandbox(self):
- # Test that "system" sandbox has elevated privileges in execute_script
- result = self.marionette.execute_script(
- "return Components.interfaces.nsIPermissionManager.ALLOW_ACTION",
- sandbox="system")
- self.assertEqual(result, 1)
-
- def test_execute_async_system_sandbox(self):
- # Test that "system" sandbox has elevated privileges in
- # execute_async_script.
- result = self.marionette.execute_async_script("""
- const Ci = Components.interfaces;
- let result = Ci.nsIPermissionManager.ALLOW_ACTION;
- marionetteScriptFinished(result);""",
- sandbox="system")
- self.assertEqual(result, 1)
-
- def test_execute_switch_sandboxes(self):
- # Test that sandboxes are retained when switching between them
- # for execute_script.
- self.marionette.execute_script("foo = 1", sandbox="1")
- self.marionette.execute_script("foo = 2", sandbox="2")
- foo = self.marionette.execute_script(
- "return foo", sandbox="1", new_sandbox=False)
- self.assertEqual(foo, 1)
- foo = self.marionette.execute_script(
- "return foo", sandbox="2", new_sandbox=False)
- self.assertEqual(foo, 2)
-
- def test_execute_new_sandbox(self):
- # test that clearing a sandbox does not affect other sandboxes
- self.marionette.execute_script("foo = 1", sandbox="1")
- self.marionette.execute_script("foo = 2", sandbox="2")
-
- # deprecate sandbox 1 by asking explicitly for a fresh one
- with self.assertRaises(JavascriptException):
- self.marionette.execute_script("return foo",
- sandbox="1", new_sandbox=True)
-
- foo = self.marionette.execute_script(
- "return foo", sandbox="2", new_sandbox=False)
- self.assertEqual(foo, 2)
-
- def test_execute_async_switch_sandboxes(self):
- # Test that sandboxes are retained when switching between them
- # for execute_async_script.
- self.marionette.execute_async_script(
- "foo = 1; marionetteScriptFinished()", sandbox="1")
- self.marionette.execute_async_script(
- "foo = 2; marionetteScriptFinished()", sandbox='2')
- foo = self.marionette.execute_async_script(
- "marionetteScriptFinished(foo)",
- sandbox="1",
- new_sandbox=False)
- self.assertEqual(foo, 1)
- foo = self.marionette.execute_async_script(
- "marionetteScriptFinished(foo)",
- sandbox="2",
- new_sandbox=False)
- self.assertEqual(foo, 2)
-
-
-class TestExecuteSandboxesChrome(TestExecuteSandboxes):
- def setUp(self):
- super(TestExecuteSandboxesChrome, self).setUp()
- self.marionette.set_context("chrome")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
deleted file mode 100644
index 1ef4549d3c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
+++ /dev/null
@@ -1,402 +0,0 @@
-# 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
-import urllib
-
-from marionette_driver import By, errors
-from marionette_driver.marionette import HTMLElement
-from marionette_driver.wait import Wait
-
-from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
-
-
-elements = inline("<p>foo</p> <p>bar</p>")
-
-globals = set([
- "atob",
- "Audio",
- "btoa",
- "document",
- "navigator",
- "URL",
- "window",
- ])
-
-
-class TestExecuteSimpleTestContent(MarionetteTestCase):
- def test_stack_trace(self):
- try:
- self.marionette.execute_js_script("""
- let a = 1;
- throwHere();
- """, filename="file.js")
- self.assertFalse(True)
- except errors.JavascriptException as e:
- self.assertIn("throwHere is not defined", e.message)
- self.assertIn("@file.js:2", e.stacktrace)
-
-
-class TestExecuteContent(MarionetteTestCase):
-
- def assert_is_defined(self, property, sandbox="default"):
- self.assertTrue(self.marionette.execute_script(
- "return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox),
- "property {} is undefined".format(property))
-
- def test_return_number(self):
- self.assertEqual(1, self.marionette.execute_script("return 1"))
- self.assertEqual(1.5, self.marionette.execute_script("return 1.5"))
-
- def test_return_boolean(self):
- self.assertTrue(self.marionette.execute_script("return true"))
-
- def test_return_string(self):
- self.assertEqual("foo", self.marionette.execute_script("return 'foo'"))
-
- def test_return_array(self):
- self.assertEqual(
- [1, 2], self.marionette.execute_script("return [1, 2]"))
- self.assertEqual(
- [1.25, 1.75], self.marionette.execute_script("return [1.25, 1.75]"))
- self.assertEqual(
- [True, False], self.marionette.execute_script("return [true, false]"))
- self.assertEqual(
- ["foo", "bar"], self.marionette.execute_script("return ['foo', 'bar']"))
- self.assertEqual(
- [1, 1.5, True, "foo"], self.marionette.execute_script("return [1, 1.5, true, 'foo']"))
- self.assertEqual(
- [1, [2]], self.marionette.execute_script("return [1, [2]]"))
-
- def test_return_object(self):
- self.assertEqual(
- {"foo": 1}, self.marionette.execute_script("return {foo: 1}"))
- self.assertEqual(
- {"foo": 1.5}, self.marionette.execute_script("return {foo: 1.5}"))
- self.assertEqual(
- {"foo": True}, self.marionette.execute_script("return {foo: true}"))
- self.assertEqual(
- {"foo": "bar"}, self.marionette.execute_script("return {foo: 'bar'}"))
- self.assertEqual(
- {"foo": [1, 2]}, self.marionette.execute_script("return {foo: [1, 2]}"))
- self.assertEqual(
- {"foo": {"bar": [1, 2]}},
- self.marionette.execute_script("return {foo: {bar: [1, 2]}}"))
-
- def test_no_return_value(self):
- self.assertIsNone(self.marionette.execute_script("true"))
-
- def test_argument_null(self):
- self.assertIsNone(self.marionette.execute_script("return arguments[0]", [None]))
-
- def test_argument_number(self):
- self.assertEqual(
- 1, self.marionette.execute_script("return arguments[0]", [1]))
- self.assertEqual(
- 1.5, self.marionette.execute_script("return arguments[0]", [1.5]))
-
- def test_argument_boolean(self):
- self.assertTrue(self.marionette.execute_script("return arguments[0]", [True]))
-
- def test_argument_string(self):
- self.assertEqual(
- "foo", self.marionette.execute_script("return arguments[0]", ["foo"]))
-
- def test_argument_array(self):
- self.assertEqual(
- [1, 2], self.marionette.execute_script("return arguments[0]", [[1, 2]]))
-
- def test_argument_object(self):
- self.assertEqual({"foo": 1}, self.marionette.execute_script(
- "return arguments[0]", [{"foo": 1}]))
-
- def test_globals(self):
- for property in globals:
- self.assert_is_defined(property)
- self.assert_is_defined("Components")
- self.assert_is_defined("window.wrappedJSObject")
-
- def test_system_globals(self):
- for property in globals:
- self.assert_is_defined(property, sandbox="system")
- self.assert_is_defined("Components", sandbox="system")
- self.assert_is_defined("window.wrappedJSObject")
-
- def test_exception(self):
- self.assertRaises(errors.JavascriptException,
- self.marionette.execute_script, "return foo")
-
- def test_stacktrace(self):
- with self.assertRaises(errors.JavascriptException) as cm:
- self.marionette.execute_script("return b")
-
- # by default execute_script pass the name of the python file
- self.assertIn(os.path.basename(__file__.replace(".pyc", ".py")),
- cm.exception.stacktrace)
- self.assertIn("b is not defined", cm.exception.message)
- self.assertIn("return b", cm.exception.stacktrace)
-
- def test_permission(self):
- with self.assertRaises(errors.JavascriptException):
- self.marionette.execute_script("""
- var c = Components.classes["@mozilla.org/preferences-service;1"];
- """)
-
- def test_return_web_element(self):
- self.marionette.navigate(elements)
- expected = self.marionette.find_element(By.TAG_NAME, "p")
- actual = self.marionette.execute_script(
- "return document.querySelector('p')")
- self.assertEqual(expected, actual)
-
- def test_return_web_element_array(self):
- self.marionette.navigate(elements)
- expected = self.marionette.find_elements(By.TAG_NAME, "p")
- actual = self.marionette.execute_script("""
- let els = document.querySelectorAll('p')
- return [els[0], els[1]]""")
- self.assertEqual(expected, actual)
-
- # Bug 938228 identifies a problem with unmarshaling NodeList
- # objects from the DOM. document.querySelectorAll returns this
- # construct.
- def test_return_web_element_nodelist(self):
- self.marionette.navigate(elements)
- expected = self.marionette.find_elements(By.TAG_NAME, "p")
- actual = self.marionette.execute_script(
- "return document.querySelectorAll('p')")
- self.assertEqual(expected, actual)
-
- def test_sandbox_reuse(self):
- # Sandboxes between `execute_script()` invocations are shared.
- self.marionette.execute_script("this.foobar = [23, 42];")
- self.assertEqual(self.marionette.execute_script(
- "return this.foobar;", new_sandbox=False), [23, 42])
-
- self.marionette.execute_script("global.barfoo = [42, 23];")
- self.assertEqual(self.marionette.execute_script(
- "return global.barfoo;", new_sandbox=False), [42, 23])
-
- def test_sandbox_refresh_arguments(self):
- self.marionette.execute_script(
- "this.foobar = [arguments[0], arguments[1]]", [23, 42])
- self.assertEqual(self.marionette.execute_script(
- "return this.foobar", new_sandbox=False), [23, 42])
-
- def test_wrappedjsobject(self):
- try:
- self.marionette.execute_script("window.wrappedJSObject.foo = 3")
- self.assertEqual(
- self.marionette.execute_script("return window.wrappedJSObject.foo"), 3)
- finally:
- self.marionette.execute_script("delete window.wrappedJSObject.foo")
-
- def test_system_sandbox_wrappedjsobject(self):
- self.marionette.execute_script(
- "window.wrappedJSObject.foo = 4", sandbox="system")
- self.assertEqual(self.marionette.execute_script(
- "return window.wrappedJSObject.foo", sandbox="system"), 4)
-
- def test_system_dead_object(self):
- self.marionette.execute_script(
- "window.wrappedJSObject.foo = function() { return 'yo' }",
- sandbox="system")
- self.marionette.execute_script(
- "dump(window.wrappedJSObject.foo)", sandbox="system")
-
- self.marionette.execute_script(
- "window.wrappedJSObject.foo = function() { return 'yolo' }",
- sandbox="system")
- typ = self.marionette.execute_script(
- "return typeof window.wrappedJSObject.foo", sandbox="system")
- self.assertEqual("function", typ)
- obj = self.marionette.execute_script(
- "return window.wrappedJSObject.foo.toString()", sandbox="system")
- self.assertIn("yolo", obj)
-
- def test_lasting_side_effects(self):
- def send(script):
- return self.marionette._send_message(
- "executeScript", {"script": script}, key="value")
-
- send("window.foo = 1")
- foo = send("return window.foo")
- self.assertEqual(1, foo)
-
- for property in globals:
- exists = send("return typeof {} != 'undefined'".format(property))
- self.assertTrue(exists, "property {} is undefined".format(property))
-
- self.assertTrue(send("return typeof Components.utils == 'undefined'"))
- self.assertTrue(send("return typeof window.wrappedJSObject == 'undefined'"))
-
- def test_no_callback(self):
- self.assertTrue(self.marionette.execute_script(
- "return typeof arguments[0] == 'undefined'"))
-
- def test_window_set_timeout_is_not_cancelled(self):
- def content_timeout_triggered(mn):
- return mn.execute_script("return window.n", sandbox=None) > 0
-
- # subsequent call to execute_script after this
- # should not cancel the setTimeout event
- self.marionette.navigate(inline("""
- <script>
- window.n = 0;
- setTimeout(() => ++window.n, 4000);
- </script>"""))
-
- # as debug builds are inherently slow,
- # we need to assert the event did not already fire
- self.assertEqual(0, self.marionette.execute_script(
- "return window.n", sandbox=None),
- "setTimeout already fired")
-
- # if event was cancelled, this will time out
- Wait(self.marionette, timeout=8).until(
- content_timeout_triggered,
- message="Scheduled setTimeout event was cancelled by call to execute_script")
-
- def test_privileged_code_inspection(self):
- # test permission denied on toString of unload event handler
- self.marionette.navigate(inline("""
- <script>
- window.addEventListener = (type, handler) => handler.toString();
- </script>"""))
- self.marionette.execute_script("", sandbox=None)
-
- # test inspection of arguments
- self.marionette.execute_script("__webDriverArguments.toString()")
-
-
-class TestExecuteChrome(WindowManagerMixin, TestExecuteContent):
-
- def setUp(self):
- super(TestExecuteChrome, self).setUp()
-
- self.marionette.set_context("chrome")
-
- def tearDown(self):
- super(TestExecuteChrome, self).tearDown()
-
- def test_permission(self):
- self.assertEqual(1, self.marionette.execute_script("""
- var c = Components.classes["@mozilla.org/preferences-service;1"]; return 1;"""))
-
- @skip_if_mobile("New windows not supported in Fennec")
- def test_unmarshal_element_collection(self):
-
- def open_window_with_js():
- self.marionette.execute_script(
- "window.open('chrome://marionette/content/test.xul', 'xul', 'chrome');")
-
- try:
- win = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(win)
-
- expected = self.marionette.find_elements(By.TAG_NAME, "textbox")
- actual = self.marionette.execute_script(
- "return document.querySelectorAll('textbox')")
- self.assertEqual(expected, actual)
-
- finally:
- self.close_all_windows()
-
- def test_async_script_timeout(self):
- with self.assertRaises(errors.ScriptTimeoutException):
- self.marionette.execute_async_script("""
- var cb = arguments[arguments.length - 1];
- setTimeout(function() { cb() }, 250);
- """, script_timeout=100)
-
- @skip_if_mobile("New windows not supported in Fennec")
- def test_invalid_chrome_handle(self):
- try:
- win = self.open_window()
- self.marionette.switch_to_window(win)
-
- # Close new window and don't switch back to the original one
- self.marionette.close_chrome_window()
- self.assertNotEqual(self.start_window, win)
-
- # Call execute_script on an invalid chrome handle
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script("""
- return true;
- """)
-
- finally:
- self.close_all_windows()
-
- def test_lasting_side_effects(self):
- pass
-
- def test_return_web_element(self):
- pass
-
- def test_return_web_element_array(self):
- pass
-
- def test_return_web_element_nodelist(self):
- pass
-
- def test_window_set_timeout_is_not_cancelled(self):
- pass
-
- def test_privileged_code_inspection(self):
- pass
-
-
-class TestElementCollections(MarionetteTestCase):
-
- def assertSequenceIsInstance(self, seq, typ):
- for item in seq:
- self.assertIsInstance(item, typ)
-
- def test_array(self):
- self.marionette.navigate(inline("<p>foo <p>bar"))
- els = self.marionette.execute_script("return Array.from(document.querySelectorAll('p'))")
- self.assertIsInstance(els, list)
- self.assertEqual(2, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
-
- def test_html_all_collection(self):
- self.marionette.navigate(inline("<p>foo <p>bar"))
- els = self.marionette.execute_script("return document.all")
- self.assertIsInstance(els, list)
- # <html>, <head>, <body>, <p>, <p>
- self.assertEqual(5, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
-
- def test_html_collection(self):
- self.marionette.navigate(inline("<p>foo <p>bar"))
- els = self.marionette.execute_script("return document.getElementsByTagName('p')")
- self.assertIsInstance(els, list)
- self.assertEqual(2, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
-
- def test_html_form_controls_collection(self):
- self.marionette.navigate(inline("<form><input><input></form>"))
- els = self.marionette.execute_script("return document.forms[0].elements")
- self.assertIsInstance(els, list)
- self.assertEqual(2, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
-
- def test_html_options_collection(self):
- self.marionette.navigate(inline("<select><option><option></select>"))
- els = self.marionette.execute_script("return document.querySelector('select').options")
- self.assertIsInstance(els, list)
- self.assertEqual(2, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
-
- def test_node_list(self):
- self.marionette.navigate(inline("<p>foo <p>bar"))
- els = self.marionette.execute_script("return document.querySelectorAll('p')")
- self.assertIsInstance(els, list)
- self.assertEqual(2, len(els))
- self.assertSequenceIsInstance(els, HTMLElement)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_expected.py b/testing/marionette/harness/marionette_harness/tests/unit/test_expected.py
deleted file mode 100644
index ff8717c692..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_expected.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# 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 urllib
-
-from marionette_driver import expected
-from marionette_driver.by import By
-
-from marionette_harness import marionette_test
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
-
-static_element = inline("""<p>foo</p>""")
-static_elements = static_element + static_element
-
-remove_element_by_tag_name = \
- """var el = document.getElementsByTagName('{}')[0];
- document.getElementsByTagName("body")[0].remove(el);"""
-
-hidden_element = inline("<p style='display: none'>hidden</p>")
-
-selected_element = inline("<option selected>selected</option>")
-unselected_element = inline("<option>unselected</option>")
-
-enabled_element = inline("<input>")
-disabled_element = inline("<input disabled>")
-
-def no_such_element(marionette):
- return marionette.find_element(By.ID, "nosuchelement")
-
-def no_such_elements(marionette):
- return marionette.find_elements(By.ID, "nosuchelement")
-
-def p(marionette):
- return marionette.find_element(By.TAG_NAME, "p")
-
-def ps(marionette):
- return marionette.find_elements(By.TAG_NAME, "p")
-
-class TestExpected(marionette_test.MarionetteTestCase):
- def test_element_present_func(self):
- self.marionette.navigate(static_element)
- el = expected.element_present(p)(self.marionette)
- self.assertIsNotNone(el)
-
- def test_element_present_locator(self):
- self.marionette.navigate(static_element)
- el = expected.element_present(By.TAG_NAME, "p")(self.marionette)
- self.assertIsNotNone(el)
-
- def test_element_present_not_present(self):
- r = expected.element_present(no_such_element)(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertFalse(r)
-
- def test_element_not_present_func(self):
- r = expected.element_not_present(no_such_element)(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertTrue(r)
-
- def test_element_not_present_locator(self):
- r = expected.element_not_present(By.ID, "nosuchelement")(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertTrue(r)
-
- def test_element_not_present_is_present(self):
- self.marionette.navigate(static_element)
- r = expected.element_not_present(p)(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertFalse(r)
-
- def test_element_stale(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.assertIsNotNone(el)
- self.marionette.execute_script(remove_element_by_tag_name.format("p"))
- r = expected.element_stale(el)(self.marionette)
- self.assertTrue(r)
-
- def test_element_stale_is_not_stale(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- r = expected.element_stale(el)(self.marionette)
- self.assertFalse(r)
-
- def test_elements_present_func(self):
- self.marionette.navigate(static_elements)
- els = expected.elements_present(ps)(self.marionette)
- self.assertEqual(len(els), 2)
-
- def test_elements_present_locator(self):
- self.marionette.navigate(static_elements)
- els = expected.elements_present(By.TAG_NAME, "p")(self.marionette)
- self.assertEqual(len(els), 2)
-
- def test_elements_present_not_present(self):
- r = expected.elements_present(no_such_elements)(self.marionette)
- self.assertEqual(r, [])
-
- def test_elements_not_present_func(self):
- r = expected.element_not_present(no_such_elements)(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertTrue(r)
-
- def test_elements_not_present_locator(self):
- r = expected.element_not_present(By.ID, "nosuchelement")(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertTrue(r)
-
- def test_elements_not_present_is_present(self):
- self.marionette.navigate(static_elements)
- r = expected.elements_not_present(ps)(self.marionette)
- self.assertIsInstance(r, bool)
- self.assertFalse(r)
-
- def test_element_displayed(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- visible = expected.element_displayed(el)(self.marionette)
- self.assertTrue(visible)
-
- def test_element_displayed_locator(self):
- self.marionette.navigate(static_element)
- visible = expected.element_displayed(By.TAG_NAME, "p")(self.marionette)
- self.assertTrue(visible)
-
- def test_element_displayed_when_hidden(self):
- self.marionette.navigate(hidden_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- visible = expected.element_displayed(el)(self.marionette)
- self.assertFalse(visible)
-
- def test_element_displayed_when_hidden_locator(self):
- self.marionette.navigate(hidden_element)
- visible = expected.element_displayed(By.TAG_NAME, "p")(self.marionette)
- self.assertFalse(visible)
-
- def test_element_displayed_when_not_present(self):
- self.marionette.navigate("about:blank")
- visible = expected.element_displayed(By.TAG_NAME, "p")(self.marionette)
- self.assertFalse(visible)
-
- def test_element_displayed_when_stale_element(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.marionette.navigate("about:blank")
- missing = expected.element_displayed(el)(self.marionette)
- self.assertFalse(missing)
-
- def test_element_not_displayed(self):
- self.marionette.navigate(hidden_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- hidden = expected.element_not_displayed(el)(self.marionette)
- self.assertTrue(hidden)
-
- def test_element_not_displayed_locator(self):
- self.marionette.navigate(hidden_element)
- hidden = expected.element_not_displayed(By.TAG_NAME, "p")(self.marionette)
- self.assertTrue(hidden)
-
- def test_element_not_displayed_when_visible(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- hidden = expected.element_not_displayed(el)(self.marionette)
- self.assertFalse(hidden)
-
- def test_element_not_displayed_when_visible_locator(self):
- self.marionette.navigate(static_element)
- hidden = expected.element_not_displayed(By.TAG_NAME, "p")(self.marionette)
- self.assertFalse(hidden)
-
- def test_element_not_displayed_when_stale_element(self):
- self.marionette.navigate(static_element)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.marionette.navigate("about:blank")
- missing = expected.element_not_displayed(el)(self.marionette)
- self.assertTrue(missing)
-
- def test_element_selected(self):
- self.marionette.navigate(selected_element)
- el = self.marionette.find_element(By.TAG_NAME, "option")
- selected = expected.element_selected(el)(self.marionette)
- self.assertTrue(selected)
-
- def test_element_selected_when_not_selected(self):
- self.marionette.navigate(unselected_element)
- el = self.marionette.find_element(By.TAG_NAME, "option")
- unselected = expected.element_selected(el)(self.marionette)
- self.assertFalse(unselected)
-
- def test_element_not_selected(self):
- self.marionette.navigate(unselected_element)
- el = self.marionette.find_element(By.TAG_NAME, "option")
- unselected = expected.element_not_selected(el)(self.marionette)
- self.assertTrue(unselected)
-
- def test_element_not_selected_when_selected(self):
- self.marionette.navigate(selected_element)
- el = self.marionette.find_element(By.TAG_NAME, "option")
- selected = expected.element_not_selected(el)(self.marionette)
- self.assertFalse(selected)
-
- def test_element_enabled(self):
- self.marionette.navigate(enabled_element)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- enabled = expected.element_enabled(el)(self.marionette)
- self.assertTrue(enabled)
-
- def test_element_enabled_when_disabled(self):
- self.marionette.navigate(disabled_element)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- disabled = expected.element_enabled(el)(self.marionette)
- self.assertFalse(disabled)
-
- def test_element_not_enabled(self):
- self.marionette.navigate(disabled_element)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- disabled = expected.element_not_enabled(el)(self.marionette)
- self.assertTrue(disabled)
-
- def test_element_not_enabled_when_enabled(self):
- self.marionette.navigate(enabled_element)
- el = self.marionette.find_element(By.TAG_NAME, "input")
- enabled = expected.element_not_enabled(el)(self.marionette)
- self.assertFalse(enabled)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_expectedfail.py b/testing/marionette/harness/marionette_harness/tests/unit/test_expectedfail.py
deleted file mode 100644
index 138a36c58f..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_expectedfail.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestFail(MarionetteTestCase):
- def test_fails(self):
- # this test is supposed to fail!
- self.assertEquals(True, False)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_file_upload.py b/testing/marionette/harness/marionette_harness/tests/unit/test_file_upload.py
deleted file mode 100644
index f67be9556f..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_file_upload.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# 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 contextlib
-import urllib
-
-from tempfile import NamedTemporaryFile as tempfile
-
-from marionette_driver import By, errors, expected
-from marionette_driver.wait import Wait
-from marionette_harness import MarionetteTestCase, skip
-
-
-single = "data:text/html,{}".format(urllib.quote("<input type=file>"))
-multiple = "data:text/html,{}".format(urllib.quote("<input type=file multiple>"))
-upload = lambda url: "data:text/html,{}".format(urllib.quote("""
- <form action='{}' method=post enctype='multipart/form-data'>
- <input type=file>
- <input type=submit>
- </form>""".format(url)))
-
-
-class TestFileUpload(MarionetteTestCase):
- def test_sets_one_file(self):
- self.marionette.navigate(single)
- input = self.input
-
- exp = None
- with tempfile() as f:
- input.send_keys(f.name)
- exp = [f.name]
-
- files = self.get_file_names(input)
- self.assertEqual(len(files), 1)
- self.assertFileNamesEqual(files, exp)
-
- def test_sets_multiple_files(self):
- self.marionette.navigate(multiple)
- input = self.input
-
- exp = None
- with contextlib.nested(tempfile(), tempfile()) as (a, b):
- input.send_keys(a.name)
- input.send_keys(b.name)
- exp = [a.name, b.name]
-
- files = self.get_file_names(input)
- self.assertEqual(len(files), 2)
- self.assertFileNamesEqual(files, exp)
-
- def test_sets_multiple_indentical_files(self):
- self.marionette.navigate(multiple)
- input = self.input
-
- exp = []
- with tempfile() as f:
- input.send_keys(f.name)
- input.send_keys(f.name)
- exp = f.name
-
- files = self.get_file_names(input)
- self.assertEqual(len(files), 2)
- self.assertFileNamesEqual(files, exp)
-
- def test_clear_file(self):
- self.marionette.navigate(single)
- input = self.input
-
- with tempfile() as f:
- input.send_keys(f.name)
-
- self.assertEqual(len(self.get_files(input)), 1)
- input.clear()
- self.assertEqual(len(self.get_files(input)), 0)
-
- def test_clear_files(self):
- self.marionette.navigate(multiple)
- input = self.input
-
- with contextlib.nested(tempfile(), tempfile()) as (a, b):
- input.send_keys(a.name)
- input.send_keys(b.name)
-
- self.assertEqual(len(self.get_files(input)), 2)
- input.clear()
- self.assertEqual(len(self.get_files(input)), 0)
-
- def test_illegal_file(self):
- self.marionette.navigate(single)
- with self.assertRaisesRegexp(errors.MarionetteException, "File not found"):
- self.input.send_keys("rochefort")
-
- def test_upload(self):
- self.marionette.navigate(
- upload(self.marionette.absolute_url("file_upload")))
- url = self.marionette.get_url()
-
- with tempfile() as f:
- f.write("camembert")
- f.flush()
- self.input.send_keys(f.name)
- self.submit.click()
-
- Wait(self.marionette).until(lambda m: m.get_url() != url)
- self.assertIn("multipart/form-data", self.body.text)
-
- def test_change_event(self):
- self.marionette.navigate(single)
- self.marionette.execute_script("""
- window.changeEvs = [];
- let el = arguments[arguments.length - 1];
- el.addEventListener("change", ev => window.changeEvs.push(ev));
- console.log(window.changeEvs.length);
- """, script_args=(self.input,), sandbox=None)
-
- with tempfile() as f:
- self.input.send_keys(f.name)
-
- nevs = self.marionette.execute_script(
- "return window.changeEvs.length", sandbox=None)
- self.assertEqual(1, nevs)
-
- def find_inputs(self):
- return self.marionette.find_elements(By.TAG_NAME, "input")
-
- @property
- def input(self):
- return self.find_inputs()[0]
-
- @property
- def submit(self):
- return self.find_inputs()[1]
-
- @property
- def body(self):
- return Wait(self.marionette).until(
- expected.element_present(By.TAG_NAME, "body"))
-
- def get_file_names(self, el):
- fl = self.get_files(el)
- return [f["name"] for f in fl]
-
- def get_files(self, el):
- return self.marionette.execute_script(
- "return arguments[0].files", script_args=[el])
-
- def assertFileNamesEqual(self, act, exp):
- # File array returned from browser doesn't contain full path names,
- # this cuts off the path of the expected files.
- filenames = [f.rsplit("/", 0)[-1] for f in act]
- self.assertListEqual(filenames, act)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py
deleted file mode 100644
index e6b2d63bf3..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_findelement_chrome.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import NoSuchElementException
-from marionette_driver.marionette import HTMLElement
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestElementsChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_id(self):
- el = self.marionette.execute_script("return window.document.getElementById('textInput');")
- found_el = self.marionette.find_element(By.ID, "textInput")
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_that_we_can_find_elements_from_css_selectors(self):
- el = self.marionette.execute_script("return window.document.getElementById('textInput');")
- found_el = self.marionette.find_element(By.CSS_SELECTOR, "#textInput")
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_child_element(self):
- el = self.marionette.find_element(By.ID, "textInput")
- parent = self.marionette.find_element(By.ID, "things")
- found_el = parent.find_element(By.TAG_NAME, "textbox")
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_child_elements(self):
- el = self.marionette.find_element(By.ID, "textInput3")
- parent = self.marionette.find_element(By.ID, "things")
- found_els = parent.find_elements(By.TAG_NAME, "textbox")
- self.assertTrue(el.id in [found_el.id for found_el in found_els])
-
- def test_tag_name(self):
- el = self.marionette.execute_script("return window.document.getElementsByTagName('vbox')[0];")
- found_el = self.marionette.find_element(By.TAG_NAME, "vbox")
- self.assertEquals('vbox', found_el.tag_name)
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_class_name(self):
- el = self.marionette.execute_script("return window.document.getElementsByClassName('asdf')[0];")
- found_el = self.marionette.find_element(By.CLASS_NAME, "asdf")
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_xpath(self):
- el = self.marionette.execute_script("return window.document.getElementById('testBox');")
- found_el = self.marionette.find_element(By.XPATH, "id('testBox')")
- self.assertEqual(HTMLElement, type(found_el))
- self.assertEqual(el, found_el)
-
- def test_not_found(self):
- self.marionette.timeout.implicit = 1
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
- self.marionette.timeout.implicit = 0
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
-
- def test_timeout(self):
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "myid")
- self.marionette.timeout.implicit = 4
- self.marionette.execute_script("window.setTimeout(function() {var b = window.document.createElement('button'); b.id = 'myid'; document.getElementById('things').appendChild(b);}, 1000)")
- self.assertEqual(HTMLElement, type(self.marionette.find_element(By.ID, "myid")))
- self.marionette.execute_script("window.document.getElementById('things').removeChild(window.document.getElementById('myid'));")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_geckoinstance.py b/testing/marionette/harness/marionette_harness/tests/unit/test_geckoinstance.py
deleted file mode 100644
index 5405502968..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_geckoinstance.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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.geckoinstance import apps, GeckoInstance
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestGeckoInstance(MarionetteTestCase):
-
- def test_create(self):
- """Test that the correct gecko instance is determined."""
- for app in apps:
- # If app has been specified we directly return the appropriate instance class
- self.assertEqual(type(GeckoInstance.create(app=app, bin="n/a")),
- apps[app])
-
- # Unknown applications and binaries should fail
- self.assertRaises(NotImplementedError, GeckoInstance.create,
- app="n/a", bin=self.marionette.bin)
- self.assertRaises(NotImplementedError, GeckoInstance.create,
- bin="n/a")
- self.assertRaises(NotImplementedError, GeckoInstance.create,
- bin=None)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_getactiveframe_oop.py b/testing/marionette/harness/marionette_harness/tests/unit/test_getactiveframe_oop.py
deleted file mode 100644
index 9325d4892d..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_getactiveframe_oop.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-OOP_BY_DEFAULT = "dom.ipc.browser_frames.oop_by_default"
-BROWSER_FRAMES_ENABLED = "dom.mozBrowserFramesEnabeld"
-
-
-class TestGetActiveFrameOOP(MarionetteTestCase):
- def setUp(self):
- super(TestGetActiveFrameOOP, self).setUp()
- with self.marionette.using_context("chrome"):
- self.oop_by_default = self.marionette.get_pref(OOP_BY_DEFAULT)
- self.mozBrowserFramesEnabled = self.marionette.get_pref(BROWSER_FRAMES_ENABLED)
- self.marionette.set_pref(OOP_BY_DEFAULT, True)
- self.marionette.set_pref(BROWSER_FRAMES_ENABLED, True)
-
- def tearDown(self):
- with self.marionette.using_context("chrome"):
- if self.oop_by_default is None:
- self.marionette.clear_pref(OOP_BY_DEFAULT)
- else:
- self.marionette.set_pref(OOP_BY_DEFAULT, self.oop_by_default)
-
- if self.mozBrowserFramesEnabled is None:
- self.marionette.clear_pref(BROWSER_FRAMES_ENABLED)
- else:
- self.marionette.set_pref(BROWSER_FRAMES_ENABLED, self.mozBrowserFramesEnabled)
-
- def test_active_frame_oop(self):
- self.marionette.navigate(self.marionette.absolute_url("test.html"))
- self.marionette.push_permission('browser', True)
-
- # Create first OOP frame
- self.marionette.execute_script("""
- let iframe1 = document.createElement("iframe");
- iframe1.id = "remote_iframe1";
- iframe1.setAttribute('remote', true);
- iframe1.setAttribute('mozbrowser', true);
- iframe1.style.height = "100px";
- iframe1.style.width = "100%%";
- iframe1.src = "{}";
- document.body.appendChild(iframe1);
- """.format(self.marionette.absolute_url("test_oop_1.html")))
-
- # Currently no active frame
- self.assertEqual(self.marionette.get_active_frame(), None)
- self.assertTrue("test.html" in self.marionette.get_url())
-
- # Switch to iframe1, get active frame
- frame = self.marionette.find_element(By.ID, 'remote_iframe1')
- self.marionette.switch_to_frame(frame)
- active_frame1 = self.marionette.get_active_frame()
- self.assertNotEqual(active_frame1.id, None)
-
- # Switch to top-level then back to active frame, verify correct frame
- self.marionette.switch_to_frame()
- self.marionette.switch_to_frame(active_frame1)
- self.assertTrue("test_oop_1.html" in self.marionette.execute_script("return document.wrappedJSObject.location.href"))
-
- # Create another OOP frame
- self.marionette.switch_to_frame()
- self.marionette.execute_script("""
- let iframe2 = document.createElement("iframe");
- iframe2.setAttribute('mozbrowser', true);
- iframe2.setAttribute('remote', true);
- iframe2.id = "remote_iframe2";
- iframe2.style.height = "100px";
- iframe2.style.width = "100%%";
- iframe2.src = "{}";
- document.body.appendChild(iframe2);
- """.format(self.marionette.absolute_url("test_oop_2.html")))
-
- # Switch to iframe2, get active frame
- frame2 = self.marionette.find_element(By.ID, 'remote_iframe2')
- self.marionette.switch_to_frame(frame2)
- active_frame2 = self.marionette.get_active_frame()
- self.assertNotEqual(active_frame2.id, None)
-
- # Switch to top-level then back to active frame 1, verify correct frame
- self.marionette.switch_to_frame()
- self.marionette.switch_to_frame(active_frame1)
- self.assertTrue("test_oop_1.html" in self.marionette.execute_script("return document.wrappedJSObject.location.href"))
-
- # Switch to top-level then back to active frame 2, verify correct frame
- self.marionette.switch_to_frame()
- self.marionette.switch_to_frame(active_frame2)
- self.assertTrue("test_oop_2.html" in self.marionette.execute_script("return document.wrappedJSObject.location.href"))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_implicit_waits.py b/testing/marionette/harness/marionette_harness/tests/unit/test_implicit_waits.py
deleted file mode 100644
index 954443ac30..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_implicit_waits.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import NoSuchElementException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestImplicitWaits(MarionetteTestCase):
- def test_implicitly_wait_for_single_element(self):
- test_html = self.marionette.absolute_url("test_dynamic.html")
- self.marionette.navigate(test_html)
- add = self.marionette.find_element(By.ID, "adder")
- self.marionette.timeout.implicit = 30
- add.click()
- # all is well if this does not throw
- self.marionette.find_element(By.ID, "box0")
-
- def test_implicit_wait_reaches_timeout(self):
- test_html = self.marionette.absolute_url("test_dynamic.html")
- self.marionette.navigate(test_html)
- self.marionette.timeout.implicit = 3
- with self.assertRaises(NoSuchElementException):
- self.marionette.find_element(By.ID, "box0")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_import_script.py b/testing/marionette/harness/marionette_harness/tests/unit/test_import_script.py
deleted file mode 100644
index e86de2bd57..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_import_script.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# 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_driver.by import By
-from marionette_driver.errors import JavascriptException
-
-from marionette_harness import (
- MarionetteTestCase,
- skip_if_chrome,
- skip_if_mobile,
- WindowManagerMixin,
-)
-
-
-class TestImportScriptContent(WindowManagerMixin, MarionetteTestCase):
- contexts = set(["chrome", "content"])
-
- script_file = os.path.abspath(
- os.path.join(__file__, os.path.pardir, "importscript.js"))
- another_script_file = os.path.abspath(
- os.path.join(__file__, os.path.pardir, "importanotherscript.js"))
-
- def setUp(self):
- super(TestImportScriptContent, self).setUp()
-
- for context in self.contexts:
- with self.marionette.using_context(context):
- self.marionette.clear_imported_scripts()
- self.reset_context()
-
- def tearDown(self):
- self.close_all_windows()
-
- super(TestImportScriptContent, self).tearDown()
-
- def reset_context(self):
- self.marionette.set_context("content")
-
- @property
- def current_context(self):
- return self.marionette._send_message("getContext", key="value")
-
- @property
- def other_context(self):
- return self.contexts.copy().difference([self.current_context]).pop()
-
- def is_defined(self, symbol):
- return self.marionette.execute_script(
- "return typeof {} != 'undefined'".format(symbol))
-
- def assert_defined(self, symbol, msg=None):
- if msg is None:
- msg = "Expected symbol {} to be defined".format(symbol)
- self.assertTrue(self.is_defined(symbol), msg)
-
- def assert_undefined(self, symbol, msg=None):
- if msg is None:
- msg = "Expected symbol {} to be undefined".format(symbol)
- self.assertFalse(self.is_defined(symbol), msg)
-
- def assert_scripts_cleared(self):
- self.marionette.import_script(self.script_file)
- self.assert_defined("testFunc")
- self.marionette.clear_imported_scripts()
- self.assert_undefined("testFunc")
-
- def test_import_script(self):
- self.marionette.import_script(self.script_file)
- self.assertEqual(
- "i'm a test function!", self.marionette.execute_script("return testFunc();"))
- self.assertEqual("i'm a test function!", self.marionette.execute_async_script(
- "marionetteScriptFinished(testFunc());"))
-
- def test_import_script_twice(self):
- self.marionette.import_script(self.script_file)
- self.assert_defined("testFunc")
-
- # TODO(ato): Note that the WebDriver command primitives
- # does not allow us to check what scripts have been imported.
- # I suspect we must to do this through an xpcshell test.
-
- self.marionette.import_script(self.script_file)
- self.assert_defined("testFunc")
-
- def test_import_script_and_clear(self):
- self.marionette.import_script(self.script_file)
- self.assert_defined("testFunc")
- self.marionette.clear_imported_scripts()
- self.assert_scripts_cleared()
- self.assert_undefined("testFunc")
- with self.assertRaises(JavascriptException):
- self.marionette.execute_script("return testFunc()")
- with self.assertRaises(JavascriptException):
- self.marionette.execute_async_script(
- "marionetteScriptFinished(testFunc())")
-
- def test_clear_scripts_in_other_context(self):
- self.marionette.import_script(self.script_file)
- self.assert_defined("testFunc")
-
- # clearing other context's script file should not affect ours
- with self.marionette.using_context(self.other_context):
- self.marionette.clear_imported_scripts()
- self.assert_undefined("testFunc")
-
- self.assert_defined("testFunc")
-
- def test_multiple_imports(self):
- self.marionette.import_script(self.script_file)
- self.marionette.import_script(self.another_script_file)
- self.assert_defined("testFunc")
- self.assert_defined("testAnotherFunc")
-
- @skip_if_chrome("Needs content scope")
- @skip_if_mobile("New windows not supported in Fennec")
- def test_imports_apply_globally(self):
- self.marionette.navigate(
- self.marionette.absolute_url("test_windows.html"))
-
- def open_window_with_link():
- self.marionette.find_element(By.LINK_TEXT, "Open new window").click()
-
- new_window = self.open_window(trigger=open_window_with_link)
- self.marionette.switch_to_window(new_window)
-
- self.marionette.import_script(self.script_file)
- self.marionette.close_chrome_window()
-
- self.marionette.switch_to_window(self.start_window)
- self.assert_defined("testFunc")
-
-
-class TestImportScriptChrome(TestImportScriptContent):
- def reset_context(self):
- self.marionette.set_context("chrome")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_key_actions.py b/testing/marionette/harness/marionette_harness/tests/unit/test_key_actions.py
deleted file mode 100644
index 60e38b3c60..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_key_actions.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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.by import By
-from marionette_driver.keys import Keys
-from marionette_driver.marionette import Actions
-
-from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
-
-
-class TestKeyActions(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestKeyActions, self).setUp()
- if self.marionette.session_capabilities["platformName"] == "darwin":
- self.mod_key = Keys.META
- else:
- self.mod_key = Keys.CONTROL
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- self.reporter_element = self.marionette.find_element(By.ID, "keyReporter")
- self.reporter_element.click()
- self.key_action = Actions(self.marionette)
-
- @property
- def key_reporter_value(self):
- return self.reporter_element.get_property("value")
-
- def test_key_action_basic_input(self):
- self.key_action.key_down("a").key_down("b").key_down("c").perform()
- self.assertEqual(self.key_reporter_value, "abc")
-
- def test_upcase_input(self):
- (self.key_action.key_down(Keys.SHIFT)
- .key_down("a")
- .key_up(Keys.SHIFT)
- .key_down("b")
- .key_down("c")
- .perform())
- self.assertEqual(self.key_reporter_value, "Abc")
-
- def test_replace_input(self):
- self.key_action.key_down("a").key_down("b").key_down("c").perform()
- self.assertEqual(self.key_reporter_value, "abc")
- (self.key_action.key_down(self.mod_key)
- .key_down("a")
- .key_up(self.mod_key)
- .key_down("x")
- .perform())
- self.assertEqual(self.key_reporter_value, "x")
-
- def test_clear_input(self):
- self.key_action.key_down("a").key_down("b").key_down("c").perform()
- self.assertEqual(self.key_reporter_value, "abc")
- (self.key_action.key_down(self.mod_key)
- .key_down("a")
- .key_down("x")
- .perform())
- self.assertEqual(self.key_reporter_value, "")
- self.key_action.key_down("a").key_down("b").key_down("c").perform()
- self.assertEqual(self.key_reporter_value, "abc")
-
- def test_input_with_wait(self):
- self.key_action.key_down("a").key_down("b").key_down("c").perform()
- (self.key_action.key_down(self.mod_key)
- .key_down("a")
- .wait(.5)
- .key_down("x")
- .perform())
- self.assertEqual(self.key_reporter_value, "")
-
- @skip_if_mobile("Interacting with chrome windows not available for Fennec")
- def test_open_in_new_window_shortcut(self):
-
- def open_window_with_action():
- el = self.marionette.find_element(By.ID, "updatediv")
- # Ensure that the element is in the current view port because press() doesn't
- # handle that inside the action chain (bug 1295538).
- self.marionette.execute_script('arguments[0].scrollIntoView()', script_args=[el])
- (self.key_action.key_down(Keys.SHIFT)
- .press(el)
- .release()
- .key_up(Keys.SHIFT)
- .perform())
-
- new_window = self.open_window(trigger=open_window_with_action)
- self.marionette.switch_to_window(new_window)
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
- self.assertEqual(self.key_reporter_value, "")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_localization.py b/testing/marionette/harness/marionette_harness/tests/unit/test_localization.py
deleted file mode 100644
index 1b89f6f34e..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_localization.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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 (
- InvalidArgumentException,
- NoSuchElementException,
- UnknownException
-)
-from marionette_driver.localization import L10n
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestL10n(MarionetteTestCase):
-
- def setUp(self):
- super(TestL10n, self).setUp()
-
- self.l10n = L10n(self.marionette)
-
- def test_localize_entity(self):
- dtds = ['chrome://marionette/content/test_dialog.dtd']
- value = self.l10n.localize_entity(dtds, 'testDialog.title')
-
- self.assertEqual(value, 'Test Dialog')
-
- def test_localize_entity_invalid_arguments(self):
- dtds = ['chrome://marionette/content/test_dialog.dtd']
-
- self.assertRaises(NoSuchElementException,
- self.l10n.localize_entity, dtds, 'notExistent')
- self.assertRaises(InvalidArgumentException,
- self.l10n.localize_entity, dtds[0], 'notExistent')
- self.assertRaises(InvalidArgumentException,
- self.l10n.localize_entity, dtds, True)
-
- def test_localize_property(self):
- properties = ['chrome://marionette/content/test_dialog.properties']
-
- value = self.l10n.localize_property(properties, 'testDialog.title')
- self.assertEqual(value, 'Test Dialog')
-
- self.assertRaises(NoSuchElementException,
- self.l10n.localize_property, properties, 'notExistent')
-
- def test_localize_property_invalid_arguments(self):
- properties = ['chrome://global/locale/filepicker.properties']
-
- self.assertRaises(NoSuchElementException,
- self.l10n.localize_property, properties, 'notExistent')
- self.assertRaises(InvalidArgumentException,
- self.l10n.localize_property, properties[0], 'notExistent')
- self.assertRaises(InvalidArgumentException,
- self.l10n.localize_property, properties, True)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_log.py b/testing/marionette/harness/marionette_harness/tests/unit/test_log.py
deleted file mode 100644
index dd3cf82b47..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_log.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestLog(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- # clears log cache
- self.marionette.get_logs()
-
- def test_log(self):
- self.marionette.log("foo")
- logs = self.marionette.get_logs()
- self.assertEqual("INFO", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
- def test_log_level(self):
- self.marionette.log("foo", "ERROR")
- logs = self.marionette.get_logs()
- self.assertEqual("ERROR", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
- def test_clear(self):
- self.marionette.log("foo")
- self.assertEqual(1, len(self.marionette.get_logs()))
- self.assertEqual(0, len(self.marionette.get_logs()))
-
- def test_multiple_entries(self):
- self.marionette.log("foo")
- self.marionette.log("bar")
- self.assertEqual(2, len(self.marionette.get_logs()))
-
- def test_log_from_sync_script(self):
- self.marionette.execute_script("log('foo')")
- logs = self.marionette.get_logs()
- self.assertEqual("INFO", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
- def test_log_from_sync_script_level(self):
- self.marionette.execute_script("log('foo', 'ERROR')")
- logs = self.marionette.get_logs()
- self.assertEqual("ERROR", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
- def test_log_from_async_script(self):
- self.marionette.execute_async_script("log('foo'); arguments[0]();")
- logs = self.marionette.get_logs()
- self.assertEqual("INFO", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
- def test_log_from_async_script_variable_arguments(self):
- self.marionette.execute_async_script("log('foo', 'ERROR'); arguments[0]();")
- logs = self.marionette.get_logs()
- self.assertEqual("ERROR", logs[0][0])
- self.assertEqual("foo", logs[0][1])
-
-
-class TestLogChrome(TestLog):
- def setUp(self):
- TestLog.setUp(self)
- self.marionette.set_context("chrome")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py b/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py
deleted file mode 100644
index e68312872e..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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 itertools
-import time
-
-from marionette_driver import errors
-
-from marionette_harness import MarionetteTestCase, run_if_manage_instance, skip_if_mobile
-
-
-class TestMarionette(MarionetteTestCase):
-
- def test_correct_test_name(self):
- """Test that the correct test name gets set."""
- expected_test_name = '{module}.py {cls}.{func}'.format(
- module=__name__,
- cls=self.__class__.__name__,
- func=self.test_correct_test_name.__name__,
- )
-
- self.assertEqual(self.marionette.test_name, expected_test_name)
-
- @run_if_manage_instance("Only runnable if Marionette manages the instance")
- @skip_if_mobile("Bug 1322993 - Missing temporary folder")
- def test_wait_for_port_non_existing_process(self):
- """Test that wait_for_port doesn't run into a timeout if instance is not running."""
- self.marionette.quit()
- self.assertIsNotNone(self.marionette.instance.runner.returncode)
- start_time = time.time()
- self.assertFalse(self.marionette.wait_for_port(timeout=5))
- self.assertLess(time.time() - start_time, 5)
-
-
-class TestProtocol2Errors(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.op = self.marionette.protocol
- self.marionette.protocol = 2
-
- def tearDown(self):
- self.marionette.protocol = self.op
- MarionetteTestCase.tearDown(self)
-
- def test_malformed_packet(self):
- req = ["error", "message", "stacktrace"]
- ps = []
- for p in [p for i in range(0, len(req) + 1) for p in itertools.permutations(req, i)]:
- ps.append(dict((x, None) for x in p))
-
- for p in filter(lambda p: len(p) < 3, ps):
- self.assertRaises(KeyError, self.marionette._handle_error, p)
-
- def test_known_error_status(self):
- with self.assertRaises(errors.NoSuchElementException):
- self.marionette._handle_error(
- {"error": errors.NoSuchElementException.status,
- "message": None,
- "stacktrace": None})
-
- def test_unknown_error_status(self):
- with self.assertRaises(errors.MarionetteException):
- self.marionette._handle_error(
- {"error": "barbera",
- "message": None,
- "stacktrace": None})
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
deleted file mode 100644
index f7108bdfff..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import NoAlertPresentException, ElementNotInteractableException
-from marionette_driver.marionette import Alert
-from marionette_driver.wait import Wait
-
-from marionette_harness import MarionetteTestCase, skip_if_e10s
-
-
-class TestTabModals(MarionetteTestCase):
-
- def setUp(self):
- super(TestTabModals, self).setUp()
- self.marionette.set_pref("prompts.tab_modal.enabled", True)
- self.marionette.navigate(self.marionette.absolute_url('modal_dialogs.html'))
-
- def tearDown(self):
- # Ensure an alert is absent before proceeding past this test.
- Wait(self.marionette).until(lambda _: not self.alert_present())
- self.marionette.execute_script("window.onbeforeunload = null;")
- self.marionette.clear_pref("prompts.tab_modal.enabled")
- super(TestTabModals, self).tearDown()
-
- def alert_present(self):
- try:
- Alert(self.marionette).text
- return True
- except NoAlertPresentException:
- return False
-
- def wait_for_alert(self):
- Wait(self.marionette).until(lambda _: self.alert_present())
-
- def test_no_alert_raises(self):
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).accept)
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).dismiss)
-
- def test_alert_accept(self):
- self.marionette.find_element(By.ID, 'modal-alert').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.accept()
-
- def test_alert_dismiss(self):
- self.marionette.find_element(By.ID, 'modal-alert').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.dismiss()
-
- def test_confirm_accept(self):
- self.marionette.find_element(By.ID, 'modal-confirm').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.accept()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'confirm-result').text == 'true')
-
- def test_confirm_dismiss(self):
- self.marionette.find_element(By.ID, 'modal-confirm').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.dismiss()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'confirm-result').text == 'false')
-
- def test_prompt_accept(self):
- self.marionette.find_element(By.ID, 'modal-prompt').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.accept()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'prompt-result').text == '')
-
- def test_prompt_dismiss(self):
- self.marionette.find_element(By.ID, 'modal-prompt').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.dismiss()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'prompt-result').text == 'null')
-
- def test_alert_text(self):
- with self.assertRaises(NoAlertPresentException):
- alert = self.marionette.switch_to_alert()
- alert.text
- self.marionette.find_element(By.ID, 'modal-alert').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertEqual(alert.text, 'Marionette alert')
- alert.accept()
-
- def test_prompt_text(self):
- with self.assertRaises(NoAlertPresentException):
- alert = self.marionette.switch_to_alert()
- alert.text
- self.marionette.find_element(By.ID, 'modal-prompt').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertEqual(alert.text, 'Marionette prompt')
- alert.accept()
-
- def test_confirm_text(self):
- with self.assertRaises(NoAlertPresentException):
- alert = self.marionette.switch_to_alert()
- alert.text
- self.marionette.find_element(By.ID, 'modal-confirm').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertEqual(alert.text, 'Marionette confirm')
- alert.accept()
-
- def test_set_text_throws(self):
- self.assertRaises(NoAlertPresentException, Alert(self.marionette).send_keys, "Foo")
- self.marionette.find_element(By.ID, 'modal-alert').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertRaises(ElementNotInteractableException, alert.send_keys, "Foo")
- alert.accept()
-
- def test_set_text_accept(self):
- self.marionette.find_element(By.ID, 'modal-prompt').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.send_keys("Some text!");
- alert.accept()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'prompt-result').text == 'Some text!')
-
- def test_set_text_dismiss(self):
- self.marionette.find_element(By.ID, 'modal-prompt').click()
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- alert.send_keys("Some text!");
- alert.dismiss()
- self.wait_for_condition(lambda mn: mn.find_element(By.ID, 'prompt-result').text == 'null')
-
- def test_onbeforeunload_dismiss(self):
- start_url = self.marionette.get_url()
- self.marionette.find_element(By.ID, 'onbeforeunload-handler').click()
- self.wait_for_condition(
- lambda mn: mn.execute_script("""
- return window.onbeforeunload !== null;
- """))
- self.marionette.navigate("about:blank")
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
- alert.dismiss()
- self.assertTrue(self.marionette.get_url().startswith(start_url))
-
- def test_onbeforeunload_accept(self):
- self.marionette.find_element(By.ID, 'onbeforeunload-handler').click()
- self.wait_for_condition(
- lambda mn: mn.execute_script("""
- return window.onbeforeunload !== null;
- """))
- self.marionette.navigate("about:blank")
- self.wait_for_alert()
- alert = self.marionette.switch_to_alert()
- self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
- alert.accept()
- self.wait_for_condition(lambda mn: mn.get_url() == "about:blank")
-
- @skip_if_e10s("Bug 1325044")
- def test_unrelated_command_when_alert_present(self):
- click_handler = self.marionette.find_element(By.ID, 'click-handler')
- text = self.marionette.find_element(By.ID, 'click-result').text
- self.assertEqual(text, '')
-
- self.marionette.find_element(By.ID, 'modal-alert').click()
- self.wait_for_alert()
-
- # Commands succeed, but because the dialog blocks the event loop,
- # our actions aren't reflected on the page.
- text = self.marionette.find_element(By.ID, 'click-result').text
- self.assertEqual(text, '')
- click_handler.click()
- text = self.marionette.find_element(By.ID, 'click-result').text
- self.assertEqual(text, '')
-
- alert = self.marionette.switch_to_alert()
- alert.accept()
-
- Wait(self.marionette).until(lambda _: not self.alert_present())
-
- click_handler.click()
- text = self.marionette.find_element(By.ID, 'click-result').text
- self.assertEqual(text, 'result')
-
-
-class TestGlobalModals(TestTabModals):
-
- def setUp(self):
- super(TestGlobalModals, self).setUp()
- self.marionette.set_pref("prompts.tab_modal.enabled", False)
-
- def test_unrelated_command_when_alert_present(self):
- # The assumptions in this test do not hold on certain platforms, and not when
- # e10s is enabled.
- pass
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py b/testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py
deleted file mode 100644
index 2460682158..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_mouse_action.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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.by import By
-from marionette_driver.keys import Keys
-from marionette_driver.marionette import Actions
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestMouseAction(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- if self.marionette.session_capabilities["platformName"] == "darwin":
- self.mod_key = Keys.META
- else:
- self.mod_key = Keys.CONTROL
- self.action = Actions(self.marionette)
-
- def test_click_action(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- link = self.marionette.find_element(By.ID, "mozLink")
- self.action.click(link).perform()
- self.assertEqual("Clicked", self.marionette.execute_script(
- "return document.getElementById('mozLink').innerHTML"))
-
- def test_clicking_element_out_of_view_succeeds(self):
- # The action based click doesn"t check for visibility.
- test_html = self.marionette.absolute_url("hidden.html")
- self.marionette.navigate(test_html)
- el = self.marionette.find_element(By.ID, "child")
- self.action.click(el).perform()
-
- def test_double_click_action(self):
- test_html = self.marionette.absolute_url("double_click.html")
- self.marionette.navigate(test_html)
- el = self.marionette.find_element(By.ID, "one-word-div")
- self.action.double_click(el).perform()
- el.send_keys(self.mod_key + "c")
- rel = self.marionette.find_element(By.ID, "input-field")
- rel.send_keys(self.mod_key + "v")
- self.assertEqual("zyxw", rel.get_property("value"))
-
- def test_context_click_action(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- click_el = self.marionette.find_element(By.ID, "resultContainer")
-
- def context_menu_state():
- with self.marionette.using_context("chrome"):
- cm_el = self.marionette.find_element(By.ID, "contentAreaContextMenu")
- return cm_el.get_property("state")
-
- self.assertEqual("closed", context_menu_state())
- self.action.context_click(click_el).perform()
- self.wait_for_condition(lambda _: context_menu_state() == "open")
-
- with self.marionette.using_context("chrome"):
- self.marionette.find_element(By.ID, "main-window").send_keys(Keys.ESCAPE)
- self.wait_for_condition(lambda _: context_menu_state() == "closed")
-
- def test_middle_click_action(self):
- test_html = self.marionette.absolute_url("clicks.html")
- self.marionette.navigate(test_html)
-
- self.marionette.find_element(By.ID, "addbuttonlistener").click()
-
- el = self.marionette.find_element(By.ID, "showbutton")
- self.action.middle_click(el).perform()
-
- self.wait_for_condition(lambda _: el.get_property("innerHTML") == "1")
-
- def test_chrome_click(self):
- self.marionette.navigate("about:blank")
- data_uri = "data:text/html,<html></html>"
- with self.marionette.using_context("chrome"):
- urlbar = self.marionette.find_element(By.ID, "urlbar")
- urlbar.send_keys(data_uri)
- go_button = self.marionette.find_element(By.ID, "urlbar-go-button")
- self.action.click(go_button).perform()
- self.wait_for_condition(lambda mn: mn.get_url() == data_uri)
-
- def test_chrome_double_click(self):
- self.marionette.navigate("about:blank")
- test_word = "quux"
-
- with self.marionette.using_context("chrome"):
- urlbar = self.marionette.find_element(By.ID, "urlbar")
- self.assertEqual("", urlbar.get_property("value"))
-
- urlbar.send_keys(test_word)
- self.assertEqual(urlbar.get_property("value"), test_word)
- (self.action.double_click(urlbar).perform()
- .key_down(self.mod_key)
- .key_down("x").perform())
- self.assertEqual(urlbar.get_property("value"), "")
-
- def test_chrome_context_click_action(self):
- self.marionette.set_context("chrome")
- def context_menu_state():
- cm_el = self.marionette.find_element(By.ID, "tabContextMenu")
- return cm_el.get_property("state")
-
- currtab = self.marionette.execute_script("return gBrowser.selectedTab")
- self.assertEqual("closed", context_menu_state())
- self.action.context_click(currtab).perform()
- self.wait_for_condition(lambda _: context_menu_state() == "open")
-
- (self.marionette.find_element(By.ID, "main-window")
- .send_keys(Keys.ESCAPE))
-
- self.wait_for_condition(lambda _: context_menu_state() == "closed")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py b/testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py
deleted file mode 100644
index 75ed37ecd9..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_navigation.py
+++ /dev/null
@@ -1,447 +0,0 @@
-# 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 contextlib
-import time
-import urllib
-
-from marionette_driver import By, errors, expected, Wait
-from marionette_harness import (
- MarionetteTestCase,
- run_if_e10s,
- run_if_manage_instance,
- skip,
- skip_if_mobile,
- WindowManagerMixin,
-)
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
-
-
-class TestBackForwardNavigation(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestBackForwardNavigation, self).setUp()
-
- self.test_page = self.marionette.absolute_url('test.html')
-
- def open_with_link():
- link = self.marionette.find_element(By.ID, "new-blank-tab")
- link.click()
-
- # Always use a blank new tab for an empty history
- self.marionette.navigate(self.marionette.absolute_url("windowHandles.html"))
- self.new_tab = self.open_tab(open_with_link)
- self.marionette.switch_to_window(self.new_tab)
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda _: self.history_length == 1,
- message="The newly opened tab doesn't have a browser history length of 1")
-
- def tearDown(self):
- self.marionette.switch_to_parent_frame()
- self.close_all_tabs()
-
- super(TestBackForwardNavigation, self).tearDown()
-
- @property
- def history_length(self):
- return self.marionette.execute_script("return window.history.length;")
-
- def run_test(self, test_pages):
- # Helper method to run simple back and forward testcases.
- for index, page in enumerate(test_pages):
- if "error" in page:
- with self.assertRaises(page["error"]):
- self.marionette.navigate(page["url"])
- else:
- self.marionette.navigate(page["url"])
- self.assertEqual(page["url"], self.marionette.get_url())
- self.assertEqual(self.history_length, index + 1)
-
- for page in test_pages[-2::-1]:
- if "error" in page:
- with self.assertRaises(page["error"]):
- self.marionette.go_back()
- else:
- self.marionette.go_back()
- self.assertEqual(page["url"], self.marionette.get_url())
-
- for page in test_pages[1::]:
- if "error" in page:
- with self.assertRaises(page["error"]):
- self.marionette.go_forward()
- else:
- self.marionette.go_forward()
- self.assertEqual(page["url"], self.marionette.get_url())
-
- def test_no_history_items(self):
- # Both methods should not raise a failure if no navigation is possible
- self.marionette.go_back()
- self.marionette.go_forward()
-
- def test_data_urls(self):
- test_pages = [
- {"url": inline("<p>foobar</p>")},
- {"url": self.test_page},
- {"url": inline("<p>foobar</p>")},
- ]
- self.run_test(test_pages)
-
- def test_same_document_hash_change(self):
- test_pages = [
- {"url": "{}#23".format(self.test_page)},
- {"url": self.test_page},
- {"url": "{}#42".format(self.test_page)},
- ]
- self.run_test(test_pages)
-
- @skip("Causes crashes for JS GC (bug 1344863) and a11y (bug 1344868)")
- def test_frameset(self):
- test_pages = [
- {"url": self.marionette.absolute_url("frameset.html")},
- {"url": self.test_page},
- {"url": self.marionette.absolute_url("frameset.html")},
- ]
- self.run_test(test_pages)
-
- def test_frameset_after_navigating_in_frame(self):
- test_element_locator = (By.ID, "email")
-
- self.marionette.navigate(self.test_page)
- self.assertEqual(self.marionette.get_url(), self.test_page)
- self.assertEqual(self.history_length, 1)
- page = self.marionette.absolute_url("frameset.html")
- self.marionette.navigate(page)
- self.assertEqual(self.marionette.get_url(), page)
- self.assertEqual(self.history_length, 2)
- frame = self.marionette.find_element(By.ID, "fifth")
- self.marionette.switch_to_frame(frame)
- link = self.marionette.find_element(By.ID, "linkId")
- link.click()
-
- # We cannot use get_url() to wait until the target page has been loaded,
- # because it will return the URL of the top browsing context and doesn't
- # wait for the page load to be complete.
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- expected.element_present(*test_element_locator),
- message="Target element 'email' has not been found")
- self.assertEqual(self.history_length, 3)
-
- # Go back to the frame the click navigated away from
- self.marionette.go_back()
- self.assertEqual(self.marionette.get_url(), page)
- with self.assertRaises(errors.NoSuchElementException):
- self.marionette.find_element(*test_element_locator)
-
- # Go back to the non-frameset page
- self.marionette.switch_to_parent_frame()
- self.marionette.go_back()
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- # Go forward to the frameset page
- self.marionette.go_forward()
- self.assertEqual(self.marionette.get_url(), page)
-
- # Go forward to the frame the click navigated to
- # TODO: See above for automatic browser context switches. Hard to do here
- frame = self.marionette.find_element(By.ID, "fifth")
- self.marionette.switch_to_frame(frame)
- self.marionette.go_forward()
- self.marionette.find_element(*test_element_locator)
- self.assertEqual(self.marionette.get_url(), page)
-
- def test_image_document_to_html(self):
- test_pages = [
- {"url": self.marionette.absolute_url('black.png')},
- {"url": self.test_page},
- {"url": self.marionette.absolute_url('white.png')},
- ]
- self.run_test(test_pages)
-
- def test_image_document_to_image_document(self):
- test_pages = [
- {"url": self.marionette.absolute_url('black.png')},
- {"url": self.marionette.absolute_url('white.png')},
- ]
- self.run_test(test_pages)
-
- @run_if_e10s("Requires e10s mode enabled")
- def test_remoteness_change(self):
- # TODO: Verify that a remoteness change happened
- # like: self.assertNotEqual(self.marionette.current_window_handle, self.new_tab)
-
- # about:robots is always a non-remote page for now
- test_pages = [
- {"url": "about:robots"},
- {"url": self.test_page},
- {"url": "about:robots"},
- ]
- self.run_test(test_pages)
-
- def test_navigate_to_requested_about_page_after_error_page(self):
- test_pages = [
- {"url": "about:neterror"},
- {"url": self.marionette.absolute_url("test.html")},
- {"url": "about:blocked"},
- ]
- self.run_test(test_pages)
-
- def test_timeout_error(self):
- # Bug 1354908 - Disabled on Windows XP due to intermittent failures
- caps = self.marionette.session_capabilities
- if caps["platformName"] == "windows_nt" and float(caps["platformVersion"]) < 6:
- return
-
- urls = [
- self.marionette.absolute_url('slow'),
- self.test_page,
- self.marionette.absolute_url('slow'),
- ]
-
- # First, load all pages completely to get them added to the cache
- for index, url in enumerate(urls):
- self.marionette.navigate(url)
- self.assertEqual(url, self.marionette.get_url())
- self.assertEqual(self.history_length, index + 1)
-
- self.marionette.go_back()
- self.assertEqual(urls[1], self.marionette.get_url())
-
- # Force triggering a timeout error
- self.marionette.timeout.page_load = 0.1
- with self.assertRaises(errors.TimeoutException):
- self.marionette.go_back()
- self.assertEqual(urls[0], self.marionette.get_url())
- self.marionette.timeout.page_load = 300000
-
- self.marionette.go_forward()
- self.assertEqual(urls[1], self.marionette.get_url())
-
- # Force triggering a timeout error
- self.marionette.timeout.page_load = 0.1
- with self.assertRaises(errors.TimeoutException):
- self.marionette.go_forward()
- self.assertEqual(urls[2], self.marionette.get_url())
- self.marionette.timeout.page_load = 300000
-
- def test_certificate_error(self):
- test_pages = [
- {"url": self.fixtures.where_is("/test.html", on="https"),
- "error": errors.InsecureCertificateException},
- {"url": self.test_page},
- {"url": self.fixtures.where_is("/test.html", on="https"),
- "error": errors.InsecureCertificateException},
- ]
- self.run_test(test_pages)
-
-
-class TestNavigate(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestNavigate, self).setUp()
-
- self.marionette.navigate("about:")
- self.test_doc = self.marionette.absolute_url("test.html")
- self.iframe_doc = self.marionette.absolute_url("test_iframe.html")
-
- def tearDown(self):
- self.marionette.timeout.reset()
- self.close_all_tabs()
-
- super(TestNavigate, self).tearDown()
-
- @property
- def location_href(self):
- # Windows 8 has recently seen a proliferation of intermittent
- # test failures to do with failing to compare "about:blank" ==
- # u"about:blank". For the sake of consistenty, we encode the
- # returned URL as Unicode here to ensure that the values are
- # absolutely of the same type.
- #
- # (https://bugzilla.mozilla.org/show_bug.cgi?id=1322862)
- return self.marionette.execute_script("return window.location.href").encode("utf-8")
-
- def test_set_location_through_execute_script(self):
- self.marionette.execute_script(
- "window.location.href = '%s'" % self.test_doc)
- Wait(self.marionette).until(
- lambda _: self.test_doc == self.location_href)
- self.assertEqual("Marionette Test", self.marionette.title)
-
- def test_navigate_chrome_error(self):
- with self.marionette.using_context("chrome"):
- self.assertRaises(errors.UnsupportedOperationException,
- self.marionette.navigate, "about:blank")
- self.assertRaises(errors.UnsupportedOperationException, self.marionette.go_back)
- self.assertRaises(errors.UnsupportedOperationException, self.marionette.go_forward)
- self.assertRaises(errors.UnsupportedOperationException, self.marionette.refresh)
-
- def test_get_current_url_returns_top_level_browsing_context_url(self):
- self.marionette.navigate(self.iframe_doc)
- self.assertEqual(self.iframe_doc, self.location_href)
- frame = self.marionette.find_element(By.CSS_SELECTOR, "#test_iframe")
- self.marionette.switch_to_frame(frame)
- self.assertEqual(self.iframe_doc, self.marionette.get_url())
-
- def test_get_current_url(self):
- self.marionette.navigate(self.test_doc)
- self.assertEqual(self.test_doc, self.marionette.get_url())
- self.marionette.navigate("about:blank")
- self.assertEqual("about:blank", self.marionette.get_url())
-
- def test_refresh(self):
- self.marionette.navigate(self.test_doc)
- self.assertEqual("Marionette Test", self.marionette.title)
- self.assertTrue(self.marionette.execute_script(
- """var elem = window.document.createElement('div'); elem.id = 'someDiv';
- window.document.body.appendChild(elem); return true;"""))
- self.assertFalse(self.marionette.execute_script(
- "return window.document.getElementById('someDiv') == undefined"))
- self.marionette.refresh()
- # TODO(ato): Bug 1291320
- time.sleep(0.2)
- self.assertEqual("Marionette Test", self.marionette.title)
- self.assertTrue(self.marionette.execute_script(
- "return window.document.getElementById('someDiv') == undefined"))
-
- def test_navigate_in_child_frame_changes_to_top(self):
- frame_html = self.marionette.absolute_url("frameset.html")
-
- self.marionette.navigate(frame_html)
- frame = self.marionette.find_element(By.NAME, "third")
- self.marionette.switch_to_frame(frame)
- self.assertRaises(errors.NoSuchElementException,
- self.marionette.find_element, By.NAME, "third")
-
- self.marionette.navigate(frame_html)
- self.marionette.find_element(By.NAME, "third")
-
- @skip_if_mobile("Bug 1323755 - Socket timeout")
- def test_invalid_protocol(self):
- with self.assertRaises(errors.MarionetteException):
- self.marionette.navigate("thisprotocoldoesnotexist://")
-
- def test_find_element_state_complete(self):
- self.marionette.navigate(self.test_doc)
- state = self.marionette.execute_script(
- "return window.document.readyState")
- self.assertEqual("complete", state)
- self.assertTrue(self.marionette.find_element(By.ID, "mozLink"))
-
- def test_error_when_exceeding_page_load_timeout(self):
- self.marionette.timeout.page_load = 0.1
- with self.assertRaises(errors.TimeoutException):
- self.marionette.navigate(self.marionette.absolute_url("slow"))
-
- def test_navigate_to_same_image_document_twice(self):
- self.marionette.navigate(self.fixtures.where_is("black.png"))
- self.assertIn("black.png", self.marionette.title)
- self.marionette.navigate(self.fixtures.where_is("black.png"))
- self.assertIn("black.png", self.marionette.title)
-
- def test_navigate_hash_change(self):
- doc = inline("<p id=foo>")
- self.marionette.navigate(doc)
- self.marionette.execute_script("window.visited = true", sandbox=None)
- self.marionette.navigate("{}#foo".format(doc))
- self.assertTrue(self.marionette.execute_script(
- "return window.visited", sandbox=None))
-
- @skip_if_mobile("Bug 1334095 - Timeout: No new tab has been opened")
- def test_about_blank_for_new_docshell(self):
- """ Bug 1312674 - Hang when loading about:blank for a new docshell."""
- def open_with_link():
- link = self.marionette.find_element(By.ID, "new-blank-tab")
- link.click()
-
- # Open a new tab to get a new docshell created
- self.marionette.navigate(self.marionette.absolute_url("windowHandles.html"))
- new_tab = self.open_tab(trigger=open_with_link)
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.get_url(), "about:blank")
-
- self.marionette.navigate('about:blank')
- self.marionette.close()
- self.marionette.switch_to_window(self.start_window)
-
- @skip("Bug 1332064 - NoSuchElementException: Unable to locate element: :focus")
- @run_if_manage_instance("Only runnable if Marionette manages the instance")
- @skip_if_mobile("Bug 1322993 - Missing temporary folder")
- def test_focus_after_navigation(self):
- self.marionette.quit()
- self.marionette.start_session()
-
- self.marionette.navigate(inline("<input autofocus>"))
- active_el = self.marionette.execute_script("return document.activeElement")
- focus_el = self.marionette.find_element(By.CSS_SELECTOR, ":focus")
- self.assertEqual(active_el, focus_el)
-
-
-class TestTLSNavigation(MarionetteTestCase):
- insecure_tls = {"acceptInsecureCerts": True}
- secure_tls = {"acceptInsecureCerts": False}
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.delete_session()
- self.capabilities = self.marionette.start_session(
- {"requiredCapabilities": self.insecure_tls})
-
- def tearDown(self):
- try:
- self.marionette.delete_session()
- except:
- pass
- MarionetteTestCase.tearDown(self)
-
- @contextlib.contextmanager
- def safe_session(self):
- try:
- self.capabilities = self.marionette.start_session(
- {"requiredCapabilities": self.secure_tls})
- self.assertFalse(self.capabilities["acceptInsecureCerts"])
- yield self.marionette
- finally:
- self.marionette.delete_session()
-
- @contextlib.contextmanager
- def unsafe_session(self):
- try:
- self.capabilities = self.marionette.start_session(
- {"requiredCapabilities": self.insecure_tls})
- self.assertTrue(self.capabilities["acceptInsecureCerts"])
- yield self.marionette
- finally:
- self.marionette.delete_session()
-
- def test_navigate_by_command(self):
- self.marionette.navigate(
- self.fixtures.where_is("/test.html", on="https"))
- self.assertIn("https", self.marionette.get_url())
-
- def test_navigate_by_click(self):
- link_url = self.fixtures.where_is("/test.html", on="https")
- self.marionette.navigate(
- inline("<a href=%s>https is the future</a>" % link_url))
- self.marionette.find_element(By.TAG_NAME, "a").click()
- self.assertIn("https", self.marionette.get_url())
-
- def test_deactivation(self):
- invalid_cert_url = self.fixtures.where_is("/test.html", on="https")
-
- print "with safe session"
- with self.safe_session() as session:
- with self.assertRaises(errors.InsecureCertificateException):
- session.navigate(invalid_cert_url)
-
- print "with unsafe session"
- with self.unsafe_session() as session:
- session.navigate(invalid_cert_url)
-
- print "with safe session again"
- with self.safe_session() as session:
- with self.assertRaises(errors.InsecureCertificateException):
- session.navigate(invalid_cert_url)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource.py b/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource.py
deleted file mode 100644
index c886669869..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestPageSource(MarionetteTestCase):
- def testShouldReturnTheSourceOfAPage(self):
- test_html = self.marionette.absolute_url("testPageSource.html")
- self.marionette.navigate(test_html)
- source = self.marionette.page_source
- from_web_api = self.marionette.execute_script("return document.documentElement.outerHTML")
- self.assertTrue("<html" in source)
- self.assertTrue("PageSource" in source)
- self.assertEqual(source, from_web_api)
-
- def testShouldReturnTheSourceOfAPageWhenThereAreUnicodeChars(self):
- test_html = self.marionette.absolute_url("testPageSourceWithUnicodeChars.html")
- self.marionette.navigate(test_html)
- # if we don't throw on the next line we are good!
- source = self.marionette.page_source
- from_web_api = self.marionette.execute_script("return document.documentElement.outerHTML")
- self.assertEqual(source, from_web_api)
-
- def testShouldReturnAXMLDocumentSource(self):
- test_xml = self.marionette.absolute_url("testPageSource.xml")
- self.marionette.navigate(test_xml)
- source = self.marionette.page_source
- from_web_api = self.marionette.execute_script("return document.documentElement.outerHTML")
- import re
- self.assertEqual(re.sub("\s", "", source), "<xml><foo><bar>baz</bar></foo></xml>")
- self.assertEqual(source, from_web_api)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource_chrome.py
deleted file mode 100644
index 5f60e60109..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_pagesource_chrome.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestPageSourceChrome(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestPageSourceChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- def open_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(open_with_js)
- self.marionette.switch_to_window(new_window)
-
- def tearDown(self):
- self.close_all_windows()
- super(TestPageSourceChrome, self).tearDown()
-
- def testShouldReturnXULDetails(self):
- source = self.marionette.page_source
- self.assertTrue('<textbox id="textInput"' in source)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_position.py b/testing/marionette/harness/marionette_harness/tests/unit/test_position.py
deleted file mode 100644
index 2cc4d59470..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_position.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestPosition(MarionetteTestCase):
-
- def test_should_get_element_position_back(self):
- test_url = self.marionette.absolute_url('rectangles.html')
- self.marionette.navigate(test_url)
-
- r2 = self.marionette.find_element(By.ID, "r2")
- location = r2.rect
- self.assertEqual(11, location['x'])
- self.assertEqual(10, location['y'])
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py b/testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py
deleted file mode 100644
index 9cfbe1df1f..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# 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 JavascriptException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestPreferences(MarionetteTestCase):
- prefs = {
- "bool": "marionette.test.bool",
- "int": "marionette.test.int",
- "string": "marionette.test.string",
- }
-
- def tearDown(self):
- for pref in self.prefs.values():
- self.marionette.clear_pref(pref)
-
- super(TestPreferences, self).tearDown()
-
- def test_clear_pref(self):
- self.assertIsNone(self.marionette.get_pref(self.prefs["bool"]))
-
- self.marionette.set_pref(self.prefs["bool"], True)
- self.assertTrue(self.marionette.get_pref(self.prefs["bool"]))
-
- self.marionette.clear_pref(self.prefs["bool"])
- self.assertIsNone(self.marionette.get_pref(self.prefs["bool"]))
-
- def test_get_and_set_pref(self):
- # By default none of the preferences are set
- self.assertIsNone(self.marionette.get_pref(self.prefs["bool"]))
- self.assertIsNone(self.marionette.get_pref(self.prefs["int"]))
- self.assertIsNone(self.marionette.get_pref(self.prefs["string"]))
-
- # Test boolean values
- self.marionette.set_pref(self.prefs["bool"], True)
- value = self.marionette.get_pref(self.prefs["bool"])
- self.assertTrue(value)
- self.assertEqual(type(value), bool)
-
- # Test int values
- self.marionette.set_pref(self.prefs["int"], 42)
- value = self.marionette.get_pref(self.prefs["int"])
- self.assertEqual(value, 42)
- self.assertEqual(type(value), int)
-
- # Test string values
- self.marionette.set_pref(self.prefs["string"], "abc")
- value = self.marionette.get_pref(self.prefs["string"])
- self.assertEqual(value, "abc")
- self.assertTrue(isinstance(value, basestring))
-
- # Test reset value
- self.marionette.set_pref(self.prefs["string"], None)
- self.assertIsNone(self.marionette.get_pref(self.prefs["string"]))
-
- def test_get_set_pref_default_branch(self):
- pref_default = "marionette.test.pref_default1"
- self.assertIsNone(self.marionette.get_pref(self.prefs["string"]))
-
- self.marionette.set_pref(pref_default, "default_value", default_branch=True)
- self.assertEqual(self.marionette.get_pref(pref_default), "default_value")
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "default_value")
-
- self.marionette.set_pref(pref_default, "user_value")
- self.assertEqual(self.marionette.get_pref(pref_default), "user_value")
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "default_value")
-
- self.marionette.clear_pref(pref_default)
- self.assertEqual(self.marionette.get_pref(pref_default), "default_value")
-
- def test_get_pref_value_type(self):
- # Without a given value type the properties URL will be returned only
- pref_complex = "browser.menu.showCharacterEncoding"
- properties_file = "chrome://browser/locale/browser.properties"
- self.assertEqual(self.marionette.get_pref(pref_complex, default_branch=True),
- properties_file)
-
- # Otherwise the property named like the pref will be translated
- value = self.marionette.get_pref(pref_complex, default_branch=True,
- value_type="nsIPrefLocalizedString")
- self.assertNotEqual(value, properties_file)
-
- def test_set_prefs(self):
- # By default none of the preferences are set
- self.assertIsNone(self.marionette.get_pref(self.prefs["bool"]))
- self.assertIsNone(self.marionette.get_pref(self.prefs["int"]))
- self.assertIsNone(self.marionette.get_pref(self.prefs["string"]))
-
- # Set a value on the default branch first
- pref_default = "marionette.test.pref_default2"
- self.assertIsNone(self.marionette.get_pref(pref_default))
- self.marionette.set_prefs({pref_default: "default_value"}, default_branch=True)
-
- # Set user values
- prefs = {self.prefs["bool"]: True, self.prefs["int"]: 42,
- self.prefs["string"]: "abc", pref_default: "user_value"}
- self.marionette.set_prefs(prefs)
-
- self.assertTrue(self.marionette.get_pref(self.prefs["bool"]))
- self.assertEqual(self.marionette.get_pref(self.prefs["int"]), 42)
- self.assertEqual(self.marionette.get_pref(self.prefs["string"]), "abc")
- self.assertEqual(self.marionette.get_pref(pref_default), "user_value")
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "default_value")
-
- def test_using_prefs(self):
- # Test that multiple preferences can be set with "using_prefs", and that
- # they are set correctly and unset correctly after leaving the context
- # manager.
- pref_not_existent = "marionette.test.not_existent1"
- pref_default = "marionette.test.pref_default3"
-
- self.marionette.set_prefs({self.prefs["string"]: "abc",
- self.prefs["int"]: 42,
- self.prefs["bool"]: False,
- })
- self.assertFalse(self.marionette.get_pref(self.prefs["bool"]))
- self.assertEqual(self.marionette.get_pref(self.prefs["int"]), 42)
- self.assertEqual(self.marionette.get_pref(self.prefs["string"]), "abc")
- self.assertIsNone(self.marionette.get_pref(pref_not_existent))
-
- with self.marionette.using_prefs({self.prefs["bool"]: True,
- self.prefs["int"]: 24,
- self.prefs["string"]: "def",
- pref_not_existent: "existent"}):
-
- self.assertTrue(self.marionette.get_pref(self.prefs["bool"]), True)
- self.assertEquals(self.marionette.get_pref(self.prefs["int"]), 24)
- self.assertEquals(self.marionette.get_pref(self.prefs["string"]), "def")
- self.assertEquals(self.marionette.get_pref(pref_not_existent), "existent")
-
- self.assertFalse(self.marionette.get_pref(self.prefs["bool"]))
- self.assertEqual(self.marionette.get_pref(self.prefs["int"]), 42)
- self.assertEqual(self.marionette.get_pref(self.prefs["string"]), "abc")
- self.assertIsNone(self.marionette.get_pref(pref_not_existent))
-
- # Using context with default branch
- self.marionette.set_pref(pref_default, "default_value", default_branch=True)
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "default_value")
-
- with self.marionette.using_prefs({pref_default: "new_value"}, default_branch=True):
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "new_value")
-
- self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
- "default_value")
-
- def test_using_prefs_exception(self):
- # Test that throwing an exception inside the context manager doesn"t
- # prevent the preferences from being restored at context manager exit.
- self.marionette.set_pref(self.prefs["string"], "abc")
-
- try:
- with self.marionette.using_prefs({self.prefs["string"]: "def"}):
- self.assertEquals(self.marionette.get_pref(self.prefs["string"]), "def")
- self.marionette.execute_script("return foo.bar.baz;")
- except JavascriptException:
- pass
-
- self.assertEquals(self.marionette.get_pref(self.prefs["string"]), "abc")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py b/testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py
deleted file mode 100644
index f8ec952b27..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestProfileManagement(MarionetteTestCase):
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.enforce_gecko_prefs(
- {"marionette.test.bool": True,
- "marionette.test.string": "testing",
- "marionette.test.int": 3
- })
- self.marionette.set_context("chrome")
-
- def test_preferences_are_set(self):
- self.assertTrue(self.marionette.get_pref("marionette.test.bool"))
- self.assertEqual(self.marionette.get_pref("marionette.test.string"), "testing")
- self.assertEqual(self.marionette.get_pref("marionette.test.int"), 3)
-
- def test_change_preference(self):
- self.assertTrue(self.marionette.get_pref("marionette.test.bool"))
-
- self.marionette.enforce_gecko_prefs({"marionette.test.bool": False})
-
- self.assertFalse(self.marionette.get_pref("marionette.test.bool"))
-
- def test_clean_profile(self):
- self.marionette.restart(clean=True)
-
- self.assertEqual(self.marionette.get_pref("marionette.test.bool"), None)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_proxy.py b/testing/marionette/harness/marionette_harness/tests/unit/test_proxy.py
deleted file mode 100644
index 887d69b764..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_proxy.py
+++ /dev/null
@@ -1,252 +0,0 @@
-# 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 InvalidArgumentException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestProxy(MarionetteTestCase):
-
- def setUp(self):
- super(TestProxy, self).setUp()
- self.marionette.delete_session()
-
- def test_that_we_can_set_a_autodetect_proxy(self):
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "autodetect",
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- }
- """)
-
- self.assertEqual(result["proxyType"], 4)
-
- def test_that_capabilities_returned_have_proxy_details(self):
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "autodetect",
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = self.marionette.session_capabilities
-
- self.assertEqual(result["proxy"]["proxyType"], "autodetect")
-
- def test_that_we_can_set_a_system_proxy(self):
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "system",
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- }
- """)
-
- self.assertEqual(result["proxyType"], 5)
-
- def test_we_can_set_a_pac_proxy(self):
- url = "http://marionette.test"
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "pac",
- "proxyAutoconfigUrl": url,
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- "proxyAutoconfigUrl" : Services.prefs.getCharPref('network.proxy.autoconfig_url'),
- }
- """)
-
- self.assertEqual(result["proxyType"], 2)
- self.assertEqual(result["proxyAutoconfigUrl"], url, 'proxyAutoconfigUrl was not set')
-
- def test_that_we_can_set_a_manual_proxy(self):
- port = 4444
- url = "http://marionette.test"
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "manual",
- "ftpProxy": url,
- "ftpProxyPort": port,
- "httpProxy": url,
- "httpProxyPort": port,
- "sslProxy": url,
- "sslProxyPort": port,
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- "httpProxy" : Services.prefs.getCharPref('network.proxy.http'),
- "httpProxyPort": Services.prefs.getIntPref('network.proxy.http_port'),
- "sslProxy": Services.prefs.getCharPref('network.proxy.ssl'),
- "sslProxyPort": Services.prefs.getIntPref('network.proxy.ssl_port'),
- "ftpProxy": Services.prefs.getCharPref('network.proxy.ftp'),
- "ftpProxyPort": Services.prefs.getIntPref('network.proxy.ftp_port'),
- }
- """)
-
- self.assertEqual(result["proxyType"], 1)
- self.assertEqual(result["httpProxy"], url, 'httpProxy was not set')
- self.assertEqual(result["httpProxyPort"], port, 'httpProxyPort was not set')
- self.assertEqual(result["sslProxy"], url, 'sslProxy url was not set')
- self.assertEqual(result["sslProxyPort"], port, 'sslProxyPort was not set')
- self.assertEqual(result["ftpProxy"], url, 'ftpProxy was not set')
- self.assertEqual(result["ftpProxyPort"], port, 'ftpProxyPort was not set')
-
- def test_we_can_set_a_manual_proxy_with_a_socks_proxy_with_socks_version(self):
- port = 4444
- url = "http://marionette.test"
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "manual",
- "socksProxy": url,
- "socksProxyPort": port,
- "socksVersion": 4,
- "socksUsername": "cake",
- "socksPassword": "made with cake"
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- "socksProxy" : Services.prefs.getCharPref('network.proxy.socks'),
- "socksProxyPort": Services.prefs.getIntPref('network.proxy.socks_port'),
- "socksVersion": Services.prefs.getIntPref('network.proxy.socks_version'),
- }
- """)
- self.assertEqual(result["socksProxy"], url, 'socksProxy was not set')
- self.assertEqual(result["socksProxyPort"], port, 'socksProxyPort was not set')
- self.assertEqual(result["socksVersion"], 4, 'socksVersion was not set to 4')
-
- def test_we_can_set_a_manual_proxy_with_a_socks_proxy_with_no_socks_version(self):
- port = 4444
- url = "http://marionette.test"
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "manual",
- "socksProxy": url,
- "socksProxyPort": port,
- "socksUsername": "cake",
- "socksPassword": "made with cake"
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- "socksProxy" : Services.prefs.getCharPref('network.proxy.socks'),
- "socksProxyPort": Services.prefs.getIntPref('network.proxy.socks_port'),
- "socksVersion": Services.prefs.getIntPref('network.proxy.socks_version'),
-
- }
- """)
- self.assertEqual(result["socksProxy"], url, 'socksProxy was not set')
- self.assertEqual(result["socksProxyPort"], port, 'socksProxyPort was not set')
- self.assertEqual(result["socksVersion"], 5, 'socksVersion was not set to 5')
-
- def test_when_not_all_manual_proxy_details_are_in_capabilities(self):
- port = 4444
- url = "http://marionette.test"
- capabilities = {"requiredCapabilities":
- {
- "proxy":{
- "proxyType": "manual",
- "ftpProxy": url,
- "ftpProxyPort": port,
- }
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType" : Services.prefs.getIntPref('network.proxy.type'),
- "httpProxy" : Services.prefs.getCharPref('network.proxy.http'),
- "httpProxyPort": Services.prefs.getIntPref('network.proxy.http_port'),
- "sslProxy": Services.prefs.getCharPref('network.proxy.ssl'),
- "sslProxyPort": Services.prefs.getIntPref('network.proxy.ssl_port'),
- "ftpProxy": Services.prefs.getCharPref('network.proxy.ftp'),
- "ftpProxyPort": Services.prefs.getIntPref('network.proxy.ftp_port'),
- }
- """)
-
- self.assertEqual(result["proxyType"], 1)
- self.assertNotEqual(result["httpProxy"], url,
- 'httpProxy was set. {}'.format(result["httpProxy"]))
- self.assertNotEqual(result["httpProxyPort"], port, 'httpProxyPort was set')
- self.assertNotEqual(result["sslProxy"], url, 'sslProxy url was set')
- self.assertNotEqual(result["sslProxyPort"], port, 'sslProxyPort was set')
- self.assertEqual(result["ftpProxy"], url, 'ftpProxy was set')
- self.assertEqual(result["ftpProxyPort"], port, 'ftpProxyPort was set')
-
-
-
- def test_proxy_is_a_string_should_throw_invalid_argument(self):
- capabilities = {"requiredCapabilities":
- {
- "proxy":"I really should be a dictionary"
- }
- }
- try:
- self.marionette.start_session(capabilities)
- self.fail("We should have started a session because proxy should be a dict")
- except InvalidArgumentException as e:
- assert e.message == "Value of 'proxy' should be an object"
-
- def test_proxy_is_passed_in_with_no_proxy_doesnt_set_it(self):
- capabilities = {"requiredCapabilities":
- {
- "proxy": {"proxyType": "NOPROXY"},
- }
- }
- self.marionette.start_session(capabilities)
- result = None
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_script("""return {
- "proxyType": Services.prefs.getIntPref('network.proxy.type'),
- };
- """)
-
- self.assertEqual(result["proxyType"], 0)
-
- def tearDown(self):
- if not self.marionette.session:
- self.marionette.start_session()
- else:
- self.marionette.restart(clean=True)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py b/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
deleted file mode 100644
index 38c6785562..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# 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 marionette_harness import MarionetteTestCase
-
-
-class TestQuitRestart(MarionetteTestCase):
-
- def setUp(self):
- MarionetteTestCase.setUp(self)
-
- self.pid = self.marionette.process_id
- self.session_id = self.marionette.session_id
-
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
- self.marionette.set_pref("browser.startup.page", 3)
-
- def tearDown(self):
- # Ensure to restart a session if none exist for clean-up
- if not self.marionette.session:
- self.marionette.start_session()
-
- self.marionette.clear_pref("browser.startup.page")
-
- MarionetteTestCase.tearDown(self)
-
- def test_force_restart(self):
- self.marionette.restart()
- self.assertEqual(self.marionette.session_id, self.session_id)
-
- # A forced restart will cause a new process id
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- # If a preference value is not forced, a restart will cause a reset
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_force_quit(self):
- self.marionette.quit()
-
- self.assertEqual(self.marionette.session, None)
- with self.assertRaisesRegexp(MarionetteException, "Please start a session"):
- self.marionette.get_url()
-
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.session_id, self.session_id)
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_in_app_clean_restart(self):
- with self.assertRaises(ValueError):
- self.marionette.restart(in_app=True, clean=True)
-
- def test_in_app_restart(self):
- self.marionette.restart(in_app=True)
- self.assertEqual(self.marionette.session_id, self.session_id)
-
- # An in-app restart will keep the same process id only on Linux
- if self.marionette.session_capabilities['platformName'] == 'linux':
- self.assertEqual(self.marionette.process_id, self.pid)
- else:
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- # If a preference value is not forced, a restart will cause a reset
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_in_app_restart_with_callback(self):
- self.marionette.restart(in_app=True,
- callback=lambda: self.shutdown(restart=True))
-
- self.assertEqual(self.marionette.session_id, self.session_id)
-
- # An in-app restart will keep the same process id only on Linux
- if self.marionette.session_capabilities['platformName'] == 'linux':
- self.assertEqual(self.marionette.process_id, self.pid)
- else:
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- # If a preference value is not forced, a restart will cause a reset
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_in_app_quit(self):
- self.marionette.quit(in_app=True)
-
- self.assertEqual(self.marionette.session, None)
- with self.assertRaisesRegexp(MarionetteException, "Please start a session"):
- self.marionette.get_url()
-
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.session_id, self.session_id)
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_in_app_quit_with_callback(self):
- self.marionette.quit(in_app=True, callback=self.shutdown)
- self.assertEqual(self.marionette.session, None)
- with self.assertRaisesRegexp(MarionetteException, "Please start a session"):
- self.marionette.get_url()
-
- self.marionette.start_session()
- self.assertNotEqual(self.marionette.session_id, self.session_id)
- self.assertNotEqual(self.marionette.get_pref("browser.startup.page"), 3)
-
- def test_reset_context_after_quit_by_set_context(self):
- # Check that we are in content context which is used by default in Marionette
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Context doesn't default to content")
-
- self.marionette.set_context('chrome')
- self.marionette.quit(in_app=True)
- self.assertEqual(self.marionette.session, None)
- self.marionette.start_session()
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Not in content context after quit with using_context")
-
- def test_reset_context_after_quit_by_using_context(self):
- # Check that we are in content context which is used by default in Marionette
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Context doesn't default to content")
-
- with self.marionette.using_context('chrome'):
- self.marionette.quit(in_app=True)
- self.assertEqual(self.marionette.session, None)
- self.marionette.start_session()
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Not in content context after quit with using_context")
-
- def test_keep_context_after_restart_by_set_context(self):
- # Check that we are in content context which is used by default in Marionette
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Context doesn't default to content")
-
- # restart while we are in chrome context
- self.marionette.set_context('chrome')
- self.marionette.restart(in_app=True)
-
- # An in-app restart will keep the same process id only on Linux
- if self.marionette.session_capabilities['platformName'] == 'linux':
- self.assertEqual(self.marionette.process_id, self.pid)
- else:
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- self.assertIn('chrome://', self.marionette.get_url(),
- "Not in chrome context after a restart with set_context")
-
- def test_keep_context_after_restart_by_using_context(self):
- # Check that we are in content context which is used by default in Marionette
- self.assertNotIn('chrome://', self.marionette.get_url(),
- "Context doesn't default to content")
-
- # restart while we are in chrome context
- with self.marionette.using_context('chrome'):
- self.marionette.restart(in_app=True)
-
- # An in-app restart will keep the same process id only on Linux
- if self.marionette.session_capabilities['platformName'] == 'linux':
- self.assertEqual(self.marionette.process_id, self.pid)
- else:
- self.assertNotEqual(self.marionette.process_id, self.pid)
-
- self.assertIn('chrome://', self.marionette.get_url(),
- "Not in chrome context after a restart with using_context")
-
- def shutdown(self, restart=False):
- self.marionette.set_context("chrome")
- self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let flags = Ci.nsIAppStartup.eAttemptQuit
- if(arguments[0]) {
- flags |= Ci.nsIAppStartup.eRestart;
- }
- Services.startup.quit(flags);
- """, script_args=[restart])
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_rendered_element.py b/testing/marionette/harness/marionette_harness/tests/unit/test_rendered_element.py
deleted file mode 100644
index 508870e918..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_rendered_element.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#Copyright 2007-2009 WebDriver committers
-#Copyright 2007-2009 Google Inc.
-#
-#Licensed under the Apache License, Version 2.0 (the "License");
-#you may not use this file except in compliance with the License.
-#You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-#Unless required by applicable law or agreed to in writing, software
-#distributed under the License is distributed on an "AS IS" BASIS,
-#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#See the License for the specific language governing permissions and
-#limitations under the License.
-
-from marionette_driver.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class RenderedElementTests(MarionetteTestCase):
-
- def testWeCanGetComputedStyleValueOnElement(self):
- test_url = self.marionette.absolute_url('javascriptPage.html')
- self.marionette.navigate(test_url)
- element = self.marionette.find_element(By.ID, "green-parent")
- backgroundColour = element.value_of_css_property("background-color")
-
- self.assertEqual("rgb(0, 128, 0)", backgroundColour)
-
- element = self.marionette.find_element(By.ID, "red-item")
- backgroundColour = element.value_of_css_property("background-color")
-
- self.assertEqual("rgb(255, 0, 0)", backgroundColour)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_report.py b/testing/marionette/harness/marionette_harness/tests/unit/test_report.py
deleted file mode 100644
index f22c3db4b7..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_report.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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_harness import MarionetteTestCase, expectedFailure, skip
-
-
-class TestReport(MarionetteTestCase):
-
- def test_pass(self):
- assert True
-
- def test_fail(self):
- assert False
-
- @skip('Skip Message')
- def test_skip(self):
- assert False
-
- @expectedFailure
- def test_expected_fail(self):
- assert False
-
- @expectedFailure
- def test_unexpected_pass(self):
- assert True
-
- def test_error(self):
- raise Exception()
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_run_js_test.py b/testing/marionette/harness/marionette_harness/tests/unit/test_run_js_test.py
deleted file mode 100644
index 134223ce15..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_run_js_test.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# Any copyright is dedicated to the Public Domain.
-# http://creativecommons.org/publicdomain/zero/1.0/
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestRunJSTest(MarionetteTestCase):
- def test_basic(self):
- self.run_js_test('test_simpletest_pass.js')
- self.run_js_test('test_simpletest_fail.js')
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_screen_orientation.py b/testing/marionette/harness/marionette_harness/tests/unit/test_screen_orientation.py
deleted file mode 100644
index 830795a1ec..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_screen_orientation.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# 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 errors
-from mozrunner.devices.emulator_screen import EmulatorScreen
-
-from marionette_harness import MarionetteTestCase, skip_if_desktop, skip_if_mobile
-
-
-default_orientation = "portrait-primary"
-unknown_orientation = "Unknown screen orientation: {}"
-
-
-class TestScreenOrientation(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.is_mobile = self.marionette.session_capabilities.get("rotatable", False)
-
- def tearDown(self):
- if self.is_mobile:
- self.marionette.set_orientation(default_orientation)
- self.assertEqual(self.marionette.orientation, default_orientation, "invalid state")
- MarionetteTestCase.tearDown(self)
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_portrait_primary(self):
- self.marionette.set_orientation("portrait-primary")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "portrait-primary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_landscape_primary(self):
- self.marionette.set_orientation("landscape-primary")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "landscape-primary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_portrait_secondary(self):
- self.marionette.set_orientation("portrait-secondary")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "portrait-secondary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_landscape_secondary(self):
- self.marionette.set_orientation("landscape-secondary")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "landscape-secondary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_shorthand_portrait(self):
- # Set orientation to something other than portrait-primary first, since the default is
- # portrait-primary.
- self.marionette.set_orientation("landscape-primary")
- self.assertEqual(self.marionette.orientation, "landscape-primary", "invalid state")
-
- self.marionette.set_orientation("portrait")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "portrait-primary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_to_shorthand_landscape(self):
- self.marionette.set_orientation("landscape")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "landscape-primary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_orientation_with_mixed_casing(self):
- self.marionette.set_orientation("lAnDsCaPe")
- new_orientation = self.marionette.orientation
- self.assertEqual(new_orientation, "landscape-primary")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_invalid_orientation(self):
- with self.assertRaisesRegexp(errors.MarionetteException, unknown_orientation.format("cheese")):
- self.marionette.set_orientation("cheese")
-
- @skip_if_desktop("Not supported in Firefox")
- def test_set_null_orientation(self):
- with self.assertRaisesRegexp(errors.MarionetteException, unknown_orientation.format("null")):
- self.marionette.set_orientation(None)
-
- @skip_if_mobile("Specific test for Firefox")
- def test_unsupported_operation_on_desktop(self):
- with self.assertRaises(errors.UnsupportedOperationException):
- self.marionette.set_orientation("landscape-primary")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py b/testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py
deleted file mode 100644
index aa0e6ab1c3..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py
+++ /dev/null
@@ -1,428 +0,0 @@
-# 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 base64
-import hashlib
-import imghdr
-import struct
-import urllib
-
-from marionette_driver import By
-from marionette_driver.errors import JavascriptException, NoSuchWindowException
-from marionette_harness import (
- MarionetteTestCase,
- skip,
- skip_if_mobile,
- WindowManagerMixin,
-)
-
-
-def inline(doc, mime="text/html;charset=utf-8"):
- return "data:{0},{1}".format(mime, urllib.quote(doc))
-
-
-box = inline("<body><div id='box'><p id='green' style='width: 50px; height: 50px; "
- "background: silver;'></p></div></body>")
-input = inline("<body><input id='text-input'></input></body>")
-long = inline("<body style='height: 300vh'><p style='margin-top: 100vh'>foo</p></body>")
-short = inline("<body style='height: 10vh'></body>")
-svg = inline("""
- <svg xmlns="http://www.w3.org/2000/svg" height="20" width="20">
- <rect height="20" width="20"/>
- </svg>""", mime="image/svg+xml")
-
-
-class ScreenCaptureTestCase(MarionetteTestCase):
-
- def setUp(self):
- super(ScreenCaptureTestCase, self).setUp()
-
- self._device_pixel_ratio = None
-
- @property
- def device_pixel_ratio(self):
- if self._device_pixel_ratio is None:
- self._device_pixel_ratio = self.marionette.execute_script("""
- return window.devicePixelRatio
- """)
- return self._device_pixel_ratio
-
- @property
- def document_element(self):
- return self.marionette.find_element(By.CSS_SELECTOR, ":root")
-
- @property
- def page_y_offset(self):
- return self.marionette.execute_script("return window.pageYOffset")
-
- @property
- def viewport_dimensions(self):
- return self.marionette.execute_script("""
- return [arguments[0].clientWidth,
- arguments[0].clientHeight];
- """, script_args=[self.document_element])
-
- def assert_png(self, screenshot):
- """Test that screenshot is a Base64 encoded PNG file."""
- image = base64.decodestring(screenshot)
- self.assertEqual(imghdr.what("", image), "png")
-
- def assert_formats(self, element=None):
- if element is None:
- element = self.document_element
-
- screenshot_default = self.marionette.screenshot(element=element)
- screenshot_image = self.marionette.screenshot(element=element, format="base64")
- binary1 = self.marionette.screenshot(element=element, format="binary")
- binary2 = self.marionette.screenshot(element=element, format="binary")
- hash1 = self.marionette.screenshot(element=element, format="hash")
- hash2 = self.marionette.screenshot(element=element, format="hash")
-
- # Valid data should have been returned
- self.assert_png(screenshot_image)
- self.assertEqual(imghdr.what("", binary1), "png")
- self.assertEqual(screenshot_image, base64.b64encode(binary1))
- self.assertEqual(hash1, hashlib.sha256(screenshot_image).hexdigest())
-
- # Different formats produce different data
- self.assertNotEqual(screenshot_image, binary1)
- self.assertNotEqual(screenshot_image, hash1)
- self.assertNotEqual(binary1, hash1)
-
- # A second capture should be identical
- self.assertEqual(screenshot_image, screenshot_default)
- self.assertEqual(binary1, binary2)
- self.assertEqual(hash1, hash2)
-
- def get_element_dimensions(self, element):
- rect = element.rect
- return rect["width"], rect["height"]
-
- def get_image_dimensions(self, screenshot):
- self.assert_png(screenshot)
- image = base64.decodestring(screenshot)
- width, height = struct.unpack(">LL", image[16:24])
- return int(width), int(height)
-
- def scale(self, rect):
- return (int(rect[0] * self.device_pixel_ratio),
- int(rect[1] * self.device_pixel_ratio))
-
-
-class TestScreenCaptureChrome(WindowManagerMixin, ScreenCaptureTestCase):
-
- def setUp(self):
- super(TestScreenCaptureChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- def tearDown(self):
- self.close_all_windows()
- super(TestScreenCaptureChrome, self).tearDown()
-
- @property
- def window_dimensions(self):
- return tuple(self.marionette.execute_script("""
- let el = document.documentElement;
- let rect = el.getBoundingClientRect();
- return [rect.width, rect.height];
- """))
-
- def open_dialog(self, url=None, width=None, height=None):
- if url is None:
- url = "chrome://marionette/content/test_dialog.xul"
-
- def opener():
- features = "chrome"
- if height is not None:
- features += ",height={}".format(height)
- if width is not None:
- features += ",width={}".format(width)
-
- self.marionette.execute_script("""
- window.open(arguments[0], "", arguments[1]);
- """, script_args=[url, features])
-
- return self.open_window(opener)
-
- def test_capture_different_context(self):
- """Check that screenshots in content and chrome are different."""
- with self.marionette.using_context("content"):
- screenshot_content = self.marionette.screenshot()
- screenshot_chrome = self.marionette.screenshot()
- self.assertNotEqual(screenshot_content, screenshot_chrome)
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_capture_element(self):
- dialog = self.open_dialog()
- self.marionette.switch_to_window(dialog)
-
- # Ensure we only capture the element
- el = self.marionette.find_element(By.ID, "test-list")
- screenshot_element = self.marionette.screenshot(element=el)
- self.assertEqual(self.scale(self.get_element_dimensions(el)),
- self.get_image_dimensions(screenshot_element))
-
- # Ensure we do not capture the full window
- screenshot_dialog = self.marionette.screenshot()
- self.assertNotEqual(screenshot_dialog, screenshot_element)
-
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_capture_flags(self):
- dialog = self.open_dialog()
- self.marionette.switch_to_window(dialog)
-
- textbox = self.marionette.find_element(By.ID, "text-box")
- textbox.send_keys("")
- screenshot_focus = self.marionette.screenshot()
-
- self.marionette.execute_script("arguments[0].blur();", script_args=[textbox])
- screenshot_no_focus = self.marionette.screenshot()
-
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
-
- self.assertNotEqual(screenshot_focus, screenshot_no_focus)
-
- def test_capture_full_area(self):
- # A full capture is not the outer dimensions of the window,
- # but instead the bounding box of the window's root node (documentElement).
- screenshot_full = self.marionette.screenshot()
- screenshot_root = self.marionette.screenshot(element=self.document_element)
-
- self.assert_png(screenshot_full)
- self.assert_png(screenshot_root)
- self.assertEqual(screenshot_root, screenshot_full)
- self.assertEqual(self.scale(self.get_element_dimensions(self.document_element)),
- self.get_image_dimensions(screenshot_full))
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_capture_viewport(self):
- # Load a HTML test page into the chrome window to get scrollbars
- test_page = self.marionette.absolute_url("test.html")
- dialog = self.open_dialog(url=test_page, width=50, height=50)
- self.marionette.switch_to_window(dialog)
-
- # Size of screenshot has to match viewport size
- screenshot = self.marionette.screenshot(full=False)
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.viewport_dimensions),
- self.get_image_dimensions(screenshot))
- self.assertNotEqual(self.scale(self.window_dimensions),
- self.get_image_dimensions(screenshot))
-
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_capture_window_already_closed(self):
- dialog = self.open_dialog()
- self.marionette.switch_to_window(dialog)
- self.marionette.close_chrome_window()
-
- self.assertRaises(NoSuchWindowException, self.marionette.screenshot)
- self.marionette.switch_to_window(self.start_window)
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_formats(self):
- dialog = self.open_dialog()
- self.marionette.switch_to_window(dialog)
-
- self.assert_formats()
-
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
-
- def test_format_unknown(self):
- with self.assertRaises(ValueError):
- self.marionette.screenshot(format="cheese")
-
- @skip_if_mobile("Fennec doesn't support other chrome windows")
- def test_highlight_elements(self):
- dialog = self.open_dialog()
- self.marionette.switch_to_window(dialog)
-
- # Highlighting the element itself shouldn't make the image larger
- element = self.marionette.find_element(By.ID, "test-list")
- screenshot_element = self.marionette.screenshot(element=element)
- screenshot_highlight = self.marionette.screenshot(element=element,
- highlights=[element])
- self.assertEqual(self.scale(self.get_element_dimensions(element)),
- self.get_image_dimensions(screenshot_element))
- self.assertNotEqual(screenshot_element, screenshot_highlight)
-
- # Highlighting a sub element
- button = self.marionette.find_element(By.ID, "choose-button")
- screenshot_highlight_button = self.marionette.screenshot(element=element,
- highlights=[button])
- self.assertNotEqual(screenshot_element, screenshot_highlight_button)
- self.assertNotEqual(screenshot_highlight, screenshot_highlight_button)
-
- self.marionette.close_chrome_window()
- self.marionette.switch_to_window(self.start_window)
-
- def test_highlight_element_not_seen(self):
- """Check that for not found elements an exception is raised."""
- with self.marionette.using_context('content'):
- self.marionette.navigate(box)
- content_element = self.marionette.find_element(By.ID, "green")
-
- self.assertRaisesRegexp(JavascriptException, "Element reference not seen before",
- self.marionette.screenshot, highlights=[content_element])
-
- chrome_document_element = self.document_element
- with self.marionette.using_context('content'):
- self.assertRaisesRegexp(JavascriptException, "Element reference not seen before",
- self.marionette.screenshot,
- highlights=[chrome_document_element])
-
-
-class TestScreenCaptureContent(WindowManagerMixin, ScreenCaptureTestCase):
-
- def setUp(self):
- super(TestScreenCaptureContent, self).setUp()
- self.marionette.set_context("content")
-
- def tearDown(self):
- self.close_all_tabs()
- super(TestScreenCaptureContent, self).tearDown()
-
- @property
- def scroll_dimensions(self):
- return tuple(self.marionette.execute_script("""
- return [document.body.scrollWidth, document.body.scrollHeight]
- """))
-
- @skip_if_mobile("Needs application independent method to open a new tab")
- def test_capture_tab_already_closed(self):
- tab = self.open_tab()
- self.marionette.switch_to_window(tab)
- self.marionette.close()
-
- self.assertRaises(NoSuchWindowException, self.marionette.screenshot)
- self.marionette.switch_to_window(self.start_tab)
-
- def test_capture_element(self):
- self.marionette.navigate(box)
- el = self.marionette.find_element(By.TAG_NAME, "div")
- screenshot = self.marionette.screenshot(element=el)
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.get_element_dimensions(el)),
- self.get_image_dimensions(screenshot))
-
- @skip("Bug 1213875")
- def test_capture_element_scrolled_into_view(self):
- self.marionette.navigate(long)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- screenshot = self.marionette.screenshot(element=el)
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.get_element_dimensions(el)),
- self.get_image_dimensions(screenshot))
- self.assertGreater(self.page_y_offset, 0)
-
- @skip("Bug 1330560 - AssertionError: u'iVBORw0KGgoA... (images unexpectedly equal)")
- def test_capture_flags(self):
- self.marionette.navigate(input)
-
- textbox = self.marionette.find_element(By.ID, "text-input")
- textbox.send_keys("")
- screenshot_focus = self.marionette.screenshot()
-
- self.marionette.execute_script("arguments[0].blur();", script_args=[textbox])
- screenshot_no_focus = self.marionette.screenshot()
-
- self.assertNotEqual(screenshot_focus, screenshot_no_focus)
-
- @skip_if_mobile("Bug 1330642 - Tuples differ: (1960, 11130) != (1960, 11129)")
- def test_capture_html_document_element(self):
- self.marionette.navigate(long)
- screenshot = self.marionette.screenshot()
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.scroll_dimensions),
- self.get_image_dimensions(screenshot))
-
- def test_capture_svg_document_element(self):
- self.marionette.navigate(svg)
- screenshot = self.marionette.screenshot()
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.get_element_dimensions(self.document_element)),
- self.get_image_dimensions(screenshot))
-
- def test_capture_viewport(self):
- url = self.marionette.absolute_url("clicks.html")
- self.marionette.navigate(short)
- self.marionette.navigate(url)
- screenshot = self.marionette.screenshot(full=False)
- self.assert_png(screenshot)
- self.assertEqual(self.scale(self.viewport_dimensions),
- self.get_image_dimensions(screenshot))
-
- def test_capture_viewport_after_scroll(self):
- self.marionette.navigate(long)
- before = self.marionette.screenshot()
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.marionette.execute_script(
- "arguments[0].scrollIntoView()", script_args=[el])
- after = self.marionette.screenshot(full=False)
- self.assertNotEqual(before, after)
- self.assertGreater(self.page_y_offset, 0)
-
- def test_formats(self):
- self.marionette.navigate(box)
-
- # Use a smaller region to speed up the test
- element = self.marionette.find_element(By.TAG_NAME, "div")
- self.assert_formats(element=element)
-
- def test_format_unknown(self):
- with self.assertRaises(ValueError):
- self.marionette.screenshot(format="cheese")
-
- def test_highlight_elements(self):
- self.marionette.navigate(box)
- element = self.marionette.find_element(By.TAG_NAME, "div")
-
- # Highlighting the element itself shouldn't make the image larger
- screenshot_element = self.marionette.screenshot(element=element)
- screenshot_highlight = self.marionette.screenshot(element=element,
- highlights=[element])
- self.assertEqual(self.scale(self.get_element_dimensions(element)),
- self.get_image_dimensions(screenshot_highlight))
- self.assertNotEqual(screenshot_element, screenshot_highlight)
-
- # Highlighting a sub element
- paragraph = self.marionette.find_element(By.ID, "green")
- screenshot_highlight_paragraph = self.marionette.screenshot(element=element,
- highlights=[paragraph])
- self.assertNotEqual(screenshot_element, screenshot_highlight_paragraph)
- self.assertNotEqual(screenshot_highlight, screenshot_highlight_paragraph)
-
- def test_scroll_default(self):
- self.marionette.navigate(long)
- before = self.page_y_offset
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.marionette.screenshot(element=el, format="hash")
- self.assertNotEqual(before, self.page_y_offset)
-
- def test_scroll(self):
- self.marionette.navigate(long)
- before = self.page_y_offset
- el = self.marionette.find_element(By.TAG_NAME, "p")
- self.marionette.screenshot(element=el, format="hash", scroll=True)
- self.assertNotEqual(before, self.page_y_offset)
-
- def test_scroll_off(self):
- self.marionette.navigate(long)
- el = self.marionette.find_element(By.TAG_NAME, "p")
- before = self.page_y_offset
- self.marionette.screenshot(element=el, format="hash", scroll=False)
- self.assertEqual(before, self.page_y_offset)
-
- def test_scroll_no_element(self):
- self.marionette.navigate(long)
- before = self.page_y_offset
- self.marionette.screenshot(format="hash", scroll=True)
- self.assertEqual(before, self.page_y_offset)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_select.py b/testing/marionette/harness/marionette_harness/tests/unit/test_select.py
deleted file mode 100644
index 3c9522bead..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_select.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# 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 urllib
-
-from marionette_driver.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
-
-
-class SelectTestCase(MarionetteTestCase):
- def assertSelected(self, option_element):
- self.assertTrue(option_element.is_selected(), "<option> element not selected")
- self.assertTrue(self.marionette.execute_script(
- "return arguments[0].selected", script_args=[option_element], sandbox=None),
- "<option> selected attribute not updated")
-
- def assertNotSelected(self, option_element):
- self.assertFalse(option_element.is_selected(), "<option> is selected")
- self.assertFalse(self.marionette.execute_script(
- "return arguments[0].selected", script_args=[option_element], sandbox=None),
- "<option> selected attribute not updated")
-
-
-class TestSelect(SelectTestCase):
- def test_single(self):
- self.marionette.navigate(inline("""
- <select>
- <option>first
- <option>second
- </select>"""))
- select = self.marionette.find_element(By.TAG_NAME, "select")
- options = self.marionette.find_elements(By.TAG_NAME, "option")
-
- self.assertSelected(options[0])
- options[1].click()
- self.assertSelected(options[1])
-
- def test_deselect(self):
- self.marionette.navigate(inline("""
- <select>
- <option>first
- <option>second
- <option>third
- </select>"""))
- select = self.marionette.find_element(By.TAG_NAME, "select")
- options = self.marionette.find_elements(By.TAG_NAME, "option")
-
- options[0].click()
- self.assertSelected(options[0])
- options[1].click()
- self.assertSelected(options[1])
- options[2].click()
- self.assertSelected(options[2])
- options[0].click()
- self.assertSelected(options[0])
-
- def test_out_of_view(self):
- self.marionette.navigate(inline("""
- <select>
- <option>1
- <option>2
- <option>3
- <option>4
- <option>5
- <option>6
- <option>7
- <option>8
- <option>9
- <option>10
- <option>11
- <option>12
- <option>13
- <option>14
- <option>15
- <option>16
- <option>17
- <option>18
- <option>19
- <option>20
- </select>"""))
- select = self.marionette.find_element(By.TAG_NAME, "select")
- options = self.marionette.find_elements(By.TAG_NAME, "option")
-
- options[14].click()
- self.assertSelected(options[14])
-
-
-class TestSelectMultiple(SelectTestCase):
- def test_single(self):
- self.marionette.navigate(inline("<select multiple> <option>first </select>"))
- option = self.marionette.find_element(By.TAG_NAME, "option")
- option.click()
- self.assertSelected(option)
-
- def test_multiple(self):
- self.marionette.navigate(inline("""
- <select multiple>
- <option>first
- <option>second
- <option>third
- </select>"""))
- select = self.marionette.find_element(By.TAG_NAME, "select")
- options = select.find_elements(By.TAG_NAME, "option")
-
- options[1].click()
- self.assertSelected(options[1])
-
- options[2].click()
- self.assertSelected(options[2])
- self.assertSelected(options[1])
-
- def test_deselect_selected(self):
- self.marionette.navigate(inline("<select multiple> <option>first </select>"))
- option = self.marionette.find_element(By.TAG_NAME, "option")
- option.click()
- self.assertSelected(option)
- option.click()
- self.assertNotSelected(option)
-
- def test_deselect_preselected(self):
- self.marionette.navigate(inline("""
- <select multiple>
- <option selected>first
- </select>"""))
- option = self.marionette.find_element(By.TAG_NAME, "option")
- self.assertSelected(option)
- option.click()
- self.assertNotSelected(option)
-
- def test_out_of_view(self):
- self.marionette.navigate(inline("""
- <select multiple>
- <option>1
- <option>2
- <option>3
- <option>4
- <option>5
- <option>6
- <option>7
- <option>8
- <option>9
- <option>10
- <option>11
- <option>12
- <option>13
- <option>14
- <option>15
- <option>16
- <option>17
- <option>18
- <option>19
- <option>20
- </select>"""))
- select = self.marionette.find_element(By.TAG_NAME, "select")
- options = self.marionette.find_elements(By.TAG_NAME, "option")
-
- options[-1].click()
- self.assertSelected(options[-1])
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_session.py b/testing/marionette/harness/marionette_harness/tests/unit/test_session.py
deleted file mode 100644
index 1676df51fa..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_session.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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 errors
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestSession(MarionetteTestCase):
- def setUp(self):
- super(TestSession, self).setUp()
- self.marionette.delete_session()
-
- def test_new_session_returns_capabilities(self):
- # Sends newSession
- caps = self.marionette.start_session()
-
- # Check that session was created. This implies the server
- # sent us the sessionId and status fields.
- self.assertIsNotNone(self.marionette.session)
-
- # Required capabilities mandated by WebDriver spec
- self.assertIn("browserName", caps)
- self.assertIn("browserVersion", caps)
- self.assertIn("platformName", caps)
- self.assertIn("platformVersion", caps)
-
- # Optional capabilities we want Marionette to support
- self.assertIn("rotatable", caps)
-
- def test_get_session_id(self):
- # Sends newSession
- self.marionette.start_session()
-
- self.assertTrue(self.marionette.session_id is not None)
- self.assertTrue(isinstance(self.marionette.session_id, unicode))
-
- def test_set_the_session_id(self):
- # Sends newSession
- self.marionette.start_session(session_id="ILoveCheese")
-
- self.assertEqual(self.marionette.session_id, "ILoveCheese")
- self.assertTrue(isinstance(self.marionette.session_id, unicode))
-
- def test_session_already_started(self):
- self.marionette.start_session()
- self.assertTrue(isinstance(self.marionette.session_id, unicode))
- with self.assertRaises(errors.SessionNotCreatedException):
- self.marionette._send_message("newSession", {})
-
- def test_no_session(self):
- with self.assertRaises(errors.InvalidSessionIdException):
- self.marionette.get_url()
- self.marionette.start_session()
- self.marionette.get_url()
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_set_window_size.py b/testing/marionette/harness/marionette_harness/tests/unit/test_set_window_size.py
deleted file mode 100644
index e1bd5e6849..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_set_window_size.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestSetWindowSize(MarionetteTestCase):
- def setUp(self):
- super(MarionetteTestCase, self).setUp()
- self.start_size = self.marionette.window_size
- self.max_width = self.marionette.execute_script("return window.screen.availWidth;")
- self.max_height = self.marionette.execute_script("return window.screen.availHeight;")
-
- def tearDown(self):
- # WebDriver spec says a resize cannot result in window being maximized, an
- # error is returned if that is the case; therefore if the window is maximized
- # at the start of this test, returning to the original size via set_window_size
- # size will result in error; so reset to original size minus 1 pixel width
- if self.start_size['width'] == self.max_width and self.start_size['height'] == self.max_height:
- self.start_size['width']-=1
- self.marionette.set_window_size(self.start_size['width'], self.start_size['height'])
- super(MarionetteTestCase, self).tearDown()
-
- def test_that_we_can_get_and_set_window_size(self):
- # event handler
- self.marionette.execute_script("""
- window.wrappedJSObject.rcvd_event = false;
- window.onresize = function() {
- window.wrappedJSObject.rcvd_event = true;
- };
- """)
-
- # valid size
- width = self.max_width - 100
- height = self.max_height - 100
- self.marionette.set_window_size(width, height)
- self.wait_for_condition(lambda m: m.execute_script("return window.wrappedJSObject.rcvd_event;"))
- size = self.marionette.window_size
- self.assertEqual(size['width'], width,
- "Window width is {0} but should be {1}".format(size['width'], width))
- self.assertEqual(size['height'], height,
- "Window height is {0} but should be {1}".format(size['height'], height))
-
- def test_that_we_can_get_new_size_when_set_window_size(self):
- actual = self.marionette.window_size
- width = actual['width'] - 50
- height = actual['height'] - 50
- size = self.marionette.set_window_size(width, height)
- self.assertIsNotNone(size, "Response is None")
- self.assertEqual(size['width'], width,
- "New width is {0} but should be {1}".format(size['width'], width))
- self.assertEqual(size['height'], height,
- "New height is {0} but should be {1}".format(size['height'], height))
-
- def test_possible_to_request_window_larger_than_screen(self):
- self.marionette.set_window_size(4 * self.max_width, 4 * self.max_height)
- size = self.marionette.window_size
-
- # In X the window size may be greater than the bounds of the screen
- self.assertGreaterEqual(size["width"], self.max_width)
- self.assertGreaterEqual(size["height"], self.max_height)
-
- def test_that_we_can_maximise_the_window(self):
- # valid size
- width = self.max_width - 100
- height = self.max_height - 100
- self.marionette.set_window_size(width, height)
-
- # event handler
- self.marionette.execute_script("""
- window.wrappedJSObject.rcvd_event = false;
- window.onresize = function() {
- window.wrappedJSObject.rcvd_event = true;
- };
- """)
- self.marionette.maximize_window()
- self.wait_for_condition(lambda m: m.execute_script("return window.wrappedJSObject.rcvd_event;"))
-
- size = self.marionette.window_size
- self.assertGreaterEqual(size['width'], self.max_width,
- "Window width does not use availWidth, current width: {0}, max width: {1}".format(size['width'], self.max_width))
- self.assertGreaterEqual(size['height'], self.max_height,
- "Window height does not use availHeight. current width: {0}, max width: {1}".format(size['height'], self.max_height))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_shadow_dom.py b/testing/marionette/harness/marionette_harness/tests/unit/test_shadow_dom.py
deleted file mode 100644
index 3f91d7cc0c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_shadow_dom.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import (
- NoSuchElementException,
- StaleElementException,
- UnsupportedOperationException,
-)
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestShadowDom(MarionetteTestCase):
-
- def setUp(self):
- super(TestShadowDom, self).setUp()
- self.marionette.set_pref("dom.webcomponents.enabled", True)
- self.marionette.navigate(self.marionette.absolute_url("test_shadow_dom.html"))
-
- self.host = self.marionette.find_element(By.ID, "host")
- self.marionette.switch_to_shadow_root(self.host)
- self.button = self.marionette.find_element(By.ID, "button")
-
- def tearDown(self):
- self.marionette.clear_pref("dom.webcomponents.enabled")
- super(TestShadowDom, self).tearDown()
-
- def test_chrome_error(self):
- with self.marionette.using_context("chrome"):
- self.assertRaises(UnsupportedOperationException,
- self.marionette.switch_to_shadow_root)
-
- def test_shadow_dom(self):
- # Button in shadow root should be actionable
- self.button.click()
-
- def test_shadow_dom_after_switch_away_from_shadow_root(self):
- # Button in shadow root should be actionable
- self.button.click()
- self.marionette.switch_to_shadow_root()
- # After switching back to top content, button should be stale
- self.assertRaises(StaleElementException, self.button.click)
-
- def test_shadow_dom_raises_stale_element_exception_when_button_remove(self):
- self.marionette.execute_script(
- 'document.getElementById("host").shadowRoot.getElementById("button").remove();')
- # After removing button from shadow DOM, button should be stale
- self.assertRaises(StaleElementException, self.button.click)
-
- def test_shadow_dom_raises_stale_element_exception_when_host_removed(self):
- self.marionette.execute_script('document.getElementById("host").remove();')
- # After removing shadow DOM host element, button should be stale
- self.assertRaises(StaleElementException, self.button.click)
-
- def test_non_existent_shadow_dom(self):
- # Jump back to top level content
- self.marionette.switch_to_shadow_root()
- # When no ShadowRoot is found, switch_to_shadow_root throws NoSuchElementException
- self.assertRaises(NoSuchElementException, self.marionette.switch_to_shadow_root,
- self.marionette.find_element(By.ID, "empty-host"))
-
- def test_inner_shadow_dom(self):
- # Button in shadow root should be actionable
- self.button.click()
- self.inner_host = self.marionette.find_element(By.ID, "inner-host")
- self.marionette.switch_to_shadow_root(self.inner_host)
- self.inner_button = self.marionette.find_element(By.ID, "inner-button")
- # Nested nutton in nested shadow root should be actionable
- self.inner_button.click()
- self.marionette.switch_to_shadow_root()
- # After jumping back to parent shadow root, button should again be actionable but inner
- # button should now be stale
- self.button.click()
- self.assertRaises(StaleElementException, self.inner_button.click)
- self.marionette.switch_to_shadow_root()
- # After switching back to top content, both buttons should now be stale
- self.assertRaises(StaleElementException, self.button.click)
- self.assertRaises(StaleElementException, self.inner_button.click)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js b/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js
deleted file mode 100644
index d5edffa67a..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-MARIONETTE_CONTEXT = 'chrome';
-
-is(2, 2, "test for is()");
-isnot(2, 3, "test for isnot()");
-ok(2 == 2, "test for ok()");
-finish();
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js b/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js
deleted file mode 100644
index 16d9aea592..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/* 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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-
-/* this test will fail */
-
-setTimeout(function() {
- is(1, 2, "is(1,2) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS);
- finish();
-}, 100);
-isnot(1, 1, "isnot(1,1) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS);
-ok(1 == 2, "ok(1==2) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS);
-
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js b/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js
deleted file mode 100644
index 93ee676191..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-
-is(2, 2, "test for is()");
-isnot(2, 3, "test for isnot()");
-ok(2 == 2, "test for ok()");
-
-setTimeout(finish, 100);
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py b/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py
deleted file mode 100644
index 8f97285614..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class SimpletestSanityTest(MarionetteTestCase):
- callFinish = "return finish();"
-
- def run_sync(self, test):
- return self.marionette.execute_js_script(test, async=False)
-
- def run_async(self, test):
- return self.marionette.execute_js_script(test)
-
- def test_is(self):
- def runtests():
- sentFail1 = "is(true, false, 'isTest1', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentFail2 = "is(true, false, 'isTest2', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentPass1 = "is(true, true, 'isTest3');" + self.callFinish
- sentPass2 = "is(true, true, 'isTest4');" + self.callFinish
-
- self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]))
- self.assertEqual(0, self.run_sync(sentFail2)["passed"])
- self.assertEqual(1, self.run_sync(sentPass1)["passed"])
- self.assertEqual(0, len(self.run_sync(sentPass2)["failures"]))
-
- self.marionette.timeout.script = 1
- self.assertEqual(1, len(self.run_async(sentFail1)["failures"]))
- self.assertEqual(0, self.run_async(sentFail2)["passed"])
- self.assertEqual(1, self.run_async(sentPass1)["passed"])
- self.assertEqual(0, len(self.run_async(sentPass2)["failures"]))
-
- self.marionette.set_context("content")
- runtests()
- self.marionette.set_context("chrome")
- runtests()
-
- def test_isnot(self):
- def runtests():
- sentFail1 = "isnot(true, true, 'isnotTest3', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentFail2 = "isnot(true, true, 'isnotTest4', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentPass1 = "isnot(true, false, 'isnotTest1');" + self.callFinish
- sentPass2 = "isnot(true, false, 'isnotTest2');" + self.callFinish
-
- self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]));
- self.assertEqual(0, self.run_sync(sentFail2)["passed"]);
- self.assertEqual(0, len(self.run_sync(sentPass1)["failures"]));
- self.assertEqual(1, self.run_sync(sentPass2)["passed"]);
-
- self.marionette.timeout.script = 1
- self.assertEqual(1, len(self.run_async(sentFail1)["failures"]));
- self.assertEqual(0, self.run_async(sentFail2)["passed"]);
- self.assertEqual(0, len(self.run_async(sentPass1)["failures"]));
- self.assertEqual(1, self.run_async(sentPass2)["passed"]);
-
- self.marionette.set_context("content")
- runtests()
- self.marionette.set_context("chrome")
- runtests()
-
- def test_ok(self):
- def runtests():
- sentFail1 = "ok(1==2, 'testOk1', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentFail2 = "ok(1==2, 'testOk2', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
- sentPass1 = "ok(1==1, 'testOk3');" + self.callFinish
- sentPass2 = "ok(1==1, 'testOk4');" + self.callFinish
-
- self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]));
- self.assertEqual(0, self.run_sync(sentFail2)["passed"]);
- self.assertEqual(0, len(self.run_sync(sentPass1)["failures"]));
- self.assertEqual(1, self.run_sync(sentPass2)["passed"]);
-
- self.marionette.timeout.script = 1
- self.assertEqual(1, len(self.run_async(sentFail1)["failures"]));
- self.assertEqual(0, self.run_async(sentFail2)["passed"]);
- self.assertEqual(0, len(self.run_async(sentPass1)["failures"]));
- self.assertEqual(1, self.run_async(sentPass2)["passed"]);
-
- self.marionette.set_context("content")
- runtests()
- self.marionette.set_context("chrome")
- runtests()
-
- def test_todo(self):
- def runtests():
- sentFail1 = "todo(1==1, 'testTodo1', TEST_UNEXPECTED_PASS, TEST_KNOWN_FAIL);" + self.callFinish
- sentFail2 = "todo(1==1, 'testTodo2', TEST_UNEXPECTED_PASS, TEST_KNOWN_FAIL);" + self.callFinish
- sentPass1 = "todo(1==2, 'testTodo3');" + self.callFinish
- sentPass2 = "todo(1==2, 'testTodo4');" + self.callFinish
-
- self.assertEqual(1, len(self.run_sync(sentFail1)["unexpectedSuccesses"]));
- self.assertEqual(0, len(self.run_sync(sentFail2)["expectedFailures"]));
- self.assertEqual(0, len(self.run_sync(sentPass1)["unexpectedSuccesses"]));
- self.assertEqual(1, len(self.run_sync(sentPass2)["expectedFailures"]));
-
- self.marionette.timeout.script = 1
- self.assertEqual(1, len(self.run_async(sentFail1)["unexpectedSuccesses"]));
- self.assertEqual(0, len(self.run_async(sentFail2)["expectedFailures"]));
- self.assertEqual(0, len(self.run_async(sentPass1)["unexpectedSuccesses"]));
- self.assertEqual(1, len(self.run_async(sentPass2)["expectedFailures"]));
-
- self.marionette.set_context("content")
- runtests()
- self.marionette.set_context("chrome")
- runtests()
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js b/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js
deleted file mode 100644
index 9792a936a3..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/* 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/. */
-
-MARIONETTE_TIMEOUT = 100;
-
-/* this test will timeout */
-
-function do_test() {
- is(1, 1);
- isnot(1, 2);
- ok(1 == 1);
- finish();
-}
-
-setTimeout(do_test, 1000);
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_single_finger_desktop.py b/testing/marionette/harness/marionette_harness/tests/unit/test_single_finger_desktop.py
deleted file mode 100644
index 8ac80c3c54..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_single_finger_desktop.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# 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
-import sys
-
-from marionette_driver.errors import MarionetteException
-from marionette_driver import Actions, By
-
-from marionette_harness import MarionetteTestCase, skip
-
-# add this directory to the path
-sys.path.append(os.path.dirname(__file__))
-
-from single_finger_functions import (
- chain, chain_flick, context_menu, double_tap,
- long_press_action, long_press_on_xy_action,
- move_element, move_element_offset, press_release, single_tap, wait,
- wait_with_value
-)
-
-
-class testSingleFingerMouse(MarionetteTestCase):
- def setUp(self):
- super(MarionetteTestCase, self).setUp()
- # set context menu related preferences needed for some tests
- self.marionette.set_context("chrome")
- self.enabled = self.marionette.execute_script("""
-let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-let value = false;
-try {
- value = prefs.getBoolPref("ui.click_hold_context_menus");
-}
-catch (e) {}
-prefs.setBoolPref("ui.click_hold_context_menus", true);
-return value;
-""")
- self.wait_time = self.marionette.execute_script("""
-let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-let value = 750;
-try {
- value = prefs.getIntPref("ui.click_hold_context_menus.delay");
-}
-catch (e) {}
-prefs.setIntPref("ui.click_hold_context_menus.delay", value);
-return value;
-""")
- self.marionette.set_context("content")
-
- def tearDown(self):
- self.marionette.set_context("chrome")
- self.marionette.execute_script(
- """
-let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-prefs.setBoolPref("ui.click_hold_context_menus", arguments[0]);
-""", [self.enabled])
- self.marionette.execute_script(
- """
-let prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
-prefs.setIntPref("ui.click_hold_context_menus.delay", arguments[0]);
-""", [self.wait_time])
- self.marionette.set_context("content")
- super(MarionetteTestCase, self).tearDown()
-
- def test_press_release(self):
- press_release(self.marionette, 1, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click")
-
- def test_press_release_twice(self):
- press_release(self.marionette, 2, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click-mousemove-mousedown-mouseup-click")
-
- def test_move_element(self):
- move_element(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown", "button2-mousemove-mouseup")
-
- def test_move_by_offset(self):
- move_element_offset(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown", "button2-mousemove-mouseup")
-
- def test_wait(self):
- wait(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click")
-
- def test_wait_with_value(self):
- wait_with_value(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click")
-
- @skip("Bug 1191066")
- def test_context_menu(self):
- context_menu(self.marionette, self.wait_for_condition,
- "button1-mousemove-mousedown-contextmenu",
- "button1-mousemove-mousedown-contextmenu-mouseup-click")
-
- @skip("Bug 1191066")
- def test_long_press_action(self):
- long_press_action(self.marionette, self.wait_for_condition,
- "button1-mousemove-mousedown-contextmenu-mouseup-click")
-
- @skip("Bug 1191066")
- def test_long_press_on_xy_action(self):
- long_press_on_xy_action(self.marionette, self.wait_for_condition,
- "button1-mousemove-mousedown-contextmenu-mouseup-click")
-
- @skip("Bug 865334")
- def test_long_press_fail(self):
- testAction = self.marionette.absolute_url("testAction.html")
- self.marionette.navigate(testAction)
- button = self.marionette.find_element(By.ID, "button1Copy")
- action = Actions(self.marionette)
- action.press(button).long_press(button, 5)
- self.assertRaises(MarionetteException, action.perform)
-
- def test_chain(self):
- chain(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown", "delayed-mousemove-mouseup")
-
- def test_chain_flick(self):
- chain_flick(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown-mousemove", "buttonFlick-mousemove-mouseup")
-
- def test_single_tap(self):
- single_tap(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click")
-
- def test_double_tap(self):
- double_tap(self.marionette, self.wait_for_condition, "button1-mousemove-mousedown-mouseup-click-mousemove-mousedown-mouseup-click")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_skip_setup.py b/testing/marionette/harness/marionette_harness/tests/unit/test_skip_setup.py
deleted file mode 100644
index 9a0432fb7d..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_skip_setup.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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_harness import MarionetteTestCase, SkipTest
-
-
-class TestSetUpSkipped(MarionetteTestCase):
-
- testVar = {'test':'SkipTest'}
-
- def setUp(self):
- try:
- self.testVar['email']
- except KeyError:
- raise SkipTest('email key not present in dict, skip ...')
- MarionetteTestCase.setUp(self)
-
- def test_assert(self):
- assert True
-
-class TestSetUpNotSkipped(MarionetteTestCase):
-
- testVar = {'test':'SkipTest'}
-
- def setUp(self):
- try:
- self.testVar['test']
- except KeyError:
- raise SkipTest('email key not present in dict, skip ...')
- MarionetteTestCase.setUp(self)
-
- def test_assert(self):
- assert True
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py
deleted file mode 100644
index 18eb34169a..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import (
- JavascriptException,
- NoSuchFrameException,
-)
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestSwitchFrame(MarionetteTestCase):
- def test_switch_simple(self):
- start_url = "test_iframe.html"
- verify_title = "Marionette IFrame Test"
- test_html = self.marionette.absolute_url(start_url)
- self.marionette.navigate(test_html)
- self.assertEqual(self.marionette.get_active_frame(), None)
- frame = self.marionette.find_element(By.ID, "test_iframe")
- self.marionette.switch_to_frame(frame)
- self.assertTrue(start_url in self.marionette.get_url())
- inner_frame_element = self.marionette.get_active_frame()
- # test that we can switch back to main frame, then switch back to the
- # inner frame with the value we got from get_active_frame
- self.marionette.switch_to_frame()
- self.assertEqual(verify_title, self.marionette.title)
- self.marionette.switch_to_frame(inner_frame_element)
- self.assertTrue(start_url in self.marionette.get_url())
-
- def test_switch_nested(self):
- start_url = "test_nested_iframe.html"
- verify_title = "Marionette IFrame Test"
- test_html = self.marionette.absolute_url(start_url)
- self.marionette.navigate(test_html)
- frame = self.marionette.find_element(By.ID, "test_iframe")
- self.assertEqual(self.marionette.get_active_frame(), None)
- self.marionette.switch_to_frame(frame)
- self.assertTrue(start_url in self.marionette.get_url())
- inner_frame_element = self.marionette.get_active_frame()
- # test that we can switch back to main frame, then switch back to the
- # inner frame with the value we got from get_active_frame
- self.marionette.switch_to_frame()
- self.assertEqual(verify_title, self.marionette.title)
- self.marionette.switch_to_frame(inner_frame_element)
- self.assertTrue(start_url in self.marionette.get_url())
- inner_frame = self.marionette.find_element(By.ID, 'inner_frame')
- self.marionette.switch_to_frame(inner_frame)
- self.assertTrue(start_url in self.marionette.get_url())
- self.marionette.switch_to_frame() # go back to main frame
- self.assertTrue(start_url in self.marionette.get_url())
- #test that we're using the right window object server-side
- self.assertTrue("test_nested_iframe.html" in self.marionette.execute_script("return window.location.href;"))
-
- def test_stack_trace(self):
- start_url = "test_iframe.html"
- verify_title = "Marionette IFrame Test"
- test_html = self.marionette.absolute_url(start_url)
- self.marionette.navigate(test_html)
- frame = self.marionette.find_element(By.ID, "test_iframe")
- self.assertEqual(self.marionette.get_active_frame(), None)
- self.marionette.switch_to_frame(frame)
- self.assertTrue(start_url in self.marionette.get_url())
- inner_frame_element = self.marionette.get_active_frame()
- # test that we can switch back to main frame, then switch back to the
- # inner frame with the value we got from get_active_frame
- self.marionette.switch_to_frame()
- self.assertEqual(verify_title, self.marionette.title)
- self.marionette.switch_to_frame(inner_frame_element)
- self.assertTrue(start_url in self.marionette.get_url())
-
- try:
- self.marionette.execute_async_script("foo();")
- except JavascriptException as e:
- self.assertTrue("foo" in e.message)
-
- def test_should_be_able_to_carry_on_working_if_the_frame_is_deleted_from_under_us(self):
- test_html = self.marionette.absolute_url("deletingFrame.html")
- self.marionette.navigate(test_html)
-
- self.marionette.switch_to_frame(self.marionette.find_element(By.ID,
- 'iframe1'))
- killIframe = self.marionette.find_element(By.ID, "killIframe")
- killIframe.click()
- self.marionette.switch_to_frame()
-
- self.assertEqual(0, len(self.marionette.find_elements(By.ID, "iframe1")))
-
- addIFrame = self.marionette.find_element(By.ID, "addBackFrame")
- addIFrame.click()
- self.marionette.find_element(By.ID, "iframe1")
-
- self.marionette.switch_to_frame(self.marionette.find_element(By.ID,
- "iframe1"))
-
- self.marionette.find_element(By.ID, "checkbox")
-
- def test_should_allow_a_user_to_switch_from_an_iframe_back_to_the_main_content_of_the_page(self):
- test_iframe = self.marionette.absolute_url("test_iframe.html")
- self.marionette.navigate(test_iframe)
- self.marionette.switch_to_frame(0)
- self.marionette.switch_to_default_content()
- header = self.marionette.find_element(By.ID, "iframe_page_heading")
- self.assertEqual(header.text, "This is the heading")
-
- def test_should_be_able_to_switch_to_a_frame_by_its_index(self):
- test_html = self.marionette.absolute_url("frameset.html")
- self.marionette.navigate(test_html)
- self.marionette.switch_to_frame(2)
- element = self.marionette.find_element(By.ID, "email")
- self.assertEquals("email", element.get_attribute("type"))
-
- def test_should_be_able_to_switch_to_a_frame_using_a_previously_located_element(self):
- test_html = self.marionette.absolute_url("frameset.html")
- self.marionette.navigate(test_html)
- frame = self.marionette.find_element(By.NAME, "third")
- self.marionette.switch_to_frame(frame)
-
- element = self.marionette.find_element(By.ID, "email")
- self.assertEquals("email", element.get_attribute("type"))
-
- def test_switch_to_frame_with_out_of_bounds_index(self):
- self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
- count = self.marionette.execute_script("return window.frames.length;")
- self.assertRaises(NoSuchFrameException, self.marionette.switch_to_frame, count)
-
- def test_switch_to_frame_with_negative_index(self):
- self.marionette.navigate(self.marionette.absolute_url("test_iframe.html"))
- self.assertRaises(NoSuchFrameException, self.marionette.switch_to_frame, -1)
-
- def test_switch_to_parent_frame(self):
- frame_html = self.marionette.absolute_url("frameset.html")
- self.marionette.navigate(frame_html)
- frame = self.marionette.find_element(By.NAME, "third")
- self.marionette.switch_to_frame(frame)
-
- # If we don't find the following element we aren't on the right page
- self.marionette.find_element(By.ID, "checky")
- form_page_title = self.marionette.execute_script("return document.title")
- self.assertEqual("We Leave From Here", form_page_title)
-
- self.marionette.switch_to_parent_frame()
-
- current_page_title = self.marionette.execute_script("return document.title")
- self.assertEqual("Unique title", current_page_title)
-
- def test_switch_to_parent_frame_from_default_context_is_a_noop(self):
- formpage = self.marionette.absolute_url("formPage.html")
- self.marionette.navigate(formpage)
-
- self.marionette.switch_to_parent_frame()
-
- form_page_title = self.marionette.execute_script("return document.title")
- self.assertEqual("We Leave From Here", form_page_title)
-
- def test_should_be_able_to_switch_to_parent_from_second_level(self):
- frame_html = self.marionette.absolute_url("frameset.html")
- self.marionette.navigate(frame_html)
- frame = self.marionette.find_element(By.NAME, "fourth")
- self.marionette.switch_to_frame(frame)
-
- second_level = self.marionette.find_element(By.NAME, "child1")
- self.marionette.switch_to_frame(second_level)
- self.marionette.find_element(By.NAME, "myCheckBox")
-
- self.marionette.switch_to_parent_frame()
-
- second_level = self.marionette.find_element(By.NAME, "child1")
-
- def test_should_be_able_to_switch_to_parent_from_iframe(self):
- frame_html = self.marionette.absolute_url("test_iframe.html")
- self.marionette.navigate(frame_html)
- frame = self.marionette.find_element(By.ID, "test_iframe")
- self.marionette.switch_to_frame(frame)
-
- current_page_title = self.marionette.execute_script("return document.title")
- self.assertEqual("Marionette Test", current_page_title)
-
- self.marionette.switch_to_parent_frame()
-
- parent_page_title = self.marionette.execute_script("return document.title")
- self.assertEqual("Marionette IFrame Test", parent_page_title)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame_chrome.py
deleted file mode 100644
index 03c13026e5..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_frame_chrome.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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 JavascriptException
-
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestSwitchFrameChrome(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSwitchFrameChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(new_window)
- self.assertNotEqual(self.start_window, self.marionette.current_chrome_window_handle)
-
- def tearDown(self):
- self.close_all_windows()
- super(TestSwitchFrameChrome, self).tearDown()
-
- def test_switch_simple(self):
- self.assertIn("test.xul", self.marionette.get_url(), "Initial navigation has failed")
- self.marionette.switch_to_frame(0)
- self.assertIn("test2.xul", self.marionette.get_url(),"Switching by index failed")
- self.marionette.switch_to_frame()
- self.assertEqual(None, self.marionette.get_active_frame(), "Switiching by null failed")
- self.assertIn("test.xul", self.marionette.get_url(), "Switching by null failed")
- self.marionette.switch_to_frame("iframe")
- self.assertIn("test2.xul", self.marionette.get_url(), "Switching by name failed")
- self.marionette.switch_to_frame()
- self.assertIn("test.xul", self.marionette.get_url(), "Switching by null failed")
- self.marionette.switch_to_frame("iframename")
- self.assertIn("test2.xul", self.marionette.get_url(), "Switching by name failed")
- iframe_element = self.marionette.get_active_frame()
- self.marionette.switch_to_frame()
- self.assertIn("test.xul", self.marionette.get_url(), "Switching by null failed")
- self.marionette.switch_to_frame(iframe_element)
- self.assertIn("test2.xul", self.marionette.get_url(), "Switching by element failed")
-
- def test_stack_trace(self):
- self.assertIn("test.xul", self.marionette.get_url(), "Initial navigation has failed")
- self.marionette.switch_to_frame(0)
- self.assertRaises(JavascriptException, self.marionette.execute_async_script, "foo();")
- try:
- self.marionette.execute_async_script("foo();")
- except JavascriptException as e:
- self.assertIn("foo", e.message)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_remote_frame.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_remote_frame.py
deleted file mode 100644
index 07ddeef2a4..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_remote_frame.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-OOP_BY_DEFAULT = "dom.ipc.browser_frames.oop_by_default"
-BROWSER_FRAMES_ENABLED = "dom.mozBrowserFramesEnabled"
-
-
-class TestSwitchRemoteFrame(MarionetteTestCase):
- def setUp(self):
- super(TestSwitchRemoteFrame, self).setUp()
- with self.marionette.using_context('chrome'):
- self.oop_by_default = self.marionette.get_pref(OOP_BY_DEFAULT)
- self.mozBrowserFramesEnabled = self.marionette.get_pref(BROWSER_FRAMES_ENABLED)
- self.marionette.set_pref(OOP_BY_DEFAULT, True)
- self.marionette.set_pref(BROWSER_FRAMES_ENABLED, True)
-
- self.multi_process_browser = self.marionette.execute_script("""
- try {
- return Services.appinfo.browserTabsRemoteAutostart;
- } catch (e) {
- return false;
- }""")
-
- def tearDown(self):
- with self.marionette.using_context("chrome"):
- if self.oop_by_default is None:
- self.marionette.clear_pref(OOP_BY_DEFAULT)
- else:
- self.marionette.set_pref(OOP_BY_DEFAULT, self.oop_by_default)
-
- if self.mozBrowserFramesEnabled is None:
- self.marionette.clear_pref(BROWSER_FRAMES_ENABLED)
- else:
- self.marionette.set_pref(BROWSER_FRAMES_ENABLED, self.mozBrowserFramesEnabled)
-
- @property
- def is_main_process(self):
- return self.marionette.execute_script("""
- return Components.classes["@mozilla.org/xre/app-info;1"].
- getService(Components.interfaces.nsIXULRuntime).
- processType == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
- """, sandbox="system")
-
- def test_remote_frame(self):
- self.marionette.navigate(self.marionette.absolute_url("test.html"))
- self.marionette.push_permission('browser', True)
- self.marionette.execute_script("""
- let iframe = document.createElement("iframe");
- iframe.setAttribute('mozbrowser', true);
- iframe.setAttribute('remote', true);
- iframe.id = "remote_iframe";
- iframe.style.height = "100px";
- iframe.style.width = "100%%";
- iframe.src = "{}";
- document.body.appendChild(iframe);
- """.format(self.marionette.absolute_url("test.html")))
- remote_iframe = self.marionette.find_element(By.ID, "remote_iframe")
- self.marionette.switch_to_frame(remote_iframe)
- main_process = self.is_main_process
- self.assertFalse(main_process)
-
- def test_remote_frame_revisit(self):
- # test if we can revisit a remote frame (this takes a different codepath)
- self.marionette.navigate(self.marionette.absolute_url("test.html"))
- self.marionette.push_permission('browser', True)
- self.marionette.execute_script("""
- let iframe = document.createElement("iframe");
- iframe.setAttribute('mozbrowser', true);
- iframe.setAttribute('remote', true);
- iframe.id = "remote_iframe";
- iframe.style.height = "100px";
- iframe.style.width = "100%%";
- iframe.src = "{}";
- document.body.appendChild(iframe);
- """.format(self.marionette.absolute_url("test.html")))
- self.marionette.switch_to_frame(self.marionette.find_element(By.ID,
- "remote_iframe"))
- main_process = self.is_main_process
- self.assertFalse(main_process)
- self.marionette.switch_to_frame()
- main_process = self.is_main_process
- should_be_main_process = not self.multi_process_browser
- self.assertEqual(main_process, should_be_main_process)
- self.marionette.switch_to_frame(self.marionette.find_element(By.ID,
- "remote_iframe"))
- main_process = self.is_main_process
- self.assertFalse(main_process)
-
- def test_we_can_switch_to_a_remote_frame_by_index(self):
- # test if we can revisit a remote frame (this takes a different codepath)
- self.marionette.navigate(self.marionette.absolute_url("test.html"))
- self.marionette.push_permission('browser', True)
- self.marionette.execute_script("""
- let iframe = document.createElement("iframe");
- iframe.setAttribute('mozbrowser', true);
- iframe.setAttribute('remote', true);
- iframe.id = "remote_iframe";
- iframe.style.height = "100px";
- iframe.style.width = "100%%";
- iframe.src = "{}";
- document.body.appendChild(iframe);
- """.format(self.marionette.absolute_url("test.html")))
- self.marionette.switch_to_frame(0)
- main_process = self.is_main_process
- self.assertFalse(main_process)
- self.marionette.switch_to_frame()
- main_process = self.is_main_process
- should_be_main_process = not self.multi_process_browser
- self.assertEqual(main_process, should_be_main_process)
- self.marionette.switch_to_frame(0)
- main_process = self.is_main_process
- self.assertFalse(main_process)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_chrome.py
deleted file mode 100644
index 0ad63b6ce0..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_chrome.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# 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
-import sys
-from unittest import skipIf
-
-from marionette_driver import By
-
-# add this directory to the path
-sys.path.append(os.path.dirname(__file__))
-
-from test_switch_window_content import TestSwitchToWindowContent
-
-
-class TestSwitchWindowChrome(TestSwitchToWindowContent):
-
- def setUp(self):
- super(TestSwitchWindowChrome, self).setUp()
-
- self.marionette.set_context("chrome")
-
- def tearDown(self):
- self.close_all_windows()
-
- super(TestSwitchWindowChrome, self).tearDown()
-
- def open_window_in_background(self):
- with self.marionette.using_context("chrome"):
- self.marionette.execute_script("""
- window.open("about:blank", null, "location=1,toolbar=1");
- window.focus();
- """)
-
- def open_window_in_foreground(self):
- with self.marionette.using_context("content"):
- self.marionette.navigate(self.test_page)
- link = self.marionette.find_element(By.ID, "new-window")
- link.click()
-
- @skipIf(sys.platform.startswith("linux"),
- "Bug 1335457 - Fails to open a background window on Linux")
- def test_switch_tabs_for_new_background_window_without_focus_change(self):
- # Bug 1334981 - with testmode enabled getMostRecentWindow detects the wrong window
- with self.marionette.using_prefs({"focusmanager.testmode": False}):
- # Open an addition tab in the original window so we can better check
- # the selected index in thew new window to be opened.
- second_tab = self.open_tab(trigger=self.open_tab_in_foreground)
- self.marionette.switch_to_window(second_tab, focus=True)
- second_tab_index = self.get_selected_tab_index()
- self.assertNotEqual(second_tab_index, self.selected_tab_index)
-
- # Opens a new background window, but we are interested in the tab
- tab_in_new_window = self.open_tab(trigger=self.open_window_in_background)
- self.assertEqual(self.marionette.current_window_handle, second_tab)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.empty_page)
-
- # Switch to the tab in the new window but don't focus it
- self.marionette.switch_to_window(tab_in_new_window, focus=False)
- self.assertEqual(self.marionette.current_window_handle, tab_in_new_window)
- self.assertNotEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), "about:blank")
-
- def test_switch_tabs_for_new_foreground_window_with_focus_change(self):
- # Open an addition tab in the original window so we can better check
- # the selected index in thew new window to be opened.
- second_tab = self.open_tab(trigger=self.open_tab_in_foreground)
- self.marionette.switch_to_window(second_tab, focus=True)
- second_tab_index = self.get_selected_tab_index()
- self.assertNotEqual(second_tab_index, self.selected_tab_index)
-
- # Opens a new window, but we are interested in the tab
- tab_in_new_window = self.open_tab(trigger=self.open_window_in_foreground)
- self.assertEqual(self.marionette.current_window_handle, second_tab)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertNotEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(tab_in_new_window)
- self.assertEqual(self.marionette.current_window_handle, tab_in_new_window)
- self.assertNotEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertNotEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.empty_page)
-
- self.marionette.switch_to_window(second_tab, focus=True)
- self.assertEqual(self.marionette.current_window_handle, second_tab)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- # Bug 1335085 - The focus doesn't change even as requested so.
- # self.assertEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_switch_tabs_for_new_foreground_window_without_focus_change(self):
- # Open an addition tab in the original window so we can better check
- # the selected index in thew new window to be opened.
- second_tab = self.open_tab(trigger=self.open_tab_in_foreground)
- self.marionette.switch_to_window(second_tab, focus=True)
- second_tab_index = self.get_selected_tab_index()
- self.assertNotEqual(second_tab_index, self.selected_tab_index)
-
- # Opens a new window, but we are interested in the tab which automatically
- # gets the focus.
- self.open_tab(trigger=self.open_window_in_foreground)
- self.assertEqual(self.marionette.current_window_handle, second_tab)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertNotEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- # Switch to the second tab in the first window, but don't focus it.
- self.marionette.switch_to_window(second_tab, focus=False)
- self.assertEqual(self.marionette.current_window_handle, second_tab)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- self.assertNotEqual(self.get_selected_tab_index(), second_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_content.py b/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_content.py
deleted file mode 100644
index fbab1898f4..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_switch_window_content.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla ublic
-# 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 Actions, By, Wait
-from marionette_driver.keys import Keys
-
-from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
-
-
-class TestSwitchToWindowContent(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestSwitchToWindowContent, self).setUp()
-
- if self.marionette.session_capabilities["platformName"] == "darwin":
- self.mod_key = Keys.META
- else:
- self.mod_key = Keys.CONTROL
-
- self.empty_page = self.marionette.absolute_url("empty.html")
- self.test_page = self.marionette.absolute_url("windowHandles.html")
-
- self.selected_tab_index = self.get_selected_tab_index()
-
- with self.marionette.using_context("content"):
- self.marionette.navigate(self.test_page)
-
- def tearDown(self):
- self.close_all_tabs()
-
- super(TestSwitchToWindowContent, self).tearDown()
-
- def get_selected_tab_index(self):
- with self.marionette.using_context("chrome"):
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/AppConstants.jsm");
-
- let win = null;
-
- if (AppConstants.MOZ_APP_NAME == "fennec") {
- Components.utils.import("resource://gre/modules/Services.jsm");
- win = Services.wm.getMostRecentWindow("navigator:browser");
- } else {
- Components.utils.import("resource:///modules/RecentWindow.jsm");
- win = RecentWindow.getMostRecentBrowserWindow();
- }
-
- let tabBrowser = null;
-
- // Fennec
- if (win.BrowserApp) {
- tabBrowser = win.BrowserApp;
-
- // Firefox
- } else if (win.gBrowser) {
- tabBrowser = win.gBrowser;
-
- } else {
- return null;
- }
-
- for (let i = 0; i < tabBrowser.tabs.length; i++) {
- if (tabBrowser.tabs[i] == tabBrowser.selectedTab) {
- return i;
- }
- }
- """)
-
- def open_tab_in_background(self):
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-tab")
-
- action = Actions(self.marionette)
- action.key_down(self.mod_key).click(link).perform()
-
- def open_tab_in_foreground(self):
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- def test_switch_tabs_with_focus_change(self):
- new_tab = self.open_tab(self.open_tab_in_foreground)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertNotEqual(self.get_selected_tab_index(), self.selected_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- self.assertNotEqual(self.get_selected_tab_index(), self.selected_tab_index)
-
- with self.marionette.using_context("content"):
- Wait(self.marionette).until(
- lambda _: self.marionette.get_url() == self.empty_page,
- message="{} has been loaded in the newly opened tab.".format(self.empty_page))
-
- self.marionette.switch_to_window(self.start_tab, focus=True)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertEqual(self.get_selected_tab_index(), self.selected_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(new_tab)
- self.marionette.close()
- self.marionette.switch_to_window(self.start_tab)
-
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertEqual(self.get_selected_tab_index(), self.selected_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_switch_tabs_without_focus_change(self):
- new_tab = self.open_tab(self.open_tab_in_foreground)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertNotEqual(self.get_selected_tab_index(), self.selected_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- # Switch to new tab first because it is already selected
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
-
- self.marionette.switch_to_window(self.start_tab, focus=False)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertNotEqual(self.get_selected_tab_index(), self.selected_tab_index)
-
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(new_tab)
- self.marionette.close()
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertEqual(self.get_selected_tab_index(), self.selected_tab_index)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_switch_from_content_to_chrome_window_should_not_change_selected_tab(self):
- new_tab = self.open_tab(self.open_tab_in_foreground)
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- new_tab_index = self.get_selected_tab_index()
-
- self.marionette.switch_to_window(self.start_window)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- self.assertEqual(self.get_selected_tab_index(), new_tab_index)
-
- @skip_if_mobile("New windows not supported in Fennec")
- def test_switch_to_new_private_browsing_window_has_to_register_browsers(self):
- # Test that tabs (browsers) are correctly registered for a newly opened
- # private browsing window. This has to also happen without explicitely
- # switching to the tab itself before using any commands in content scope.
- #
- # Note: Not sure why this only affects private browsing windows only.
-
- def open_private_browsing_window():
- with self.marionette.using_context("content"):
- self.marionette.navigate("about:privatebrowsing")
- button = self.marionette.find_element(By.ID, "startPrivateBrowsing")
- button.click()
-
- new_window = self.open_window(open_private_browsing_window)
- self.marionette.switch_to_window(new_window)
- self.assertEqual(self.marionette.current_chrome_window_handle, new_window)
- self.assertNotEqual(self.marionette.current_window_handle, self.start_tab)
-
- with self.marionette.using_context("content"):
- self.marionette.execute_script(" return true; ")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_teardown_context_preserved.py b/testing/marionette/harness/marionette_harness/tests/unit/test_teardown_context_preserved.py
deleted file mode 100644
index 843152bc58..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_teardown_context_preserved.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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_harness import MarionetteTestCase, SkipTest
-
-
-class TestTearDownContext(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context(self.marionette.CONTEXT_CHROME)
-
- def tearDown(self):
- self.assertEqual(self.get_context(), self.marionette.CONTEXT_CHROME)
- MarionetteTestCase.tearDown(self)
-
- def get_context(self):
- return self.marionette._send_message("getContext", key="value")
-
- def test_skipped_teardown_ok(self):
- raise SkipTest("This should leave our teardown method in chrome context")
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_text.py b/testing/marionette/harness/marionette_harness/tests/unit/test_text.py
deleted file mode 100644
index e2025e9b60..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_text.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# 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.by import By
-from marionette_driver.keys import Keys
-
-from marionette_harness import MarionetteTestCase, skip_if_mobile
-
-
-class TestText(MarionetteTestCase):
- def test_getText(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- l = self.marionette.find_element(By.ID, "mozLink")
- self.assertEqual("Click me!", l.text)
-
- def test_clearText(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- l = self.marionette.find_element(By.NAME, "myInput")
- self.assertEqual("asdf", self.marionette.execute_script("return arguments[0].value;", [l]))
- l.clear()
- self.assertEqual("", self.marionette.execute_script("return arguments[0].value;", [l]))
-
- def test_sendKeys(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- l = self.marionette.find_element(By.NAME, "myInput")
- self.assertEqual("asdf", self.marionette.execute_script("return arguments[0].value;", [l]))
-
- # Set caret position to the middle of the input text.
- self.marionette.execute_script(
- """var el = arguments[0];
- el.selectionStart = el.selectionEnd = el.value.length / 2;""",
- script_args=[l])
-
- l.send_keys("o")
- self.assertEqual("asodf", self.marionette.execute_script("return arguments[0].value;", [l]))
-
- def test_send_keys_to_type_input(self):
- test_html = self.marionette.absolute_url("html5/test_html_inputs.html")
- self.marionette.navigate(test_html)
- num_input = self.marionette.find_element(By.ID, 'number')
- self.assertEqual("", self.marionette.execute_script("return arguments[0].value", [num_input]))
- num_input.send_keys("1234")
- self.assertEqual('1234', self.marionette.execute_script("return arguments[0].value", [num_input]))
-
- def test_should_fire_key_press_events(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("a")
-
- result = self.marionette.find_element(By.ID, "result")
- self.assertIn("press:", result.text)
-
- def test_should_fire_key_down_events(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("a")
-
- result = self.marionette.find_element(By.ID, "result")
- self.assertIn("down:", result.text)
-
- def test_should_fire_key_up_events(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("a")
-
- result = self.marionette.find_element(By.ID, "result")
- self.assertIn("up:", result.text)
-
- def test_should_type_lowercase_characters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("abc def")
-
- self.assertEqual("abc def", key_reporter.get_property("value"))
-
- def test_should_type_uppercase_characters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("ABC DEF")
-
- self.assertEqual("ABC DEF", key_reporter.get_property("value"))
-
- def test_should_type_a_quote_characters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys('"')
-
- self.assertEqual('"', key_reporter.get_property("value"))
-
- def test_should_type_an_at_character(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys('@')
-
- self.assertEqual("@", key_reporter.get_property("value"))
-
- def test_should_type_a_mix_of_upper_and_lower_case_character(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys("me@EXampLe.com")
-
- self.assertEqual("me@EXampLe.com", key_reporter.get_property("value"))
-
- def test_arrow_keys_are_not_printable(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- key_reporter = self.marionette.find_element(By.ID, "keyReporter")
- key_reporter.send_keys(Keys.ARROW_LEFT)
-
- self.assertEqual("", key_reporter.get_property("value"))
-
- def test_will_simulate_a_key_up_when_entering_text_into_input_elements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyUp")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- self.assertEqual(result.text, "I like cheese")
-
- def test_will_simulate_a_key_down_when_entering_text_into_input_elements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyDown")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def test_will_simulate_a_key_press_when_entering_text_into_input_elements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyPress")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def test_will_simulate_a_keyup_when_entering_text_into_textareas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyUpArea")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- self.assertEqual(result.text, "I like cheese")
-
- def test_will_simulate_a_keydown_when_entering_text_into_textareas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyDownArea")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def test_will_simulate_a_keypress_when_entering_text_into_textareas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyPressArea")
- element.send_keys("I like cheese")
-
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- @skip_if_mobile("Bug 1333069 - Assertion: 'down: 40' not found in u''")
- def test_should_report_key_code_of_arrow_keys_up_down_events(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- result = self.marionette.find_element(By.ID, "result")
- element = self.marionette.find_element(By.ID, "keyReporter")
- element.send_keys(Keys.ARROW_DOWN)
- self.assertIn("down: 40", result.text.strip())
- self.assertIn("up: 40", result.text.strip())
-
- element.send_keys(Keys.ARROW_UP)
- self.assertIn("down: 38", result.text.strip())
- self.assertIn("up: 38", result.text.strip())
-
- element.send_keys(Keys.ARROW_LEFT)
- self.assertIn("down: 37", result.text.strip())
- self.assertIn("up: 37", result.text.strip())
-
- element.send_keys(Keys.ARROW_RIGHT)
- self.assertIn("down: 39", result.text.strip())
- self.assertIn("up: 39", result.text.strip())
-
- # And leave no rubbish/printable keys in the "keyReporter"
- self.assertEqual("", element.get_property("value"))
-
- def testNumericNonShiftKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyReporter")
- numericLineCharsNonShifted = "`1234567890-=[]\\,.'/42"
- element.send_keys(numericLineCharsNonShifted)
- self.assertEqual(numericLineCharsNonShifted, element.get_property("value"))
-
- def testShouldTypeAnInteger(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "keyReporter")
- element.send_keys(1234)
- self.assertEqual("1234", element.get_property("value"))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_text_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_text_chrome.py
deleted file mode 100644
index e0b63de16f..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_text_chrome.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase, skip, WindowManagerMixin
-
-
-@skip("Disabled in bug 896043 and when working on Chrome code re-enable for bug 896046")
-class TestTextChrome(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestTextChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- new_window = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(new_window)
-
- def tearDown(self):
- self.close_all_windows()
- super(TestTextChrome, self).tearDown()
-
- def test_getText(self):
- box = self.marionette.find_element(By.ID, "textInput")
- self.assertEqual("test", box.text)
-
- def test_clearText(self):
- box = self.marionette.find_element(By.ID, "textInput")
- self.assertEqual("test", box.text)
- box.clear()
- self.assertEqual("", box.text)
-
- def test_sendKeys(self):
- box = self.marionette.find_element(By.ID, "textInput")
- self.assertEqual("test", box.text)
- box.send_keys("at")
- self.assertEqual("attest", box.text)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_timeouts.py b/testing/marionette/harness/marionette_harness/tests/unit/test_timeouts.py
deleted file mode 100644
index 354e6a7ebb..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_timeouts.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# 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.by import By
-from marionette_driver.errors import (
- MarionetteException,
- NoSuchElementException,
- ScriptTimeoutException,
-)
-from marionette_driver.marionette import HTMLElement
-
-from marionette_harness import MarionetteTestCase, run_if_manage_instance, skip_if_mobile
-
-
-class TestTimeouts(MarionetteTestCase):
- def tearDown(self):
- self.marionette.timeout.reset()
- MarionetteTestCase.tearDown(self)
-
- def test_page_timeout_notdefinetimeout_pass(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
-
- def test_page_timeout_fail(self):
- self.marionette.timeout.page_load = 0
- test_html = self.marionette.absolute_url("test.html")
- self.assertRaises(MarionetteException, self.marionette.navigate, test_html)
-
- def test_page_timeout_pass(self):
- self.marionette.timeout.page_load = 60
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
-
- def test_search_timeout_notfound_settimeout(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- self.marionette.timeout.implicit = 1
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
- self.marionette.timeout.implicit = 0
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "I'm not on the page")
-
- def test_search_timeout_found_settimeout(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- button = self.marionette.find_element(By.ID, "createDivButton")
- button.click()
- self.marionette.timeout.implicit = 8
- self.assertEqual(HTMLElement, type(self.marionette.find_element(By.ID, "newDiv")))
-
- def test_search_timeout_found(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- button = self.marionette.find_element(By.ID, "createDivButton")
- button.click()
- self.assertRaises(NoSuchElementException, self.marionette.find_element, By.ID, "newDiv")
-
- @run_if_manage_instance("Only runnable if Marionette manages the instance")
- @skip_if_mobile("Bug 1322993 - Missing temporary folder")
- def test_reset_timeout(self):
- timeouts = [getattr(self.marionette.timeout, f) for f in (
- 'implicit', 'page_load', 'script',)]
-
- def do_check(callback):
- for timeout in timeouts:
- timeout = 10000
- self.assertEqual(timeout, 10000)
- callback()
- for timeout in timeouts:
- self.assertNotEqual(timeout, 10000)
-
- def callback_quit():
- self.marionette.quit()
- self.marionette.start_session()
-
- do_check(self.marionette.restart)
- do_check(callback_quit)
-
- def test_execute_async_timeout_settimeout(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- self.marionette.timeout.script = 1
- self.assertRaises(ScriptTimeoutException, self.marionette.execute_async_script, "var x = 1;")
-
- def test_no_timeout_settimeout(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- self.marionette.timeout.script = 1
- self.assertTrue(self.marionette.execute_async_script("""
- var callback = arguments[arguments.length - 1];
- setTimeout(function() { callback(true); }, 500);
- """))
-
- def test_compat_input_types(self):
- # When using the spec-incompatible input format which we have
- # for backwards compatibility, it should be possible to send ms
- # as a string type and have the server parseInt it to an integer.
- body = {"type": "script", "ms": "30000"}
- self.marionette._send_message("setTimeouts", body)
-
- def test_deprecated_set_timeouts_command(self):
- body = {"implicit": 3000}
- self.marionette._send_message("timeouts", body)
-
- def test_deprecated_set_search_timeout(self):
- self.marionette.set_search_timeout(1000)
- self.assertEqual(1, self.marionette.timeout.implicit)
-
- def test_deprecated_set_script_timeout(self):
- self.marionette.set_script_timeout(2000)
- self.assertEqual(2, self.marionette.timeout.script)
-
- def test_deprecated_set_page_load_timeout(self):
- self.marionette.set_page_load_timeout(3000)
- self.assertEqual(3, self.marionette.timeout.page_load)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_transport.py b/testing/marionette/harness/marionette_harness/tests/unit/test_transport.py
deleted file mode 100644
index 39e36a9b22..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_transport.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# 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 json
-
-from marionette_driver.transport import (
- Command,
- Proto2Command,
- Proto2Response,
- Response,
-)
-
-from marionette_harness import MarionetteTestCase, skip_unless_protocol
-
-
-get_current_url = ("getCurrentUrl", None)
-execute_script = ("executeScript", {"script": "return 42"})
-
-
-class TestMessageSequencing(MarionetteTestCase):
- @property
- def last_id(self):
- return self.marionette.client.last_id
-
- @last_id.setter
- def last_id(self, new_id):
- self.marionette.client.last_id = new_id
-
- def send(self, name, params):
- self.last_id = self.last_id + 1
- cmd = Command(self.last_id, name, params)
- self.marionette.client.send(cmd)
- return self.last_id
-
- @skip_unless_protocol("Skip for level < 3", lambda level: level >= 3)
- def test_discard_older_messages(self):
- first = self.send(*get_current_url)
- second = self.send(*execute_script)
- resp = self.marionette.client.receive()
- self.assertEqual(second, resp.id)
-
- @skip_unless_protocol("Skip for level < 3", lambda level: level >= 3)
- def test_last_id_incremented(self):
- before = self.last_id
- self.send(*get_current_url)
- self.assertGreater(self.last_id, before)
-
-
-class MessageTestCase(MarionetteTestCase):
- def assert_attr(self, obj, attr):
- self.assertTrue(hasattr(obj, attr),
- "object does not have attribute {}".format(attr))
-
-
-class TestCommand(MessageTestCase):
- def create(self, msgid="msgid", name="name", params="params"):
- return Command(msgid, name, params)
-
- def test_initialise(self):
- cmd = self.create()
- self.assert_attr(cmd, "id")
- self.assert_attr(cmd, "name")
- self.assert_attr(cmd, "params")
- self.assertEqual("msgid", cmd.id)
- self.assertEqual("name", cmd.name)
- self.assertEqual("params", cmd.params)
-
- def test_stringify(self):
- cmd = self.create()
- string = str(cmd)
- self.assertIn("Command", string)
- self.assertIn("id=msgid", string)
- self.assertIn("name=name", string)
- self.assertIn("params=params", string)
-
- def test_to_msg(self):
- cmd = self.create()
- msg = json.loads(cmd.to_msg())
- self.assertEquals(msg[0], Command.TYPE)
- self.assertEquals(msg[1], "msgid")
- self.assertEquals(msg[2], "name")
- self.assertEquals(msg[3], "params")
-
- def test_from_msg(self):
- msg = [Command.TYPE, "msgid", "name", "params"]
- payload = json.dumps(msg)
- cmd = Command.from_msg(payload)
- self.assertEquals(msg[1], cmd.id)
- self.assertEquals(msg[2], cmd.name)
- self.assertEquals(msg[3], cmd.params)
-
-
-class TestResponse(MessageTestCase):
- def create(self, msgid="msgid", error="error", result="result"):
- return Response(msgid, error, result)
-
- def test_initialise(self):
- resp = self.create()
- self.assert_attr(resp, "id")
- self.assert_attr(resp, "error")
- self.assert_attr(resp, "result")
- self.assertEqual("msgid", resp.id)
- self.assertEqual("error", resp.error)
- self.assertEqual("result", resp.result)
-
- def test_stringify(self):
- resp = self.create()
- string = str(resp)
- self.assertIn("Response", string)
- self.assertIn("id=msgid", string)
- self.assertIn("error=error", string)
- self.assertIn("result=result", string)
-
- def test_to_msg(self):
- resp = self.create()
- msg = json.loads(resp.to_msg())
- self.assertEquals(msg[0], Response.TYPE)
- self.assertEquals(msg[1], "msgid")
- self.assertEquals(msg[2], "error")
- self.assertEquals(msg[3], "result")
-
- def test_from_msg(self):
- msg = [Response.TYPE, "msgid", "error", "result"]
- payload = json.dumps(msg)
- resp = Response.from_msg(payload)
- self.assertEquals(msg[1], resp.id)
- self.assertEquals(msg[2], resp.error)
- self.assertEquals(msg[3], resp.result)
-
-
-class TestProto2Command(MessageTestCase):
- def create(self, name="name", params="params"):
- return Proto2Command(name, params)
-
- def test_initialise(self):
- cmd = self.create()
- self.assert_attr(cmd, "id")
- self.assert_attr(cmd, "name")
- self.assert_attr(cmd, "params")
- self.assertEqual(None, cmd.id)
- self.assertEqual("name", cmd.name)
- self.assertEqual("params", cmd.params)
-
- def test_from_data_unknown(self):
- with self.assertRaises(ValueError):
- cmd = Proto2Command.from_data({})
-
-
-class TestProto2Response(MessageTestCase):
- def create(self, error="error", result="result"):
- return Proto2Response(error, result)
-
- def test_initialise(self):
- resp = self.create()
- self.assert_attr(resp, "id")
- self.assert_attr(resp, "error")
- self.assert_attr(resp, "result")
- self.assertEqual(None, resp.id)
- self.assertEqual("error", resp.error)
- self.assertEqual("result", resp.result)
-
- def test_from_data_error(self):
- data = {"error": "error"}
- resp = Proto2Response.from_data(data)
- self.assertEqual(data, resp.error)
- self.assertEqual(None, resp.result)
-
- def test_from_data_result(self):
- resp = Proto2Response.from_data("result")
- self.assertEqual(None, resp.error)
- self.assertEqual("result", resp.result)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_typing.py b/testing/marionette/harness/marionette_harness/tests/unit/test_typing.py
deleted file mode 100644
index ca63a0dc7d..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_typing.py
+++ /dev/null
@@ -1,332 +0,0 @@
-# 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 urllib
-
-from marionette_driver.by import By
-from marionette_driver.errors import ElementNotInteractableException
-from marionette_driver.keys import Keys
-
-from marionette_harness import MarionetteTestCase, skip, skip_if_mobile
-
-
-def inline(doc):
- return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
-
-
-class TypingTestCase(MarionetteTestCase):
-
- def setUp(self):
- super(TypingTestCase, self).setUp()
-
- if self.marionette.session_capabilities["platformName"] == "darwin":
- self.mod_key = Keys.META
- else:
- self.mod_key = Keys.CONTROL
-
-
-class TestTypingChrome(TypingTestCase):
-
- def setUp(self):
- super(TestTypingChrome, self).setUp()
- self.marionette.set_context("chrome")
-
- @skip_if_mobile("Interacting with chrome elements not available for Fennec")
- def test_cut_and_paste_shortcuts(self):
- with self.marionette.using_context("content"):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- self.assertEqual("", keyReporter.get_property("value"))
- keyReporter.send_keys("zyxwvutsr")
- self.assertEqual("zyxwvutsr", keyReporter.get_property("value"))
-
- # select all and cut
- keyReporter.send_keys(self.mod_key, "a")
- keyReporter.send_keys(self.mod_key, "x")
- self.assertEqual("", keyReporter.get_property("value"))
-
- url_bar = self.marionette.find_element(By.ID, "urlbar")
-
- # Clear contents first
- url_bar.send_keys(self.mod_key, "a")
- url_bar.send_keys(Keys.BACK_SPACE)
- self.assertEqual("", url_bar.get_attribute("value"))
-
- url_bar.send_keys(self.mod_key, "v")
- self.assertEqual("zyxwvutsr", url_bar.get_property("value"))
-
-
-class TestTypingContent(TypingTestCase):
-
- def testShouldFireKeyPressEvents(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("a")
- result = self.marionette.find_element(By.ID, "result")
- self.assertTrue("press:" in result.text)
-
- def testShouldFireKeyDownEvents(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("I")
- result = self.marionette.find_element(By.ID, "result")
- self.assertTrue("down" in result.text)
-
- def testShouldFireKeyUpEvents(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("a")
- result = self.marionette.find_element(By.ID, "result")
- self.assertTrue("up:" in result.text)
-
- def testShouldTypeLowerCaseLetters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("abc def")
- self.assertEqual("abc def", keyReporter.get_property("value"))
-
- def testShouldBeAbleToTypeCapitalLetters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("ABC DEF")
- self.assertEqual("ABC DEF", keyReporter.get_property("value"))
-
- def testCutAndPasteShortcuts(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- self.assertEqual("", keyReporter.get_property("value"))
- keyReporter.send_keys("zyxwvutsr")
- self.assertEqual("zyxwvutsr", keyReporter.get_property("value"))
-
- # select all and cut
- keyReporter.send_keys(self.mod_key, "a")
- keyReporter.send_keys(self.mod_key, "x")
- self.assertEqual("", keyReporter.get_property("value"))
-
- keyReporter.send_keys(self.mod_key, "v")
- self.assertEqual("zyxwvutsr", keyReporter.get_property("value"))
-
- def testShouldBeAbleToTypeQuoteMarks(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("\"")
- self.assertEqual("\"", keyReporter.get_property("value"))
-
- def testShouldBeAbleToTypeTheAtCharacter(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("@")
- self.assertEqual("@", keyReporter.get_property("value"))
-
- def testShouldBeAbleToMixUpperAndLowerCaseLetters(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys("me@eXample.com")
- self.assertEqual("me@eXample.com", keyReporter.get_property("value"))
-
- def testArrowKeysShouldNotBePrintable(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- keyReporter = self.marionette.find_element(By.ID, "keyReporter")
- keyReporter.send_keys(Keys.ARROW_LEFT)
- self.assertEqual("", keyReporter.get_property("value"))
-
- def testWillSimulateAKeyUpWhenEnteringTextIntoInputElements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyUp")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- self.assertEqual(result.text, "I like cheese")
-
- def testWillSimulateAKeyDownWhenEnteringTextIntoInputElements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyDown")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def testWillSimulateAKeyPressWhenEnteringTextIntoInputElements(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyPress")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def testWillSimulateAKeyUpWhenEnteringTextIntoTextAreas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyUpArea")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- self.assertEqual("I like cheese", result.text)
-
- def testWillSimulateAKeyDownWhenEnteringTextIntoTextAreas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyDownArea")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- def testWillSimulateAKeyPressWhenEnteringTextIntoTextAreas(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyPressArea")
- element.send_keys("I like cheese")
- result = self.marionette.find_element(By.ID, "result")
- # Because the key down gets the result before the input element is
- # filled, we're a letter short here
- self.assertEqual(result.text, "I like chees")
-
- @skip_if_mobile("Bug 1324752 - Arrow keys cannot be sent in Fennec")
- def testShouldReportKeyCodeOfArrowKeysUpDownEvents(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- result = self.marionette.find_element(By.ID, "result")
- element = self.marionette.find_element(By.ID, "keyReporter")
-
- element.send_keys(Keys.ARROW_DOWN)
-
- self.assertIn("down: 40", result.text.strip())
- self.assertIn("up: 40", result.text.strip())
-
- element.send_keys(Keys.ARROW_UP)
- self.assertIn("down: 38", result.text.strip())
- self.assertIn("up: 38", result.text.strip())
-
- element.send_keys(Keys.ARROW_LEFT)
- self.assertIn("down: 37", result.text.strip())
- self.assertIn("up: 37", result.text.strip())
-
- element.send_keys(Keys.ARROW_RIGHT)
- self.assertIn("down: 39", result.text.strip())
- self.assertIn("up: 39", result.text.strip())
-
- # And leave no rubbish/printable keys in the "keyReporter"
- self.assertEqual("", element.get_property("value"))
-
- @skip("Reenable in Bug 1068728")
- def testNumericShiftKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- result = self.marionette.find_element(By.ID, "result")
- element = self.marionette.find_element(By.ID, "keyReporter")
- numericShiftsEtc = "~!@#$%^&*()_+{}:i\"<>?|END~"
- element.send_keys(numericShiftsEtc)
- self.assertEqual(numericShiftsEtc, element.get_property("value"))
- self.assertIn(" up: 16", result.text.strip())
-
- def testLowerCaseAlphaKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyReporter")
- lowerAlphas = "abcdefghijklmnopqrstuvwxyz"
- element.send_keys(lowerAlphas)
- self.assertEqual(lowerAlphas, element.get_property("value"))
-
- @skip("Reenable in Bug 1068735")
- def testUppercaseAlphaKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- result = self.marionette.find_element(By.ID, "result")
- element = self.marionette.find_element(By.ID, "keyReporter")
- upperAlphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- element.send_keys(upperAlphas)
- self.assertEqual(upperAlphas, element.get_property("value"))
- self.assertIn(" up: 16", result.text.strip())
-
- @skip("Reenable in Bug 1068726")
- def testAllPrintableKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- result = self.marionette.find_element(By.ID, "result")
- element = self.marionette.find_element(By.ID, "keyReporter")
- allPrintable = "!\"#$%&'()*+,-./0123456789:<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ [\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
- element.send_keys(allPrintable)
-
- self.assertTrue(allPrintable, element.get_property("value"))
- self.assertIn(" up: 16", result.text.strip())
-
- @skip("Reenable in Bug 1068733")
- def testSpecialSpaceKeys(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyReporter")
- element.send_keys("abcd" + Keys.SPACE + "fgh" + Keys.SPACE + "ij")
- self.assertEqual("abcd fgh ij", element.get_property("value"))
-
- def testShouldTypeAnInteger(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- element = self.marionette.find_element(By.ID, "keyReporter")
- element.send_keys(1234)
- self.assertEqual("1234", element.get_property("value"))
-
- def testShouldSendKeysToElementsWithoutTheValueAttribute(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- # If we don't get an error below we are good
- self.marionette.find_element(By.TAG_NAME, "body").send_keys("foo")
-
- def test_not_interactable_if_hidden(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- not_displayed = self.marionette.find_element(By.ID, "notDisplayed")
- self.assertRaises(ElementNotInteractableException, not_displayed.send_keys, "foo")
-
- def test_appends_to_input_text(self):
- self.marionette.navigate(inline("<input>"))
- el = self.marionette.find_element(By.TAG_NAME, "input")
- el.send_keys("foo")
- el.send_keys("bar")
- self.assertEqual("foobar", el.get_property("value"))
-
- def test_appends_to_textarea(self):
- self.marionette.navigate(inline("<textarea></textarea>"))
- textarea = self.marionette.find_element(By.TAG_NAME, "textarea")
- textarea.send_keys("foo")
- textarea.send_keys("bar")
- self.assertEqual("foobar", textarea.get_property("value"))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_using_permissions.py b/testing/marionette/harness/marionette_harness/tests/unit/test_using_permissions.py
deleted file mode 100644
index 71e271dd44..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_using_permissions.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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 JavascriptException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestUsingPermssions(MarionetteTestCase):
-
- def test_using_permissions(self):
- # Test that multiple permissions can be set with 'using_permissions',
- # and that they are set correctly and unset correctly after leaving
- # the context manager.
- original_perm = self.marionette.get_permission('systemXHR')
- original_alarm = self.marionette.get_permission('alarms')
- new_perm = True if original_perm != 1 else False
- new_alarm = True if original_alarm != 1 else False
- with self.marionette.using_permissions({'systemXHR': new_perm,
- 'alarms': new_alarm}):
- now_perm = self.marionette.get_permission('systemXHR')
- now_alarm = self.marionette.get_permission('alarms')
- self.assertEquals(new_perm, now_perm)
- self.assertNotEquals(now_perm, original_perm)
- self.assertEquals(new_alarm, now_alarm)
- self.assertNotEquals(now_alarm, original_alarm)
- self.assertEquals(original_perm,
- self.marionette.get_permission('systemXHR'))
- self.assertEquals(original_alarm,
- self.marionette.get_permission('alarms'))
-
- def test_exception_using_permissions(self):
- # Test that throwing an exception inside the context manager doesn't
- # prevent the permissions from being restored at context manager exit.
- original_perm = self.marionette.get_permission('systemXHR')
- new_perm = True if original_perm != 1 else False
- with self.marionette.using_permissions({'systemXHR': new_perm}):
- now_perm = self.marionette.get_permission('systemXHR')
- self.assertEquals(new_perm, now_perm)
- self.assertNotEquals(now_perm, original_perm)
- self.assertRaises(JavascriptException,
- self.marionette.execute_script,
- "return foo.bar.baz;")
- self.assertEquals(original_perm,
- self.marionette.get_permission('systemXHR'))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_visibility.py b/testing/marionette/harness/marionette_harness/tests/unit/test_visibility.py
deleted file mode 100644
index 750ecf20a5..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_visibility.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# 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.by import By
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestVisibility(MarionetteTestCase):
-
- def testShouldAllowTheUserToTellIfAnElementIsDisplayedOrNot(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- self.assertTrue(self.marionette.find_element(By.ID, "displayed").is_displayed())
- self.assertFalse(self.marionette.find_element(By.ID, "none").is_displayed())
- self.assertFalse(self.marionette.find_element(By.ID,
- "suppressedParagraph").is_displayed())
- self.assertFalse(self.marionette.find_element(By.ID, "hidden").is_displayed())
-
- def testVisibilityShouldTakeIntoAccountParentVisibility(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- childDiv = self.marionette.find_element(By.ID, "hiddenchild")
- hiddenLink = self.marionette.find_element(By.ID, "hiddenlink")
-
- self.assertFalse(childDiv.is_displayed())
- self.assertFalse(hiddenLink.is_displayed())
-
- def testShouldCountElementsAsVisibleIfStylePropertyHasBeenSet(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- shown = self.marionette.find_element(By.ID, "visibleSubElement")
- self.assertTrue(shown.is_displayed())
-
- def testShouldModifyTheVisibilityOfAnElementDynamically(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
- element = self.marionette.find_element(By.ID, "hideMe")
- self.assertTrue(element.is_displayed())
- element.click()
- self.assertFalse(element.is_displayed())
-
- def testHiddenInputElementsAreNeverVisible(self):
- test_html = self.marionette.absolute_url("javascriptPage.html")
- self.marionette.navigate(test_html)
-
- shown = self.marionette.find_element(By.NAME, "hidden")
-
- self.assertFalse(shown.is_displayed())
-
- def testShouldSayElementsWithNegativeTransformAreNotDisplayed(self):
- test_html = self.marionette.absolute_url("cssTransform.html")
- self.marionette.navigate(test_html)
-
- elementX = self.marionette.find_element(By.ID, 'parentX')
- self.assertFalse(elementX.is_displayed())
- elementY = self.marionette.find_element(By.ID, 'parentY')
- self.assertFalse(elementY.is_displayed())
-
- def testShouldSayElementsWithParentWithNegativeTransformAreNotDisplayed(self):
- test_html = self.marionette.absolute_url("cssTransform.html")
- self.marionette.navigate(test_html)
-
- elementX = self.marionette.find_element(By.ID, 'childX')
- self.assertFalse(elementX.is_displayed())
- elementY = self.marionette.find_element(By.ID, 'childY')
- self.assertFalse(elementY.is_displayed())
-
- def testShouldSayElementWithZeroTransformIsVisible(self):
- test_html = self.marionette.absolute_url("cssTransform.html")
- self.marionette.navigate(test_html)
-
- zero_tranform = self.marionette.find_element(By.ID, 'zero-tranform')
- self.assertTrue(zero_tranform.is_displayed())
-
- def testShouldSayElementIsVisibleWhenItHasNegativeTransformButElementisntInANegativeSpace(self):
- test_html = self.marionette.absolute_url("cssTransform2.html")
- self.marionette.navigate(test_html)
- negative_percent__tranform = self.marionette.find_element(By.ID, 'negative-percentage-transformY')
- self.assertTrue(negative_percent__tranform.is_displayed())
-
- def testShouldSayElementIsInvisibleWhenOverflowXIsHiddenAndOutOfViewport(self):
- test_html = self.marionette.absolute_url("bug814037.html")
- self.marionette.navigate(test_html)
- overflow_x = self.marionette.find_element(By.ID, "assertMe2")
- self.assertFalse(overflow_x.is_displayed())
-
- def testShouldShowElementNotVisibleWithHiddenAttribute(self):
- test_html = self.marionette.absolute_url("hidden.html")
- self.marionette.navigate(test_html)
- singleHidden = self.marionette.find_element(By.ID, 'singleHidden')
- self.assertFalse(singleHidden.is_displayed())
-
- def testShouldShowElementNotVisibleWhenParentElementHasHiddenAttribute(self):
- test_html = self.marionette.absolute_url("hidden.html")
- self.marionette.navigate(test_html)
- child = self.marionette.find_element(By.ID, 'child')
- self.assertFalse(child.is_displayed())
-
- def testShouldClickOnELementPartiallyOffLeft(self):
- test_html = self.marionette.absolute_url("element_left.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.CSS_SELECTOR, '.element').click()
-
- def testShouldClickOnELementPartiallyOffRight(self):
- test_html = self.marionette.absolute_url("element_right.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.CSS_SELECTOR, '.element').click()
-
- def testShouldClickOnELementPartiallyOffTop(self):
- test_html = self.marionette.absolute_url("element_top.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.CSS_SELECTOR, '.element').click()
-
- def testShouldClickOnELementPartiallyOffBottom(self):
- test_html = self.marionette.absolute_url("element_bottom.html")
- self.marionette.navigate(test_html)
- self.marionette.find_element(By.CSS_SELECTOR, '.element').click()
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_wait.py b/testing/marionette/harness/marionette_harness/tests/unit/test_wait.py
deleted file mode 100644
index 6a48727734..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_wait.py
+++ /dev/null
@@ -1,347 +0,0 @@
-# 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 sys
-import time
-
-from marionette_driver import errors, wait
-from marionette_driver.wait import Wait
-
-from marionette_harness import MarionetteTestCase
-
-
-class TickingClock(object):
-
- def __init__(self, incr=1):
- self.ticks = 0
- self.increment = incr
-
- def sleep(self, dur=None):
- dur = dur if dur is not None else self.increment
- self.ticks += dur
-
- @property
- def now(self):
- return self.ticks
-
-
-class SequenceClock(object):
-
- def __init__(self, times):
- self.times = times
- self.i = 0
-
- @property
- def now(self):
- if len(self.times) > self.i:
- self.i += 1
- return self.times[self.i - 1]
-
- def sleep(self, dur):
- pass
-
-
-class MockMarionette(object):
-
- def __init__(self):
- self.waited = 0
-
- def exception(self, e=None, wait=1):
- self.wait()
- if self.waited == wait:
- if e is None:
- e = Exception
- raise e
-
- def true(self, wait=1):
- self.wait()
- if self.waited == wait:
- return True
- return None
-
- def false(self, wait=1):
- self.wait()
- return False
-
- def none(self, wait=1):
- self.wait()
- return None
-
- def value(self, value, wait=1):
- self.wait()
- if self.waited == wait:
- return value
- return None
-
- def wait(self):
- self.waited += 1
-
-
-def at_third_attempt(clock, end):
- return clock.now == 2
-
-
-def now(clock, end):
- return True
-
-
-class SystemClockTest(MarionetteTestCase):
-
- def setUp(self):
- super(SystemClockTest, self).setUp()
- self.clock = wait.SystemClock()
-
- def test_construction_initializes_time(self):
- self.assertEqual(self.clock._time, time)
-
- def test_sleep(self):
- start = time.time()
- self.clock.sleep(0.1)
- end = time.time() - start
- self.assertGreater(end, 0)
-
- def test_time_now(self):
- self.assertIsNotNone(self.clock.now)
-
-
-class FormalWaitTest(MarionetteTestCase):
-
- def setUp(self):
- super(FormalWaitTest, self).setUp()
- self.m = MockMarionette()
- self.m.timeout = 123
-
- def test_construction_with_custom_timeout(self):
- wt = Wait(self.m, timeout=42)
- self.assertEqual(wt.timeout, 42)
-
- def test_construction_with_custom_interval(self):
- wt = Wait(self.m, interval=42)
- self.assertEqual(wt.interval, 42)
-
- def test_construction_with_custom_clock(self):
- c = TickingClock(1)
- wt = Wait(self.m, clock=c)
- self.assertEqual(wt.clock, c)
-
- def test_construction_with_custom_exception(self):
- wt = Wait(self.m, ignored_exceptions=Exception)
- self.assertIn(Exception, wt.exceptions)
- self.assertEqual(len(wt.exceptions), 1)
-
- def test_construction_with_custom_exception_list(self):
- exc = [Exception, ValueError]
- wt = Wait(self.m, ignored_exceptions=exc)
- for e in exc:
- self.assertIn(e, wt.exceptions)
- self.assertEqual(len(wt.exceptions), len(exc))
-
- def test_construction_with_custom_exception_tuple(self):
- exc = (Exception, ValueError)
- wt = Wait(self.m, ignored_exceptions=exc)
- for e in exc:
- self.assertIn(e, wt.exceptions)
- self.assertEqual(len(wt.exceptions), len(exc))
-
- def test_duplicate_exceptions(self):
- wt = Wait(self.m, ignored_exceptions=[Exception, Exception])
- self.assertIn(Exception, wt.exceptions)
- self.assertEqual(len(wt.exceptions), 1)
-
- def test_default_timeout(self):
- self.assertEqual(wait.DEFAULT_TIMEOUT, 5)
-
- def test_default_interval(self):
- self.assertEqual(wait.DEFAULT_INTERVAL, 0.1)
-
- def test_end_property(self):
- wt = Wait(self.m)
- self.assertIsNotNone(wt.end)
-
- def test_marionette_property(self):
- wt = Wait(self.m)
- self.assertEqual(wt.marionette, self.m)
-
- def test_clock_property(self):
- wt = Wait(self.m)
- self.assertIsInstance(wt.clock, wait.SystemClock)
-
- def test_timeout_uses_default_if_marionette_timeout_is_none(self):
- self.m.timeout = None
- wt = Wait(self.m)
- self.assertEqual(wt.timeout, wait.DEFAULT_TIMEOUT)
-
-
-class PredicatesTest(MarionetteTestCase):
-
- def test_until(self):
- c = wait.SystemClock()
- self.assertFalse(wait.until_pred(c, sys.maxint))
- self.assertTrue(wait.until_pred(c, 0))
-
-
-class WaitUntilTest(MarionetteTestCase):
-
- def setUp(self):
- super(WaitUntilTest, self).setUp()
-
- self.m = MockMarionette()
- self.clock = TickingClock()
- self.wt = Wait(self.m, timeout=10, interval=1, clock=self.clock)
-
- def test_true(self):
- r = self.wt.until(lambda x: x.true())
- self.assertTrue(r)
- self.assertEqual(self.clock.ticks, 0)
-
- def test_true_within_timeout(self):
- r = self.wt.until(lambda x: x.true(wait=5))
- self.assertTrue(r)
- self.assertEqual(self.clock.ticks, 4)
-
- def test_timeout(self):
- with self.assertRaises(errors.TimeoutException):
- r = self.wt.until(lambda x: x.true(wait=15))
- self.assertEqual(self.clock.ticks, 10)
-
- def test_exception_raises_immediately(self):
- with self.assertRaises(TypeError):
- self.wt.until(lambda x: x.exception(e=TypeError))
- self.assertEqual(self.clock.ticks, 0)
-
- def test_ignored_exception(self):
- self.wt.exceptions = (TypeError,)
- with self.assertRaises(errors.TimeoutException):
- self.wt.until(lambda x: x.exception(e=TypeError))
-
- def test_ignored_exception_wrapped_in_timeoutexception(self):
- self.wt.exceptions = (TypeError,)
-
- exc = None
- try:
- self.wt.until(lambda x: x.exception(e=TypeError))
- except Exception as e:
- exc = e
-
- s = str(exc)
- self.assertIsNotNone(exc)
- self.assertIsInstance(exc, errors.TimeoutException)
- self.assertIn(", caused by {0!r}".format(TypeError), s)
- self.assertIn("self.wt.until(lambda x: x.exception(e=TypeError))", s)
-
- def test_ignored_exception_after_timeout_is_not_raised(self):
- with self.assertRaises(errors.TimeoutException):
- r = self.wt.until(lambda x: x.exception(wait=15))
- self.assertEqual(self.clock.ticks, 10)
-
- def test_keyboard_interrupt(self):
- with self.assertRaises(KeyboardInterrupt):
- self.wt.until(lambda x: x.exception(e=KeyboardInterrupt))
-
- def test_system_exit(self):
- with self.assertRaises(SystemExit):
- self.wt.until(lambda x: x.exception(SystemExit))
-
- def test_true_condition_returns_immediately(self):
- r = self.wt.until(lambda x: x.true())
- self.assertIsInstance(r, bool)
- self.assertTrue(r)
- self.assertEqual(self.clock.ticks, 0)
-
- def test_value(self):
- r = self.wt.until(lambda x: "foo")
- self.assertEqual(r, "foo")
- self.assertEqual(self.clock.ticks, 0)
-
- def test_custom_predicate(self):
- r = self.wt.until(lambda x: x.true(wait=2), is_true=at_third_attempt)
- self.assertTrue(r)
- self.assertEqual(self.clock.ticks, 1)
-
- def test_custom_predicate_times_out(self):
- with self.assertRaises(errors.TimeoutException):
- self.wt.until(lambda x: x.true(wait=4), is_true=at_third_attempt)
-
- self.assertEqual(self.clock.ticks, 2)
-
- def test_timeout_elapsed_duration(self):
- with self.assertRaisesRegexp(errors.TimeoutException,
- "Timed out after 2.0 seconds"):
- self.wt.until(lambda x: x.true(wait=4), is_true=at_third_attempt)
-
- def test_timeout_elapsed_rounding(self):
- wt = Wait(self.m, clock=SequenceClock([1, 0.01, 1]), timeout=0)
- with self.assertRaisesRegexp(errors.TimeoutException,
- "Timed out after 1.0 seconds"):
- wt.until(lambda x: x.true(), is_true=now)
-
- def test_timeout_elapsed_interval_by_delayed_condition_return(self):
- def callback(mn):
- self.clock.sleep(11)
- return mn.false()
-
- with self.assertRaisesRegexp(errors.TimeoutException,
- "Timed out after 11.0 seconds"):
- self.wt.until(callback)
- # With a delayed conditional return > timeout, only 1 iteration is
- # possible
- self.assertEqual(self.m.waited, 1)
-
- def test_timeout_with_delayed_condition_return(self):
- def callback(mn):
- self.clock.sleep(.5)
- return mn.false()
-
- with self.assertRaisesRegexp(errors.TimeoutException,
- "Timed out after 10.0 seconds"):
- self.wt.until(callback)
- # With a delayed conditional return < interval, 10 iterations should be
- # possible
- self.assertEqual(self.m.waited, 10)
-
- def test_timeout_interval_shorter_than_delayed_condition_return(self):
- def callback(mn):
- self.clock.sleep(2)
- return mn.false()
-
- with self.assertRaisesRegexp(errors.TimeoutException,
- "Timed out after 10.0 seconds"):
- self.wt.until(callback)
- # With a delayed return of the conditional which takes twice that long than the interval,
- # half of the iterations should be possible
- self.assertEqual(self.m.waited, 5)
-
- def test_message(self):
- self.wt.exceptions = (TypeError,)
- exc = None
- try:
- self.wt.until(lambda x: x.exception(e=TypeError), message="hooba")
- except errors.TimeoutException as e:
- exc = e
-
- result = str(exc)
- self.assertIn("seconds with message: hooba, caused by", result)
-
- def test_no_message(self):
- self.wt.exceptions = (TypeError,)
- exc = None
- try:
- self.wt.until(lambda x: x.exception(e=TypeError), message="")
- except errors.TimeoutException as e:
- exc = e
-
- result = str(exc)
- self.assertIn("seconds, caused by", result)
-
- def test_message_has_none_as_its_value(self):
- self.wt.exceptions = (TypeError,)
- exc = None
- try:
- self.wt.until(False, None, None)
- except errors.TimeoutException as e:
- exc = e
-
- result = str(exc)
- self.assertNotIn("with message:", result)
- self.assertNotIn("secondsNone", result)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_chrome.py
deleted file mode 100644
index 18ae191c19..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_chrome.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# 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_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestCloseWindow(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestCloseWindow, self).setUp()
-
- self.marionette.set_context("chrome")
-
- def tearDown(self):
- self.close_all_windows()
- self.close_all_tabs()
-
- super(TestCloseWindow, self).tearDown()
-
- def test_close_chrome_window_for_browser_window(self):
- win = self.open_window()
- self.marionette.switch_to_window(win)
-
- self.assertNotIn(win, self.marionette.window_handles)
- chrome_window_handles = self.marionette.close_chrome_window()
- self.assertNotIn(win, chrome_window_handles)
- self.assertListEqual(self.start_windows, chrome_window_handles)
- self.assertNotIn(win, self.marionette.window_handles)
-
- def test_close_chrome_window_for_non_browser_window(self):
-
- def open_window_with_js():
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- win = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(win)
-
- self.assertIn(win, self.marionette.window_handles)
- chrome_window_handles = self.marionette.close_chrome_window()
- self.assertNotIn(win, chrome_window_handles)
- self.assertListEqual(self.start_windows, chrome_window_handles)
- self.assertNotIn(win, self.marionette.window_handles)
-
- def test_close_chrome_window_for_last_open_window(self):
- self.close_all_windows()
-
- self.assertListEqual([], self.marionette.close_chrome_window())
- self.assertListEqual([self.start_tab], self.marionette.window_handles)
- self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
- self.assertIsNotNone(self.marionette.session)
-
- def test_close_window_for_browser_tab(self):
- tab = self.open_tab()
- self.marionette.switch_to_window(tab)
-
- window_handles = self.marionette.close()
- self.assertNotIn(tab, window_handles)
- self.assertListEqual(self.start_tabs, window_handles)
-
- def test_close_window_for_browser_window_with_single_tab(self):
- win = self.open_window()
- self.marionette.switch_to_window(win)
-
- self.assertEqual(len(self.start_tabs) + 1, len(self.marionette.window_handles))
- window_handles = self.marionette.close()
- self.assertNotIn(win, window_handles)
- self.assertListEqual(self.start_tabs, window_handles)
- self.assertListEqual(self.start_windows, self.marionette.chrome_window_handles)
-
- def test_close_window_for_last_open_tab(self):
- self.close_all_tabs()
-
- self.assertListEqual([], self.marionette.close())
- self.assertListEqual([self.start_tab], self.marionette.window_handles)
- self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
- self.assertIsNotNone(self.marionette.session)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
deleted file mode 100644
index 8e6485e54a..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
-
-
-class TestCloseWindow(WindowManagerMixin, MarionetteTestCase):
-
- def tearDown(self):
- self.close_all_windows()
- self.close_all_tabs()
-
- super(TestCloseWindow, self).tearDown()
-
- @skip_if_mobile("Interacting with chrome windows not available for Fennec")
- def test_close_chrome_window_for_browser_window(self):
- win = self.open_window()
- self.marionette.switch_to_window(win)
-
- self.assertNotIn(win, self.marionette.window_handles)
- chrome_window_handles = self.marionette.close_chrome_window()
- self.assertNotIn(win, chrome_window_handles)
- self.assertListEqual(self.start_windows, chrome_window_handles)
- self.assertNotIn(win, self.marionette.window_handles)
-
- @skip_if_mobile("Interacting with chrome windows not available for Fennec")
- def test_close_chrome_window_for_non_browser_window(self):
-
- def open_window_with_js():
- with self.marionette.using_context("chrome"):
- self.marionette.execute_script("""
- window.open('chrome://marionette/content/test.xul',
- 'foo', 'chrome,centerscreen');
- """)
-
- win = self.open_window(trigger=open_window_with_js)
- self.marionette.switch_to_window(win)
-
- self.assertIn(win, self.marionette.window_handles)
- chrome_window_handles = self.marionette.close_chrome_window()
- self.assertNotIn(win, chrome_window_handles)
- self.assertListEqual(self.start_windows, chrome_window_handles)
- self.assertNotIn(win, self.marionette.window_handles)
-
- @skip_if_mobile("Interacting with chrome windows not available for Fennec")
- def test_close_chrome_window_for_last_open_window(self):
- self.close_all_windows()
-
- self.assertListEqual([], self.marionette.close_chrome_window())
- self.assertListEqual([self.start_tab], self.marionette.window_handles)
- self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
- self.assertIsNotNone(self.marionette.session)
-
- @skip_if_mobile("Needs application independent method to open a new tab")
- def test_close_window_for_browser_tab(self):
- tab = self.open_tab()
- self.marionette.switch_to_window(tab)
-
- window_handles = self.marionette.close()
- self.assertNotIn(tab, window_handles)
- self.assertListEqual(self.start_tabs, window_handles)
-
- @skip_if_mobile("Interacting with chrome windows not available for Fennec")
- def test_close_window_for_browser_window_with_single_tab(self):
- win = self.open_window()
- self.marionette.switch_to_window(win)
-
- self.assertEqual(len(self.start_tabs) + 1, len(self.marionette.window_handles))
- window_handles = self.marionette.close()
- self.assertNotIn(win, window_handles)
- self.assertListEqual(self.start_tabs, window_handles)
- self.assertListEqual(self.start_windows, self.marionette.chrome_window_handles)
-
- def test_close_window_for_last_open_tab(self):
- self.close_all_tabs()
-
- self.assertListEqual([], self.marionette.close())
- self.assertListEqual([self.start_tab], self.marionette.window_handles)
- self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
- self.assertIsNotNone(self.marionette.session)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_chrome.py
deleted file mode 100644
index 7260d6324f..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_chrome.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# 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_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestWindowHandles(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestWindowHandles, self).setUp()
-
- self.empty_page = self.marionette.absolute_url("empty.html")
- self.test_page = self.marionette.absolute_url("windowHandles.html")
- self.marionette.navigate(self.test_page)
-
- self.marionette.set_context("chrome")
-
- def tearDown(self):
- self.close_all_windows()
- self.close_all_tabs()
-
- super(TestWindowHandles, self).tearDown()
-
- def test_chrome_window_handles_with_scopes(self):
- # Open a browser and a non-browser (about window) chrome window
- self.open_window(
- trigger=lambda: self.marionette.execute_script("window.open();"))
- self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 1)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
-
- self.open_window(
- trigger=lambda: self.marionette.find_element(By.ID, "aboutName").click())
- self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 2)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
-
- chrome_window_handles_in_chrome_scope = self.marionette.chrome_window_handles
- window_handles_in_chrome_scope = self.marionette.window_handles
-
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.chrome_window_handles,
- chrome_window_handles_in_chrome_scope)
- self.assertEqual(self.marionette.window_handles,
- window_handles_in_chrome_scope)
-
- def test_chrome_window_handles_after_opening_new_window(self):
- def open_with_link():
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-window")
- link.click()
-
- # We open a new window but are actually interested in the new tab
- new_win = self.open_window(trigger=open_with_link)
- self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 1)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
-
- # Check that the new tab has the correct page loaded
- self.marionette.switch_to_window(new_win)
- self.assertEqual(self.marionette.current_chrome_window_handle, new_win)
- with self.marionette.using_context("content"):
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.get_url() == self.empty_page,
- message="{} did not load after opening a new tab".format(self.empty_page))
-
- # Ensure navigate works in our current window
- other_page = self.marionette.absolute_url("test.html")
- with self.marionette.using_context("content"):
- self.marionette.navigate(other_page)
- self.assertEqual(self.marionette.get_url(), other_page)
-
- # Close the opened window and carry on in our original tab.
- self.marionette.close()
- self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows))
-
- self.marionette.switch_to_window(self.start_window)
- self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_window_handles_after_opening_new_tab(self):
- def open_with_link():
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- with self.marionette.using_context("content"):
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.get_url() == self.empty_page,
- message="{} did not load after opening a new tab".format(self.empty_page))
-
- # Ensure navigate works in our current tab
- other_page = self.marionette.absolute_url("test.html")
- with self.marionette.using_context("content"):
- self.marionette.navigate(other_page)
- self.assertEqual(self.marionette.get_url(), other_page)
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(new_tab)
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- def test_window_handles_after_opening_new_window(self):
- def open_with_link():
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-window")
- link.click()
-
- # We open a new window but are actually interested in the new tab
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- # Check that the new tab has the correct page loaded
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- with self.marionette.using_context("content"):
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.get_url() == self.empty_page,
- message="{} did not load after opening a new tab".format(self.empty_page))
-
- # Ensure navigate works in our current window
- other_page = self.marionette.absolute_url("test.html")
- with self.marionette.using_context("content"):
- self.marionette.navigate(other_page)
- self.assertEqual(self.marionette.get_url(), other_page)
-
- # Close the opened window and carry on in our original tab.
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_window_handles_after_closing_original_tab(self):
- def open_with_link():
- with self.marionette.using_context("content"):
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- with self.marionette.using_context("content"):
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.get_url() == self.empty_page,
- message="{} did not load after opening a new tab".format(self.empty_page))
-
- def test_window_handles_no_switch(self):
- """Regression test for bug 1294456.
- This test is testing the case where Marionette attempts to send a
- command to a window handle when the browser has opened and selected
- a new tab. Before bug 1294456 landed, the Marionette driver was getting
- confused about which window handle the client cared about, and assumed
- it was the window handle for the newly opened and selected tab.
-
- This caused Marionette to think that the browser needed to do a remoteness
- flip in the e10s case, since the tab opened by menu_newNavigatorTab is
- about:newtab (which is currently non-remote). This meant that commands
- sent to what should have been the original window handle would be
- queued and never sent, since the remoteness flip in the new tab was
- never going to happen.
- """
- def open_with_menu():
- menu_new_tab = self.marionette.find_element(By.ID, 'menu_newNavigatorTab')
- menu_new_tab.click()
-
- new_tab = self.open_tab(trigger=open_with_menu)
-
- # We still have the default tab set as our window handle. This
- # get_url command should be sent immediately, and not be forever-queued.
- with self.marionette.using_context("content"):
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
-
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_content.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_content.py
deleted file mode 100644
index b6ad3a6c33..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_content.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# 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_harness import MarionetteTestCase, WindowManagerMixin
-
-
-class TestWindowHandles(WindowManagerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestWindowHandles, self).setUp()
-
- self.empty_page = self.marionette.absolute_url("empty.html")
- self.test_page = self.marionette.absolute_url("windowHandles.html")
- self.marionette.navigate(self.test_page)
-
- def tearDown(self):
- self.close_all_tabs()
-
- super(TestWindowHandles, self).tearDown()
-
- def test_window_handles_after_opening_new_tab(self):
- def open_with_link():
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
- lambda mn: mn.get_url() == self.empty_page,
- message="{} did not load after opening a new tab".format(self.empty_page))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- self.marionette.switch_to_window(new_tab)
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- def test_window_handles_after_opening_new_window(self):
- def open_with_link():
- link = self.marionette.find_element(By.ID, "new-window")
- link.click()
-
- # We open a new window but are actually interested in the new tab
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- # Check that the new tab has the correct page loaded
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- Wait(self.marionette, self.marionette.timeout.page_load).until(
- lambda _: self.marionette.get_url() == self.empty_page,
- message="The expected page '{}' has not been loaded".format(self.empty_page))
-
- # Ensure navigate works in our current window
- other_page = self.marionette.absolute_url("test.html")
- self.marionette.navigate(other_page)
- self.assertEqual(self.marionette.get_url(), other_page)
-
- # Close the opened window and carry on in our original tab.
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(self.start_tab)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
- self.assertEqual(self.marionette.get_url(), self.test_page)
-
- def test_window_handles_after_closing_original_tab(self):
- def open_with_link():
- link = self.marionette.find_element(By.ID, "new-tab")
- link.click()
-
- new_tab = self.open_tab(trigger=open_with_link)
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
- self.assertEqual(self.marionette.current_window_handle, self.start_tab)
-
- self.marionette.close()
- self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
-
- self.marionette.switch_to_window(new_tab)
- self.assertEqual(self.marionette.current_window_handle, new_tab)
- Wait(self.marionette, self.marionette.timeout.page_load).until(
- lambda _: self.marionette.get_url() == self.empty_page,
- message="The expected page '{}' has not been loaded".format(self.empty_page))
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_position.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_position.py
deleted file mode 100644
index ac53658068..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_position.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#Copyright 2007-2009 WebDriver committers
-#
-#Licensed under the Apache License, Version 2.0 (the "License");
-#you may not use this file except in compliance with the License.
-#You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-#Unless required by applicable law or agreed to in writing, software
-#distributed under the License is distributed on an "AS IS" BASIS,
-#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#See the License for the specific language governing permissions and
-#limitations under the License.
-
-from marionette_driver.errors import InvalidArgumentException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestWindowPosition(MarionetteTestCase):
- def test_get_types(self):
- position = self.marionette.get_window_position()
- self.assertTrue(isinstance(position["x"], int))
- self.assertTrue(isinstance(position["y"], int))
-
- def test_set_types(self):
- for x, y in (["a", "b"], [1.2, 3.4], [True, False], [[], []], [{}, {}]):
- with self.assertRaises(InvalidArgumentException):
- self.marionette.set_window_position(x, y)
-
- def test_out_of_bounds_arguments(self):
- with self.assertRaises(InvalidArgumentException):
- self.marionette.set_window_position(-1, 0)
- with self.assertRaises(InvalidArgumentException):
- self.marionette.set_window_position(0, -1)
-
- def test_move(self):
- old_position = self.marionette.get_window_position()
- new_position = {"x": old_position["x"] + 10, "y": old_position["y"] + 10}
- self.marionette.set_window_position(new_position["x"], new_position["y"])
- self.assertNotEqual(old_position['x'], new_position["x"])
- self.assertNotEqual(old_position['y'], new_position["y"])
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_title.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_title.py
deleted file mode 100644
index 4f6e3ccf7d..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_title.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestTitle(MarionetteTestCase):
- def test_get_html_title(self):
- test_html = self.marionette.absolute_url("test.html")
- self.marionette.navigate(test_html)
- self.assertEqual('Marionette Test', self.marionette.title)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py
deleted file mode 100644
index 7bee682fdc..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_title_chrome.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestTitleChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_get_chrome_title(self):
- title = self.marionette.execute_script("return window.document.documentElement.getAttribute('title');")
- self.assertEqual(title, self.marionette.title)
- self.assertEqual('Title Test', self.marionette.title)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py b/testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py
deleted file mode 100644
index 6c5e75f517..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_window_type.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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_harness import MarionetteTestCase
-
-
-class TestWindowTypeChrome(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
- self.marionette.set_context("chrome")
- self.win = self.marionette.current_window_handle
- self.marionette.execute_script("window.open('chrome://marionette/content/test.xul', 'foo', 'chrome,centerscreen');")
- self.marionette.switch_to_window('foo')
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
-
- def tearDown(self):
- self.assertNotEqual(self.win, self.marionette.current_window_handle)
- self.marionette.execute_script("window.close();")
- self.marionette.switch_to_window(self.win)
- MarionetteTestCase.tearDown(self)
-
- def test_get_window_type(self):
- window_type = self.marionette.execute_script("return window.document.documentElement.getAttribute('windowtype');")
- self.assertEqual(window_type, self.marionette.get_window_type())
- self.assertEqual('Test Type', self.marionette.get_window_type())
-
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_with_using_context.py b/testing/marionette/harness/marionette_harness/tests/unit/test_with_using_context.py
deleted file mode 100644
index 1b2d60d2dd..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_with_using_context.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# 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.decorators import using_context
-from marionette_driver.errors import MarionetteException
-
-from marionette_harness import MarionetteTestCase
-
-
-class TestSetContext(MarionetteTestCase):
- def setUp(self):
- MarionetteTestCase.setUp(self)
-
- # shortcuts to improve readability of these tests
- self.chrome = self.marionette.CONTEXT_CHROME
- self.content = self.marionette.CONTEXT_CONTENT
-
- test_url = self.marionette.absolute_url("empty.html")
- self.marionette.navigate(test_url)
- self.marionette.set_context(self.content)
- self.assertEquals(self.get_context(), self.content)
-
- def get_context(self):
- return self.marionette._send_message("getContext", key="value")
-
- def test_set_different_context_using_with_block(self):
- with self.marionette.using_context(self.chrome):
- self.assertEquals(self.get_context(), self.chrome)
- self.assertEquals(self.get_context(), self.content)
-
- def test_set_same_context_using_with_block(self):
- with self.marionette.using_context(self.content):
- self.assertEquals(self.get_context(), self.content)
- self.assertEquals(self.get_context(), self.content)
-
- def test_nested_with_blocks(self):
- with self.marionette.using_context(self.chrome):
- self.assertEquals(self.get_context(), self.chrome)
- with self.marionette.using_context(self.content):
- self.assertEquals(self.get_context(), self.content)
- self.assertEquals(self.get_context(), self.chrome)
- self.assertEquals(self.get_context(), self.content)
-
- def test_set_scope_while_in_with_block(self):
- with self.marionette.using_context(self.chrome):
- self.assertEquals(self.get_context(), self.chrome)
- self.marionette.set_context(self.content)
- self.assertEquals(self.get_context(), self.content)
- self.assertEquals(self.get_context(), self.content)
-
- def test_exception_raised_while_in_with_block_is_propagated(self):
- with self.assertRaises(MarionetteException):
- with self.marionette.using_context(self.chrome):
- raise MarionetteException
- self.assertEquals(self.get_context(), self.content)
-
- def test_with_using_context_decorator(self):
- @using_context('content')
- def inner_content(m):
- self.assertEquals(self.get_context(), 'content')
- @using_context('chrome')
- def inner_chrome(m):
- self.assertEquals(self.get_context(), 'chrome')
- inner_content(self.marionette)
- inner_chrome(self.marionette)
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
deleted file mode 100644
index 573096378c..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ /dev/null
@@ -1,132 +0,0 @@
-[test_marionette.py]
-[test_geckoinstance.py]
-[test_data_driven.py]
-[test_session.py]
-[test_capabilities.py]
-[test_accessibility.py]
-[test_expectedfail.py]
-expected = fail
-[test_import_script.py]
-[test_click.py]
-[test_click_chrome.py]
-skip-if = appname == 'fennec'
-[test_checkbox.py]
-[test_checkbox_chrome.py]
-skip-if = appname == 'fennec'
-[test_elementsize.py]
-[test_elementsize_chrome.py]
-skip-if = appname == 'fennec'
-[test_position.py]
-[test_rendered_element.py]
-[test_chrome_element_css.py]
-skip-if = appname == 'fennec'
-[test_element_state.py]
-[test_element_state_chrome.py]
-skip-if = appname == 'fennec'
-[test_text.py]
-[test_text_chrome.py]
-skip-if = true # "Bug 896046"
-
-[test_clearing.py]
-[test_typing.py]
-
-[test_log.py]
-
-[test_about_pages.py]
-
-[test_execute_async_script.py]
-[test_execute_script.py]
-[test_simpletest_fail.js]
-[test_element_retrieval.py]
-[test_findelement_chrome.py]
-skip-if = appname == 'fennec'
-
-[test_navigation.py]
-
-[test_timeouts.py]
-
-[test_single_finger_desktop.py]
-skip-if = appname == 'fennec' || os == "win" # Bug 1025040
-
-[test_simpletest_pass.js]
-[test_simpletest_sanity.py]
-[test_simpletest_chrome.js]
-[test_simpletest_timeout.js]
-[test_anonymous_content.py]
-skip-if = appname == 'fennec'
-[test_switch_frame.py]
-skip-if = os == "win" # Bug 1078237
-[test_switch_frame_chrome.py]
-skip-if = appname == 'fennec'
-[test_switch_remote_frame.py]
-skip-if = appname == 'fennec'
-[test_switch_window_chrome.py]
-skip-if = appname == 'fennec'
-[test_switch_window_content.py]
-
-[test_pagesource.py]
-[test_pagesource_chrome.py]
-skip-if = appname == 'fennec'
-
-[test_visibility.py]
-[test_window_handles_chrome.py]
-skip-if = appname == 'fennec'
-[test_window_handles_content.py]
-[test_window_close_chrome.py]
-skip-if = appname == 'fennec'
-[test_window_close_content.py]
-[test_window_position.py]
-skip-if = appname == 'fennec'
-
-[test_screenshot.py]
-[test_cookies.py]
-[test_window_title.py]
-[test_window_title_chrome.py]
-skip-if = appname == 'fennec'
-[test_window_type.py]
-skip-if = appname == 'fennec'
-[test_implicit_waits.py]
-[test_wait.py]
-[test_expected.py]
-[test_date_time_value.py]
-[test_getactiveframe_oop.py]
-skip-if = true # Bug 925688
-[test_chrome_async_finish.js]
-[test_screen_orientation.py]
-[test_errors.py]
-
-[test_execute_isolate.py]
-[test_click_scrolling.py]
-[test_profile_management.py]
-skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
-[test_quit_restart.py]
-skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
-[test_set_window_size.py]
-skip-if = os == "linux" || appname == 'fennec' # Bug 1085717
-[test_with_using_context.py]
-
-[test_modal_dialogs.py]
-skip-if = appname == 'fennec' # Bug 1325738
-[test_key_actions.py]
-[test_mouse_action.py]
-skip-if = appname == 'fennec'
-[test_teardown_context_preserved.py]
-[test_file_upload.py]
-skip-if = appname == 'fennec' || os == "win" # http://bugs.python.org/issue14574
-
-[test_execute_sandboxes.py]
-[test_using_permissions.py]
-[test_prefs.py]
-
-[test_shadow_dom.py]
-
-[test_chrome.py]
-skip-if = appname == 'fennec'
-
-[test_addons.py]
-skip-if = appname == 'fennec' # Bug 1330598
-
-[test_select.py]
-[test_crash.py]
-skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
-[test_localization.py]
diff --git a/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini b/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini
deleted file mode 100644
index 5c94220af1..0000000000
--- a/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[include:../../../../../dom/system/tests/marionette/manifest.ini]
-skip-if = android_version > '15' # Bug 1203072
-[include:../../../../../dom/events/test/marionette/manifest.ini]
-skip-if = android_version > '15' # Bug 1203075
-[include:../../../../../dom/network/tests/marionette/manifest.ini]
diff --git a/testing/marionette/harness/marionette_harness/www/black.png b/testing/marionette/harness/marionette_harness/www/black.png
deleted file mode 100644
index b62a3a7bc8..0000000000
--- a/testing/marionette/harness/marionette_harness/www/black.png
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/bug814037.html b/testing/marionette/harness/marionette_harness/www/bug814037.html
deleted file mode 100644
index 22950134e2..0000000000
--- a/testing/marionette/harness/marionette_harness/www/bug814037.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<html>
-<head>
-<style>
-body {
- width: 100%;
- margin: 0px;
- transition: transform 300ms ease;
- overflow-x: hidden;
-}
-
-body.section1 {
- transform: translateX(0%);
-}
-
-body.section2 {
- transform: translateX(-100%);
-}
-
-section {
- width: 100%;
- height: 100%;
- position: absolute;
-}
-
-#section1 {
- left: 0px;
-}
-
-#section2 {
- left: 100%;
-}
-.mypossie {
- position:absolute;
- left: -1000px;
-}
-</style>
-
-</head>
- <body class="section1">
- <section id="section1">
- <div id="assertMe1">
- <p>Section 1</p>
- </div>
- <button id="b1" onclick="var sect = document.getElementsByTagName('body')[0]; sect.classList.add('section2'); sect.classList.remove('section1');">Show section 2</button>
- </section>
-
- <section id="section2">
- <div id="assertMe2">
- <p>Section 2</p>
- </div>
- <button id="b2" onclick="var sect = document.getElementsByTagName('body')[0]; sect.classList.add('section1'); sect.classList.remove('section2'); ">Show section 1</button>
- </section>
- <section class='mypossie'>out in left field!</section>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/click_out_of_bounds_overflow.html b/testing/marionette/harness/marionette_harness/www/click_out_of_bounds_overflow.html
deleted file mode 100644
index f0bee9b469..0000000000
--- a/testing/marionette/harness/marionette_harness/www/click_out_of_bounds_overflow.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html><head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<body>
-<div style="height: 100px; overflow: auto;">
- <table>
- <tbody>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td>data</td></tr>
- <tr><td><a href="#clicked" id="link">click me</a></td></tr>
- </tbody>
- </table>
-</div>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/clicks.html b/testing/marionette/harness/marionette_harness/www/clicks.html
deleted file mode 100644
index e48cb1b2f7..0000000000
--- a/testing/marionette/harness/marionette_harness/www/clicks.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<html>
-<head>
- <!-- 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/. -->
- <title>clicks</title>
-</head>
-<body>
-<h1>Testing Clicks</h1>
-
-<iframe id="source" src="click_source.html">
-
-</iframe>
-
-<iframe id="target" name="target">
-
-</iframe>
-
-<a href="xhtmlTest.html" id="normal">I'm a normal link</a>
-<a href="#" id="anchor">I go to an anchor</a>
-<a href="javascript:window.open('xhtmlTest.html', '_blank')" id="new-window">I open a window with javascript</a>
-<a href="xhtmlTest.html" id="twoClientRects"><span></span><span>Click me</span></a>
-<a href="xhtmlTest.html" id="link-with-enclosed-image"><img id="enclosed-image" src="./icon.gif"/></a>
-<a href="xhtmlTest.html" id="link-with-enclosed-span"><span id="enclosed-span" style="color: rgb(0, 255, 0)">I'm a green link</span></a>
-<p style="background: none repeat scroll 0% 0% rgb(0, 255, 0); width: 5em;"><a id="overflowLink" href="xhtmlTest.html">looooooooooong short looooooooooong</a>
- </p>
-<div id="bubblesTo" onclick="window.bubbledClick = true;">
- <a id="bubblesFrom">I bubble</a>
-</div>
-<div id="addbuttonlistener" onclick="var el = document.getElementById('showbutton');el.addEventListener('mousedown', function (evt) { document.getElementById('showbutton').innerHTML = evt.button; }, false);">
- click to add an event listener
-</div>
-<div id="showbutton">
- this will show the button clicked
-</div>
-<a href="xhtmlTest.html">333333</a>
-<p><a href="xhtmlTest.html" id="embeddedBlock"><span style="display: block;">I have a span</span><div>And a div</div><span>And another span</span></a></p>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/cssTransform.html b/testing/marionette/harness/marionette_harness/www/cssTransform.html
deleted file mode 100644
index c3b99648ac..0000000000
--- a/testing/marionette/harness/marionette_harness/www/cssTransform.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<style>
-#parentY {
- transform: translateY(-10000px);
- -webkit-transform: translateY(-10000px);
- -o-transform: translateY(-10000px);
- -ms-transform: translateY(-10000px);
- -moz-transform: translateY(-10000px);
-}
-#parentX {
- transform: translateX(-10000px);
- -webkit-transform: translateX(-10000px);
- -o-transform: translateX(-10000px);
- -ms-transform: translateX(-10000px);
- -moz-transform: translateX(-10000px);
-}
-#transformX {
- transform: translateX(-10000px);
- -webkit-transform: translateX(-10000px);
- -o-transform: translateX(-10000px);
- -ms-transform: translateX(-10000px);
- -moz-transform: translateX(-10000px);
-}
-#transformY {
- transform: translateY(-10000px);
- -webkit-transform: translateY(-10000px);
- -o-transform: translateY(-10000px);
- -ms-transform: translateY(-10000px);
- -moz-transform: translateY(-10000px);
-}
-
-#zero-transform {
- transform: translateY(0px);
- -webkit-transform: translateY(0px);
- -o-transform: translateY(0px);
- -ms-transform: translateY(0px);
- -moz-transform: translateY(0px);
- transform: translateX(0px);
- -webkit-transform: translateX(0px);
- -o-transform: translateX(0px);
- -ms-transform: translateX(0px);
- -moz-transform: translateX(0px);
-}
-</style>
-<div id='zero-tranform'>
-You shouldn't see anything other than this sentence on the page
-</div>
-<div id='parentY'>
- I have a hidden child
- <div id='childY'>
- I am a hidden child
- </div>
-</div>
-<div id='parentX'>
- I have a hidden child
- <div id='childX'>
- I am a hidden child
- </div>
-</div>
-<div id='transformX'>I am a hidden element </div>
-<div id='transformY'>I am a hidden element </div>
diff --git a/testing/marionette/harness/marionette_harness/www/cssTransform2.html b/testing/marionette/harness/marionette_harness/www/cssTransform2.html
deleted file mode 100644
index 602924bfbb..0000000000
--- a/testing/marionette/harness/marionette_harness/www/cssTransform2.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<style>
-#negative-percentage-transformY{
- transform: translateY(-75px);
- -webkit-transform: translateY(-75%);
- -o-transform: translateY(-75%);
- -ms-transform: translateY(-75%);
- -moz-transform: translateY(-75%);
-}
-.block {
- display = block;
-}
-</style>
-<div class='block'>
- <br/>
-</div>
- <br/>
-<div class='block'>
-</div>
-<div id='negative-percentage-transformY'>I am not a hidden element </div>
diff --git a/testing/marionette/harness/marionette_harness/www/datetimePage.html b/testing/marionette/harness/marionette_harness/www/datetimePage.html
deleted file mode 100644
index 87a05f6d26..0000000000
--- a/testing/marionette/harness/marionette_harness/www/datetimePage.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <!-- 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/. -->
-<head>
- <title>Testing date and time inputs</title>
-</head>
-<body>
- <form>
- <input id="date-test" type="date"/>
- <input id="time-test" type="time"/>
- </form>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/deletingFrame.html b/testing/marionette/harness/marionette_harness/www/deletingFrame.html
deleted file mode 100644
index d891605aff..0000000000
--- a/testing/marionette/harness/marionette_harness/www/deletingFrame.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<html>
-<head>
- <title></title>
-</head>
- <script type="text/javascript">
- function remove() {
- var iframe = document.getElementById("iframe1");
- var myDiv = document.getElementById("myDiv");
- myDiv.removeChild(iframe);
- }
- function addBack() {
- var iframe = '<iframe src="javascriptPage.html" marginheight="0" marginwidth="0" topmargin="0" leftmargin="600" allowtransparency="true" frameborder="0" height="600" scrolling="no" width="120" id="iframe1"></iframe>';
- var myDiv2 = document.getElementById("myDiv2");
- myDiv2.innerHTML = iframe;
- }
- </script>
-<body>
-
-<div id='myDiv'>
-<iframe src="formPage.html" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true"
- frameborder="1" height="900" scrolling="no" width="500" id="iframe1"></iframe>
-
- </div>
-<div id='myDiv2'>
-
-</div>
-<input type='button' id='addBackFrame' value='Add back frame' onclick='addBack();' />
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/double_click.html b/testing/marionette/harness/marionette_harness/www/double_click.html
deleted file mode 100644
index fb3ec217a6..0000000000
--- a/testing/marionette/harness/marionette_harness/www/double_click.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <!-- 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/. -->
- <head>
- <title>Testing Double Click</title>
- </head>
- <div>
- <p id="one-word-div">zyxw</p>
- </div>
-
- <div>
- <form>
- <input type="text" id="input-field" size="80"/>
- </form>
- </div>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/element_bottom.html b/testing/marionette/harness/marionette_harness/www/element_bottom.html
deleted file mode 100644
index 470199a078..0000000000
--- a/testing/marionette/harness/marionette_harness/www/element_bottom.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<style>
- .element{
- position: absolute;
- bottom: -50px;
- background-color: red;
- width: 100px;
- height: 100px;
- }
-</style>
-<div class='element'></div>
-
diff --git a/testing/marionette/harness/marionette_harness/www/element_left.html b/testing/marionette/harness/marionette_harness/www/element_left.html
deleted file mode 100644
index c98b945f94..0000000000
--- a/testing/marionette/harness/marionette_harness/www/element_left.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<style>
- .element {
- position: absolute;
- left: -50px;
- background-color: red;
- width: 100px;
- height: 100px;
- }
-</style>
-<div class='element'></div>
-
diff --git a/testing/marionette/harness/marionette_harness/www/element_outside_viewport.html b/testing/marionette/harness/marionette_harness/www/element_outside_viewport.html
deleted file mode 100644
index 69b66b8759..0000000000
--- a/testing/marionette/harness/marionette_harness/www/element_outside_viewport.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<style>
- div {
- position: absolute;
- width: 100px;
- height: 100px;
- }
- .top { background-color: red; }
- #top-70 { left: 80px; top: 0; }
- #top-50 { left: 190px; top: 20px; }
- #top-30 { left: 300px; top: 40px; }
-
- .right { background-color: black; }
- #right-70 { top: 80px; right: -140px;}
- #right-50 { top: 190px; right: -120px;}
- #right-30 { top: 300px; right: -100px;}
-
- .bottom { background-color: blue; }
- #bottom-70 { right: -50px; bottom: -140px; }
- #bottom-50 { right: 60px; bottom: -120px; }
- #bottom-30 { right: 170px; bottom: -100px; }
-
- .left { background-color: green; }
- #left-70 { bottom: -50px; left: 0; }
- #left-50 { bottom: 60px; left: 20px; }
- #left-30 { bottom: 170px; left: 40px; }
-</style>
-<body onload="window.scrollTo(70, 70);">
- <div id="top-70" class="top"></div>
- <div id="top-50" class="top"></div>
- <div id="top-30" class="top"></div>
- <div id="right-70" class="right"></div>
- <div id="right-50" class="right"></div>
- <div id="right-30" class="right"></div>
- <div id="bottom-70" class="bottom"></div>
- <div id="bottom-50" class="bottom"></div>
- <div id="bottom-30" class="bottom"></div>
- <div id="left-70" class="left"></div>
- <div id="left-50" class="left"></div>
- <div id="left-30" class="left"></div>
-</body>
diff --git a/testing/marionette/harness/marionette_harness/www/element_right.html b/testing/marionette/harness/marionette_harness/www/element_right.html
deleted file mode 100644
index ff8774ab6d..0000000000
--- a/testing/marionette/harness/marionette_harness/www/element_right.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<style>
- .element{
- position: absolute;
- right: -50px;
- background-color: red;
- width: 100px;
- height: 100px;
- }
-</style>
-<div class='element'></div>
-
diff --git a/testing/marionette/harness/marionette_harness/www/element_top.html b/testing/marionette/harness/marionette_harness/www/element_top.html
deleted file mode 100644
index b975e34c46..0000000000
--- a/testing/marionette/harness/marionette_harness/www/element_top.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<style>
- .element{
- position: absolute;
- top: -50px;
- background-color: red;
- width: 100px;
- height: 100px;
- }
-</style>
-<div class='element'></div>
-
diff --git a/testing/marionette/harness/marionette_harness/www/empty.html b/testing/marionette/harness/marionette_harness/www/empty.html
deleted file mode 100644
index 0a9d08cd62..0000000000
--- a/testing/marionette/harness/marionette_harness/www/empty.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>Marionette Test</title>
-</head>
-<body>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/formPage.html b/testing/marionette/harness/marionette_harness/www/formPage.html
deleted file mode 100644
index ee1ff9f2b9..0000000000
--- a/testing/marionette/harness/marionette_harness/www/formPage.html
+++ /dev/null
@@ -1,116 +0,0 @@
-<html>
-<head>
- <title>We Leave From Here</title>
-
- <script type="text/javascript">
- function changePage() {
- var newLocation = '/common/page/3';
- window.location = newLocation;
- }
- </script>
-</head>
-<body>
-There should be a form here:
-
-<form method="get" action="resultPage.html" name="login">
- <input type="email" id="email"/>
- <input type="submit" id="submitButton" value="Hello there"/>
-</form>
-
-<form method="get" action="resultPage.html" name="optional" style="display: block">
- Here's a checkbox:
- <input type="checkbox" id="checky" name="checky" value="furrfu"/>
- <input type="checkbox" id="checkedchecky" name="checkedchecky" checked="checked" />
- <input type="checkbox" id="disabledchecky" disabled="disabled" name="disabledchecky" />
- <input type="checkbox" id="randomly_disabled_checky" disabled="somerandomstring" checked="checked" name="randomlydisabledchecky" />
- <br/>
- <select name="selectomatic">
- <option selected="selected" id="non_multi_option" value="one">One</option>
- <option value="two">Two</option>
- <option value="four">Four</option>
- <option value="still learning how to count, apparently">Still learning how to count, apparently</option>
- </select>
-
- <select name="multi" id="multi" multiple="multiple">
- <option selected="selected" value="eggs">Eggs</option>
- <option value="ham">Ham</option>
- <option selected="selected" value="sausages">Sausages</option>
- <option value="onion gravy">Onion gravy</option>
- </select>
-
- <select name="no-select" disabled="disabled">
- <option value="foo">Foo</option>
- </select>
-
- <select name="select_empty_multiple" multiple>
- <option id="multi_1" value="select_1">select_1</option>
- <option id="multi_2" value="select_2">select_2</option>
- <option id="multi_3" value="select_3">select_3</option>
- <option id="multi_4" value="select_4">select_4</option>
- </select>
-
- <select name="multi_true" multiple="true">
- <option id="multi_true_1" value="select_1">select_1</option>
- <option id="multi_true_2" value="select_2">select_2</option>
- </select>
-
- <select name="multi_false" multiple="false">
- <option id="multi_false_1" value="select_1">select_1</option>
- <option id="multi_false_2" value="select_2">select_2</option>
- </select>
-
- <select id="invisi_select" style="opacity:0;">
- <option selected value="apples">Apples</option>
- <option value="oranges">Oranges</option>
- </select>
-
- <select name="select-default">
- <option>One</option>
- <option>Two</option>
- <option>Four</option>
- <option>Still learning how to count, apparently</option>
- </select>
-
- <select name="select_with_spaces">
- <option>One</option>
- <option> Two </option>
- <option>
- Four
- </option>
- <option>
- Still learning how to count,
- apparently
- </option>
- </select>
-
- <select>
- <option id="blankOption"></option>
- <option id="optionEmptyValueSet" value="">nothing</option>
- </select>
-
- <br/>
-
- <input type="radio" id="cheese" name="snack" value="cheese"/>Cheese<br/>
- <input type="radio" id="peas" name="snack" value="peas"/>Peas<br/>
- <input type="radio" id="cheese_and_peas" name="snack" value="cheese and peas" checked/>Cheese and peas<br/>
- <input type="radio" id="nothing" name="snack" value="nowt" disabled="disabled"/>Not a sausage<br/>
- <input type="radio" id="randomly_disabled_nothing" name="snack" value="funny nowt" disabled="somedisablingstring"/>Not another sausage
-
- <input type="hidden" name="hidden" value="fromage" />
-
- <p id="cheeseLiker">I like cheese</p>
- <input type="submit" value="Click!"/>
-
- <input type="radio" id="lone_disabled_selected_radio" name="not_a_snack" value="cumberland" checked="checked" disabled="disabled" />Cumberland sausage
-</form>
-
-<input type='button' id='killIframe' onclick='top.remove();' value="Kill containing iframe" />
-
-<form method="get" action="formPage.html">
- <p>
- <label for="checkbox-with-label" id="label-for-checkbox-with-label">Label</label><input type="checkbox" id="checkbox-with-label" />
- </p>
-</form>
-<input id="vsearchGadget" name="SearchableText" type="text" size="18" value="" title="Hvad søger du?" accesskey="4" class="inputLabel" />
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/frameset.html b/testing/marionette/harness/marionette_harness/www/frameset.html
deleted file mode 100644
index 209d705b5a..0000000000
--- a/testing/marionette/harness/marionette_harness/www/frameset.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
- <head>
- <title>Unique title</title>
- </head>
-<frameset cols="*, *, *, *, *, *, *">
- <frame name="first" src="page/1"/>
- <frame name="second" src="page/2?title=Fish"/>
- <frame name="third" src="formPage.html"/>
- <frame name="fourth" src="framesetPage2.html"/>
- <frame id="fifth" src="xhtmlTest.html"/>
- <frame id="sixth" src="test_iframe.html"/>
- <frame id="sixth.iframe1" src="page/3"/>
-</frameset>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/framesetPage2.html b/testing/marionette/harness/marionette_harness/www/framesetPage2.html
deleted file mode 100644
index 5190ceb6ce..0000000000
--- a/testing/marionette/harness/marionette_harness/www/framesetPage2.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<head></head>
-<frameset cols="*, *">
- <frame name="child1" src="test.html"/>
- <frame name="child2" src="test.html"/>
-</frameset>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/hidden.html b/testing/marionette/harness/marionette_harness/www/hidden.html
deleted file mode 100644
index 0e8097e973..0000000000
--- a/testing/marionette/harness/marionette_harness/www/hidden.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<div id='singleHidden' hidden>This will not be visible</div>
-<div id='parent' hidden>
- <div id='child'>My parent is hidden so you can't see me</div>
-</div> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/html5/blue.jpg b/testing/marionette/harness/marionette_harness/www/html5/blue.jpg
deleted file mode 100644
index 8ea27c42fa..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/blue.jpg
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/html5/boolean_attributes.html b/testing/marionette/harness/marionette_harness/www/html5/boolean_attributes.html
deleted file mode 100644
index eb0d458b84..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/boolean_attributes.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<input id='disabled' disabled> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/html5/geolocation.js b/testing/marionette/harness/marionette_harness/www/html5/geolocation.js
deleted file mode 100644
index f07af148ed..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/geolocation.js
+++ /dev/null
@@ -1,18 +0,0 @@
-function success(position) {
- var message = document.getElementById("status");
- message.innerHTML ="<img src='http://maps.google.com/maps/api/staticmap?center=" + position.coords.latitude + "," + position.coords.longitude + "&size=300x200&maptype=roadmap&zoom=12&&markers=size:mid|color:red|" + position.coords.latitude + "," + position.coords.longitude + "&sensor=false' />";
- message.innerHTML += "<p>Longitude: " + position.coords.longitude + "</p>";
- message.innerHTML += "<p>Latitude: " + position.coords.latitude + "</p>";
- message.innerHTML += "<p>Altitude: " + position.coords.altitude + "</p>";
-}
-
-function error(msg) {
- var message = document.getElementById("status");
- message.innerHTML = "Failed to get geolocation.";
-}
-
-if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(success, error);
-} else {
- error('Geolocation is not supported.');
-} \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/html5/green.jpg b/testing/marionette/harness/marionette_harness/www/html5/green.jpg
deleted file mode 100644
index 6a0d3bea47..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/green.jpg
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/html5/offline.html b/testing/marionette/harness/marionette_harness/www/html5/offline.html
deleted file mode 100644
index c24178b5f5..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/offline.html
+++ /dev/null
@@ -1 +0,0 @@
-<html><head><title>Offline</title></head><body></body></html>
diff --git a/testing/marionette/harness/marionette_harness/www/html5/red.jpg b/testing/marionette/harness/marionette_harness/www/html5/red.jpg
deleted file mode 100644
index f296e27195..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/red.jpg
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/html5/status.html b/testing/marionette/harness/marionette_harness/www/html5/status.html
deleted file mode 100644
index 394116a522..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/status.html
+++ /dev/null
@@ -1 +0,0 @@
-<html><head><title>Online</title></head><body></body></html>
diff --git a/testing/marionette/harness/marionette_harness/www/html5/test.appcache b/testing/marionette/harness/marionette_harness/www/html5/test.appcache
deleted file mode 100644
index 3bc4e00257..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/test.appcache
+++ /dev/null
@@ -1,11 +0,0 @@
-CACHE MANIFEST
-
-CACHE:
-# Additional items to cache.
-yellow.jpg
-red.jpg
-blue.jpg
-green.jpg
-
-FALLBACK:
-status.html offline.html
diff --git a/testing/marionette/harness/marionette_harness/www/html5/test_html_inputs.html b/testing/marionette/harness/marionette_harness/www/html5/test_html_inputs.html
deleted file mode 100644
index 96c9b97e3b..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/test_html_inputs.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<input id='number' type=number> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/html5/yellow.jpg b/testing/marionette/harness/marionette_harness/www/html5/yellow.jpg
deleted file mode 100644
index 7c609b3712..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5/yellow.jpg
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/html5Page.html b/testing/marionette/harness/marionette_harness/www/html5Page.html
deleted file mode 100644
index 4197cd1226..0000000000
--- a/testing/marionette/harness/marionette_harness/www/html5Page.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<html manifest="html5/test.appcache">
-<!--
-Copyright 2011 Software Freedom Conservancy.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-
-<head>
-<title>HTML5</title>
-</head>
-<body>
-
-<h3>Geolocation Test</h3>
-<div id="status">Location unknown</div>
-<script language="javascript" type="text/javascript" src="html5/geolocation.js"></script>
-
-<h3>Application Cache Test</h3>
-<div id="images">
- <p>Current network status: <span id="state"></span></p>
- <script>
- var state = document.getElementById('state')
- setInterval(function () {
- state.className = navigator.onLine ? 'online' : 'offline';
- state.innerHTML = navigator.onLine ? 'online' : 'offline';
- }, 250);
- </script>
- <img id="red" src="html5/red.jpg">
- <img id="blue" src="html5/blue.jpg">
- <img id="green" src="html5/green.jpg">
- <img id="yellow" src="html5/yellow.jpg">
-</div>
-
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/javascriptPage.html b/testing/marionette/harness/marionette_harness/www/javascriptPage.html
deleted file mode 100644
index b47c902c5e..0000000000
--- a/testing/marionette/harness/marionette_harness/www/javascriptPage.html
+++ /dev/null
@@ -1,278 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <!-- 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/. -->
-<head>
- <title>Testing Javascript</title>
- <script type="text/javascript">
- var seen = {};
-
- function updateContent(input) {
- document.getElementById('result').innerHTML = "<p>" + input.value + "</p>";
- }
-
- function displayMessage(message) {
- document.getElementById('result').innerHTML = "<p>" + message + "</p>";
- }
-
- function appendMessage(message) {
- document.getElementById('result').innerHTML += message + " ";
- }
-
- function register(message) {
- if (!seen[message]) {
- appendMessage(message);
- seen[message] = true;
- }
- }
-
- function delayedShowHide(delay, show) {
- var blackBox = document.getElementById('clickToHide');
- window.setTimeout(function() {
- blackBox.style.display = show ? '' : 'none';
- }, delay);
- }
- </script>
- <script type="text/javascript">
- var startList = function() {
- // Ugh. Let's hope no-one is faking their user agent when running the tests
- if (navigator.userAgent.indexOf("MSIE") != -1) {
- var navRoot = document.getElementById("nav");
- for (var i = 0; i < navRoot.childNodes.length; i++) {
- var node = navRoot.childNodes[i];
- if (node.nodeName == "LI") {
- node.onmouseover = function() {
- this.className += " over";
- };
- node.onmouseout = function() {
- this.className = this.className.replace(" over", "");
- };
- }
- }
- }
- };
- window.onload=startList;
- </script>
- <style type="text/css">
- #nav {
- padding: 0; margin: 0; list-style: none;
- }
- #nav li {
- float: left; position: relative; width: 10em;
- }
- #nav li ul {
- display: none; position: absolute; top: 1em; left: 0;
- }
- #nav li > ul { top: auto; left: auto; }
- #nav li:hover ul, #nav li.over ul{ display: block; background: white; }
- </style>
-</head>
-<body>
-<h1>Type Stuff</h1>
-
-<div>
- <ul id="nav">
- <li id="menu1">Menu 1
- <ul>
- <li id="item1" onclick="displayMessage('item 1');">Item 1</li>
- <li>Item 2</li>
- </ul>
- </li>
- </ul>
-</div>
-
-<div id="resultContainer" height="30">&nbsp;
- <div id="result" style="width:300;height:60">
- <p>&nbsp;</p>
- </div>
-
-</div>
-
-<div id="formageddon">
- <form action="#">
- Key Up: <input type="text" id="keyUp" onkeyup="javascript:updateContent(this)"/><br/>
- Key Down: <input type="text" id="keyDown" onkeydown="javascript:updateContent(this)"/><br/>
- Key Press: <input type="text" id="keyPress" onkeypress="javascript:updateContent(this)"/><br/>
- Change: <input type="text" id="change" onkeypress="javascript:displayMessage('change')"/><br/>
- <textarea id="keyDownArea" onkeydown="javascript:updateContent(this)" rows="2" cols="15"></textarea>
- <textarea id="keyPressArea" onkeypress="javascript:updateContent(this)" rows="2" cols="15"></textarea>
- <textarea id="keyUpArea" onkeyup="javascript:updateContent(this)" rows="2" cols="15"></textarea>
- <select id="selector" onchange="javascript:updateContent(this)">
- <option value="foo">Foo</option>
- <option value="bar">Bar</option>
- </select>
- <input type="checkbox" id="checkbox" value="checkbox thing" onchange="javascript:updateContent(this)"/>
- <input id="clickField" type="text" onclick="document.getElementById('clickField').value='Clicked';" value="Hello"/>
- <input id="doubleClickField" type="text" onclick="document.getElementById('doubleClickField').value='Clicked';" ondblclick="document.getElementById('doubleClickField').value='DoubleClicked';" oncontextmenu="document.getElementById('doubleClickField').value='ContextClicked'; return false;" value="DoubleHello"/>
- <input id="clearMe" value="Something" onchange="displayMessage('Cleared')"/>
- </form>
-</div>
-
-<div>
- <p><a href="#" onclick="javascript:document.title='Changed'">Change the page title!</a></p>
-
- <p><a onclick="javascript:document.title='Changed'" id="nohref">No href</a></p>
-
- <p><a id="updatediv" href="#" onclick="javascript:document.getElementById('dynamo').innerHTML = 'Fish and chips!';">Update a
- div</a></p>
-</div>
-
-<div id="dynamo">What's for dinner?</div>
-
-<div id="mousedown" onmousedown="javascript:displayMessage('mouse down');">
- <p>Click for the mouse down event</p>
- <span><p id="child">Here's some text</p></span>
-</div>
-
-<div id="mouseup" onmouseup="javascript:displayMessage('mouse up');">
- <p>Click for the mouse up event</p>
-</div>
-
-<div id="mouseclick" onclick="javascript:displayMessage('mouse click');">
- <p>Click for the mouse click event</p>
-</div>
-
-<div id="mousebutton">
- <p>Click to show button</p>
-</div>
-
-<div id="error" onclick="document.getElementById('doesnotexist').innerHTML = 'cheese';">
- Clicking this causes a JS exception in the click handler
-</div>
-
-<div>
- <form action="resultPage.html" id="on-form">
- <input id="theworks"
- onfocus="appendMessage('focus')"
- onkeydown="appendMessage('keydown')"
- onkeypress="appendMessage('keypress')"
- onkeyup="appendMessage('keyup')"
- onblur="appendMessage('blur')"
- onchange="appendMessage('change')"
- />
-
- <input id="changeable" name="changeable" onfocus="appendMessage('focus')" onchange="appendMessage('change')" onblur="appendMessage('blur')"/>
-
- <button type="button" id="plainButton"
- onfocus="appendMessage('focus')"
- onkeydown="appendMessage('keydown')"
- onkeypress="appendMessage('keypress')"
- onkeyup="appendMessage('keyup')"
- onblur="appendMessage('blur')"
- onclick="appendMessage('click')"
- onmousedown="appendMessage('mousedown ')"
- onmouseup="appendMessage('mouseup ')"
- onmouseover="register('mouseover ')"
- onmousemove="register('mousemove ')"
- >
- <b>Go somewhere</b>
- </button>
- <button type="submit" id="submittingButton"><emph>submit</emph></button>
- <button type="button" id="jsSubmitButton" onclick="javascript:document.getElementById('on-form').submit();">Submitomatic</button>
-
- <button type="button" id="switchFocus" onclick="document.getElementById('theworks').focus();">Switch focus</button>
- <button type="button" onclick="var element = document.getElementById('switchFocus'); var clickEvent = document.createEvent('MouseEvents'); clickEvent.initMouseEvent('click', true, true, null, 0, 0, 0, 0, 0,false, false, false, false, 0, element);element.dispatchEvent(clickEvent);">Do magic</button><br/>
- <label id="labelForCheckbox" for="labeledCheckbox" onclick="appendMessage('labelclick')">Toggle checkbox</label><input type="checkbox" id="labeledCheckbox" onclick="appendMessage('chboxclick')"/>
- </form>
-
- <form action="javascriptPage.html" id="submitListeningForm" onsubmit="appendMessage('form-onsubmit '); return false;">
- <p>
- <input id="submitListeningForm-text" type="text" onsubmit="appendMessage('text-onsubmit ')" onclick="appendMessage('text-onclick ');" />
- <input id="submitListeningForm-submit" type="submit" onsubmit="appendMessage('submit-onsubmit ')" onclick="appendMessage('submit-onclick ');" />
- </p>
- </form>
-</div>
-
-<p id="suppressedParagraph" style="display: none">A paragraph suppressed using CSS display=none</p>
-
-<div>
- <p id="displayed">Displayed</p>
-
- <form action="#"><input type="hidden" name="hidden" /> </form>
-
- <p id="none" style="display: none;">Display set to none</p>
-
- <p id="hidden" style="visibility: hidden;">Hidden</p>
-
- <div id="hiddenparent" style="height: 2em; display: none;">
- <div id="hiddenchild">
- <a href="#" id="hiddenlink">ok</a>
- </div>
- </div>
-
- <div style="visibility: hidden;">
- <span>
- <input id="unclickable" />
- <input type="checkbox" id="untogglable" checked="checked" />Check box you can't see
- </span>
- </div>
-
- <p id="outer" style="visibility: hidden">A <b id="visibleSubElement" style="visibility: visible">sub-element that is explicitly visible</b> using CSS visibility=visible</p>
-</div>
-
-<div>
- <form>
- <input type="text" id="keyReporter" size="80"
- onkeyup="appendMessage('up: ' + event.keyCode)"
- onkeypress="appendMessage('press: ' + event.keyCode)"
- onkeydown="displayMessage(''); appendMessage('down: ' + event.keyCode)" />
- <input name="suppress" onkeydown="if (event.preventDefault) event.preventDefault(); event.returnValue = false; return false;" onkeypress="appendMessage('press');"/>
- </form>
-</div>
-
-<!-- Used for testing styles -->
-<div style="background-color: green;" id="green-parent">
- <p id="style1">This should be greenish</p>
- <ul>
- <li id="green-item">So should this</li>
- <li id="red-item" style="background-color: red;">But this is red</li>
- </ul>
-</div>
-
-<a href="#" id="close" onclick="window.close();">Close window</a>
-
-<div id="delete" onclick="var d = document.getElementById('deleted'); this.removeChild(d);">
- <p id="deleted">I should be deleted when you click my containing div</p>
- <p>Whereas, I should not</p>
-</div>
-
-<div>
- <span id="hideMe" onclick="this.style.display = 'none';">Click to hide me.</span>
-</div>
-
-<div style="margin-top: 10px;">
- Click actions delayed by 3000ms:
- <div id="clickToShow" onclick="delayedShowHide(3000, true);"
- style="float: left;width: 100px;height:100px;border: 1px solid black;">
- Click to show black box
- </div>
- <div id="clickToHide" onclick="delayedShowHide(3000, false);"
- style="float: left;width: 100px;height:100px;border: 1px solid black;
- background-color: black; color: white; display: none;">
- Click to hide black box
- </div>
- <div style="clear: both"></div>
-</div>
-
-<a id="new_window" onmouseup="window.open('closeable_window.html', 'close_me')" href="#">Click me to open a new window</a>
-
-<a id="throwing-mouseover" onmouseover="throw new Error()" href="#throwing-mouseover">Mouse over me will throw a JS error</a>
-
-<div id="parent">
- <span id="movable" onmouseover="var p = document.getElementById('movable'); displayMessage('parent matches? ' + (p != event.relatedTarget));">
- Click on me to show the related target
- </span>
-</div>
-
-<div id="zero" style="width:0;height:0">
- <div>
- <img src="map.png">
- </div>
-</div>
-
-<input type='text' id='notDisplayed' style='display:none'>
-</body>
-</html>
-
-
diff --git a/testing/marionette/harness/marionette_harness/www/macbeth.html b/testing/marionette/harness/marionette_harness/www/macbeth.html
deleted file mode 100644
index 2404f1d727..0000000000
--- a/testing/marionette/harness/marionette_harness/www/macbeth.html
+++ /dev/null
@@ -1,5254 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
- <html>
- <head>
- <title>Macbeth: Entire Play
- </title>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- </HEAD>
- <body bgcolor="#ffffff" text="#000000">
-
- <!-- Originally from http://shakespeare.mit.edu/macbeth/full.html -->
-
-<a href="#5.8.86">Quick link to last speech</a>
-
-<H3>ACT I</h3>
-<h3>SCENE I. A desert place.</h3>
-<p><blockquote>
-<i>Thunder and lightning. Enter three Witches</i>
-</blockquote>
-
-<A NAME=speech1><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.1.1>When shall we three meet again</A><br>
-<A NAME=1.1.2>In thunder, lightning, or in rain?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.1.3>When the hurlyburly's done,</A><br>
-<A NAME=1.1.4>When the battle's lost and won.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.1.5>That will be ere the set of sun.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.1.6>Where the place?</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.1.7> Upon the heath.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.1.8>There to meet with Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.1.9>I come, Graymalkin!</A><br>
-</blockquote>
-
-<A NAME=speech8><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.1.10>Paddock calls.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.1.11>Anon.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>ALL</b></a>
-<blockquote>
-<A NAME=1.1.12>Fair is foul, and foul is fair:</A><br>
-<A NAME=1.1.13>Hover through the fog and filthy air.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE II. A camp near Forres.</h3>
-<p><blockquote>
-<i>Alarum within. Enter DUNCAN, MALCOLM, DONALBAIN, LENNOX, with Attendants, meeting a bleeding Sergeant</i>
-</blockquote>
-
-<A NAME=speech1><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.1>What bloody man is that? He can report,</A><br>
-<A NAME=1.2.2>As seemeth by his plight, of the revolt</A><br>
-<A NAME=1.2.3>The newest state.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=1.2.4> This is the sergeant</A><br>
-<A NAME=1.2.5>Who like a good and hardy soldier fought</A><br>
-<A NAME=1.2.6>'Gainst my captivity. Hail, brave friend!</A><br>
-<A NAME=1.2.7>Say to the king the knowledge of the broil</A><br>
-<A NAME=1.2.8>As thou didst leave it.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Sergeant</b></a>
-<blockquote>
-<A NAME=1.2.9>Doubtful it stood;</A><br>
-<A NAME=1.2.10>As two spent swimmers, that do cling together</A><br>
-<A NAME=1.2.11>And choke their art. The merciless Macdonwald--</A><br>
-<A NAME=1.2.12>Worthy to be a rebel, for to that</A><br>
-<A NAME=1.2.13>The multiplying villanies of nature</A><br>
-<A NAME=1.2.14>Do swarm upon him--from the western isles</A><br>
-<A NAME=1.2.15>Of kerns and gallowglasses is supplied;</A><br>
-<A NAME=1.2.16>And fortune, on his damned quarrel smiling,</A><br>
-<A NAME=1.2.17>Show'd like a rebel's whore: but all's too weak:</A><br>
-<A NAME=1.2.18>For brave Macbeth--well he deserves that name--</A><br>
-<A NAME=1.2.19>Disdaining fortune, with his brandish'd steel,</A><br>
-<A NAME=1.2.20>Which smoked with bloody execution,</A><br>
-<A NAME=1.2.21>Like valour's minion carved out his passage</A><br>
-<A NAME=1.2.22>Till he faced the slave;</A><br>
-<A NAME=1.2.23>Which ne'er shook hands, nor bade farewell to him,</A><br>
-<A NAME=1.2.24>Till he unseam'd him from the nave to the chaps,</A><br>
-<A NAME=1.2.25>And fix'd his head upon our battlements.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.26>O valiant cousin! worthy gentleman!</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Sergeant</b></a>
-<blockquote>
-<A NAME=1.2.27>As whence the sun 'gins his reflection</A><br>
-<A NAME=1.2.28>Shipwrecking storms and direful thunders break,</A><br>
-<A NAME=1.2.29>So from that spring whence comfort seem'd to come</A><br>
-<A NAME=1.2.30>Discomfort swells. Mark, king of Scotland, mark:</A><br>
-<A NAME=1.2.31>No sooner justice had with valour arm'd</A><br>
-<A NAME=1.2.32>Compell'd these skipping kerns to trust their heels,</A><br>
-<A NAME=1.2.33>But the Norweyan lord surveying vantage,</A><br>
-<A NAME=1.2.34>With furbish'd arms and new supplies of men</A><br>
-<A NAME=1.2.35>Began a fresh assault.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.36>Dismay'd not this</A><br>
-<A NAME=1.2.37>Our captains, Macbeth and Banquo?</A><br>
-</blockquote>
-
-<A NAME=speech7><b>Sergeant</b></a>
-<blockquote>
-<A NAME=1.2.38>Yes;</A><br>
-<A NAME=1.2.39>As sparrows eagles, or the hare the lion.</A><br>
-<A NAME=1.2.40>If I say sooth, I must report they were</A><br>
-<A NAME=1.2.41>As cannons overcharged with double cracks, so they</A><br>
-<A NAME=1.2.42>Doubly redoubled strokes upon the foe:</A><br>
-<A NAME=1.2.43>Except they meant to bathe in reeking wounds,</A><br>
-<A NAME=1.2.44>Or memorise another Golgotha,</A><br>
-<A NAME=1.2.45>I cannot tell.</A><br>
-<A NAME=1.2.46>But I am faint, my gashes cry for help.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.47>So well thy words become thee as thy wounds;</A><br>
-<A NAME=1.2.48>They smack of honour both. Go get him surgeons.</A><br>
-<p><i>Exit Sergeant, attended</i></p>
-<A NAME=1.2.49>Who comes here?</A><br>
-<p><i>Enter ROSS</i></p>
-</blockquote>
-
-<A NAME=speech9><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=1.2.50> The worthy thane of Ross.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>LENNOX</b></a>
-<blockquote>
-<A NAME=1.2.51>What a haste looks through his eyes! So should he look</A><br>
-<A NAME=1.2.52>That seems to speak things strange.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.2.53>God save the king!</A><br>
-</blockquote>
-
-<A NAME=speech12><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.54>Whence camest thou, worthy thane?</A><br>
-</blockquote>
-
-<A NAME=speech13><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.2.55>From Fife, great king;</A><br>
-<A NAME=1.2.56>Where the Norweyan banners flout the sky</A><br>
-<A NAME=1.2.57>And fan our people cold. Norway himself,</A><br>
-<A NAME=1.2.58>With terrible numbers,</A><br>
-<A NAME=1.2.59>Assisted by that most disloyal traitor</A><br>
-<A NAME=1.2.60>The thane of Cawdor, began a dismal conflict;</A><br>
-<A NAME=1.2.61>Till that Bellona's bridegroom, lapp'd in proof,</A><br>
-<A NAME=1.2.62>Confronted him with self-comparisons,</A><br>
-<A NAME=1.2.63>Point against point rebellious, arm 'gainst arm.</A><br>
-<A NAME=1.2.64>Curbing his lavish spirit: and, to conclude,</A><br>
-<A NAME=1.2.65>The victory fell on us.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.66>Great happiness!</A><br>
-</blockquote>
-
-<A NAME=speech15><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.2.67>That now</A><br>
-<A NAME=1.2.68>Sweno, the Norways' king, craves composition:</A><br>
-<A NAME=1.2.69>Nor would we deign him burial of his men</A><br>
-<A NAME=1.2.70>Till he disbursed at Saint Colme's inch</A><br>
-<A NAME=1.2.71>Ten thousand dollars to our general use.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.72>No more that thane of Cawdor shall deceive</A><br>
-<A NAME=1.2.73>Our bosom interest: go pronounce his present death,</A><br>
-<A NAME=1.2.74>And with his former title greet Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech17><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.2.75>I'll see it done.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.2.76>What he hath lost noble Macbeth hath won.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE III. A heath near Forres.</h3>
-<p><blockquote>
-<i>Thunder. Enter the three Witches</i>
-</blockquote>
-
-<A NAME=speech1><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.1>Where hast thou been, sister?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.2>Killing swine.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.3>Sister, where thou?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.4>A sailor's wife had chestnuts in her lap,</A><br>
-<A NAME=1.3.5>And munch'd, and munch'd, and munch'd:--</A><br>
-<A NAME=1.3.6>'Give me,' quoth I:</A><br>
-<A NAME=1.3.7>'Aroint thee, witch!' the rump-fed ronyon cries.</A><br>
-<A NAME=1.3.8>Her husband's to Aleppo gone, master o' the Tiger:</A><br>
-<A NAME=1.3.9>But in a sieve I'll thither sail,</A><br>
-<A NAME=1.3.10>And, like a rat without a tail,</A><br>
-<A NAME=1.3.11>I'll do, I'll do, and I'll do.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.12>I'll give thee a wind.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.13>Thou'rt kind.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.14>And I another.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.15>I myself have all the other,</A><br>
-<A NAME=1.3.16>And the very ports they blow,</A><br>
-<A NAME=1.3.17>All the quarters that they know</A><br>
-<A NAME=1.3.18>I' the shipman's card.</A><br>
-<A NAME=1.3.19>I will drain him dry as hay:</A><br>
-<A NAME=1.3.20>Sleep shall neither night nor day</A><br>
-<A NAME=1.3.21>Hang upon his pent-house lid;</A><br>
-<A NAME=1.3.22>He shall live a man forbid:</A><br>
-<A NAME=1.3.23>Weary se'nnights nine times nine</A><br>
-<A NAME=1.3.24>Shall he dwindle, peak and pine:</A><br>
-<A NAME=1.3.25>Though his bark cannot be lost,</A><br>
-<A NAME=1.3.26>Yet it shall be tempest-tost.</A><br>
-<A NAME=1.3.27>Look what I have.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.28>Show me, show me.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.29>Here I have a pilot's thumb,</A><br>
-<A NAME=1.3.30>Wreck'd as homeward he did come.</A><br>
-<p><i>Drum within</i></p>
-</blockquote>
-
-<A NAME=speech11><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.31>A drum, a drum!</A><br>
-<A NAME=1.3.32>Macbeth doth come.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>ALL</b></a>
-<blockquote>
-<A NAME=1.3.33>The weird sisters, hand in hand,</A><br>
-<A NAME=1.3.34>Posters of the sea and land,</A><br>
-<A NAME=1.3.35>Thus do go about, about:</A><br>
-<A NAME=1.3.36>Thrice to thine and thrice to mine</A><br>
-<A NAME=1.3.37>And thrice again, to make up nine.</A><br>
-<A NAME=1.3.38>Peace! the charm's wound up.</A><br>
-<p><i>Enter MACBETH and BANQUO</i></p>
-</blockquote>
-
-<A NAME=speech13><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.39>So foul and fair a day I have not seen.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.40>How far is't call'd to Forres? What are these</A><br>
-<A NAME=1.3.41>So wither'd and so wild in their attire,</A><br>
-<A NAME=1.3.42>That look not like the inhabitants o' the earth,</A><br>
-<A NAME=1.3.43>And yet are on't? Live you? or are you aught</A><br>
-<A NAME=1.3.44>That man may question? You seem to understand me,</A><br>
-<A NAME=1.3.45>By each at once her chappy finger laying</A><br>
-<A NAME=1.3.46>Upon her skinny lips: you should be women,</A><br>
-<A NAME=1.3.47>And yet your beards forbid me to interpret</A><br>
-<A NAME=1.3.48>That you are so.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.49> Speak, if you can: what are you?</A><br>
-</blockquote>
-
-<A NAME=speech16><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.50>All hail, Macbeth! hail to thee, thane of Glamis!</A><br>
-</blockquote>
-
-<A NAME=speech17><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.51>All hail, Macbeth, hail to thee, thane of Cawdor!</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.52>All hail, Macbeth, thou shalt be king hereafter!</A><br>
-</blockquote>
-
-<A NAME=speech19><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.53>Good sir, why do you start; and seem to fear</A><br>
-<A NAME=1.3.54>Things that do sound so fair? I' the name of truth,</A><br>
-<A NAME=1.3.55>Are ye fantastical, or that indeed</A><br>
-<A NAME=1.3.56>Which outwardly ye show? My noble partner</A><br>
-<A NAME=1.3.57>You greet with present grace and great prediction</A><br>
-<A NAME=1.3.58>Of noble having and of royal hope,</A><br>
-<A NAME=1.3.59>That he seems rapt withal: to me you speak not.</A><br>
-<A NAME=1.3.60>If you can look into the seeds of time,</A><br>
-<A NAME=1.3.61>And say which grain will grow and which will not,</A><br>
-<A NAME=1.3.62>Speak then to me, who neither beg nor fear</A><br>
-<A NAME=1.3.63>Your favours nor your hate.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.64>Hail!</A><br>
-</blockquote>
-
-<A NAME=speech21><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.65>Hail!</A><br>
-</blockquote>
-
-<A NAME=speech22><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.66>Hail!</A><br>
-</blockquote>
-
-<A NAME=speech23><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.67>Lesser than Macbeth, and greater.</A><br>
-</blockquote>
-
-<A NAME=speech24><b>Second Witch</b></a>
-<blockquote>
-<A NAME=1.3.68>Not so happy, yet much happier.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>Third Witch</b></a>
-<blockquote>
-<A NAME=1.3.69>Thou shalt get kings, though thou be none:</A><br>
-<A NAME=1.3.70>So all hail, Macbeth and Banquo!</A><br>
-</blockquote>
-
-<A NAME=speech26><b>First Witch</b></a>
-<blockquote>
-<A NAME=1.3.71>Banquo and Macbeth, all hail!</A><br>
-</blockquote>
-
-<A NAME=speech27><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.72>Stay, you imperfect speakers, tell me more:</A><br>
-<A NAME=1.3.73>By Sinel's death I know I am thane of Glamis;</A><br>
-<A NAME=1.3.74>But how of Cawdor? the thane of Cawdor lives,</A><br>
-<A NAME=1.3.75>A prosperous gentleman; and to be king</A><br>
-<A NAME=1.3.76>Stands not within the prospect of belief,</A><br>
-<A NAME=1.3.77>No more than to be Cawdor. Say from whence</A><br>
-<A NAME=1.3.78>You owe this strange intelligence? or why</A><br>
-<A NAME=1.3.79>Upon this blasted heath you stop our way</A><br>
-<A NAME=1.3.80>With such prophetic greeting? Speak, I charge you.</A><br>
-<p><i>Witches vanish</i></p>
-</blockquote>
-
-<A NAME=speech28><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.81>The earth hath bubbles, as the water has,</A><br>
-<A NAME=1.3.82>And these are of them. Whither are they vanish'd?</A><br>
-</blockquote>
-
-<A NAME=speech29><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.83>Into the air; and what seem'd corporal melted</A><br>
-<A NAME=1.3.84>As breath into the wind. Would they had stay'd!</A><br>
-</blockquote>
-
-<A NAME=speech30><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.85>Were such things here as we do speak about?</A><br>
-<A NAME=1.3.86>Or have we eaten on the insane root</A><br>
-<A NAME=1.3.87>That takes the reason prisoner?</A><br>
-</blockquote>
-
-<A NAME=speech31><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.88>Your children shall be kings.</A><br>
-</blockquote>
-
-<A NAME=speech32><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.89>You shall be king.</A><br>
-</blockquote>
-
-<A NAME=speech33><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.90>And thane of Cawdor too: went it not so?</A><br>
-</blockquote>
-
-<A NAME=speech34><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.91>To the selfsame tune and words. Who's here?</A><br>
-<p><i>Enter ROSS and ANGUS</i></p>
-</blockquote>
-
-<A NAME=speech35><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.3.92>The king hath happily received, Macbeth,</A><br>
-<A NAME=1.3.93>The news of thy success; and when he reads</A><br>
-<A NAME=1.3.94>Thy personal venture in the rebels' fight,</A><br>
-<A NAME=1.3.95>His wonders and his praises do contend</A><br>
-<A NAME=1.3.96>Which should be thine or his: silenced with that,</A><br>
-<A NAME=1.3.97>In viewing o'er the rest o' the selfsame day,</A><br>
-<A NAME=1.3.98>He finds thee in the stout Norweyan ranks,</A><br>
-<A NAME=1.3.99>Nothing afeard of what thyself didst make,</A><br>
-<A NAME=1.3.100>Strange images of death. As thick as hail</A><br>
-<A NAME=1.3.101>Came post with post; and every one did bear</A><br>
-<A NAME=1.3.102>Thy praises in his kingdom's great defence,</A><br>
-<A NAME=1.3.103>And pour'd them down before him.</A><br>
-</blockquote>
-
-<A NAME=speech36><b>ANGUS</b></a>
-<blockquote>
-<A NAME=1.3.104>We are sent</A><br>
-<A NAME=1.3.105>To give thee from our royal master thanks;</A><br>
-<A NAME=1.3.106>Only to herald thee into his sight,</A><br>
-<A NAME=1.3.107>Not pay thee.</A><br>
-</blockquote>
-
-<A NAME=speech37><b>ROSS</b></a>
-<blockquote>
-<A NAME=1.3.108>And, for an earnest of a greater honour,</A><br>
-<A NAME=1.3.109>He bade me, from him, call thee thane of Cawdor:</A><br>
-<A NAME=1.3.110>In which addition, hail, most worthy thane!</A><br>
-<A NAME=1.3.111>For it is thine.</A><br>
-</blockquote>
-
-<A NAME=speech38><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.112> What, can the devil speak true?</A><br>
-</blockquote>
-
-<A NAME=speech39><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.113>The thane of Cawdor lives: why do you dress me</A><br>
-<A NAME=1.3.114>In borrow'd robes?</A><br>
-</blockquote>
-
-<A NAME=speech40><b>ANGUS</b></a>
-<blockquote>
-<A NAME=1.3.115> Who was the thane lives yet;</A><br>
-<A NAME=1.3.116>But under heavy judgment bears that life</A><br>
-<A NAME=1.3.117>Which he deserves to lose. Whether he was combined</A><br>
-<A NAME=1.3.118>With those of Norway, or did line the rebel</A><br>
-<A NAME=1.3.119>With hidden help and vantage, or that with both</A><br>
-<A NAME=1.3.120>He labour'd in his country's wreck, I know not;</A><br>
-<A NAME=1.3.121>But treasons capital, confess'd and proved,</A><br>
-<A NAME=1.3.122>Have overthrown him.</A><br>
-</blockquote>
-
-<A NAME=speech41><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.123>[Aside] Glamis, and thane of Cawdor!</A><br>
-<A NAME=1.3.124>The greatest is behind.</A><br>
-<p><i>To ROSS and ANGUS</i></p>
-<A NAME=1.3.125>Thanks for your pains.</A><br>
-<p><i>To BANQUO</i></p>
-<A NAME=1.3.126>Do you not hope your children shall be kings,</A><br>
-<A NAME=1.3.127>When those that gave the thane of Cawdor to me</A><br>
-<A NAME=1.3.128>Promised no less to them?</A><br>
-</blockquote>
-
-<A NAME=speech42><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.129>That trusted home</A><br>
-<A NAME=1.3.130>Might yet enkindle you unto the crown,</A><br>
-<A NAME=1.3.131>Besides the thane of Cawdor. But 'tis strange:</A><br>
-<A NAME=1.3.132>And oftentimes, to win us to our harm,</A><br>
-<A NAME=1.3.133>The instruments of darkness tell us truths,</A><br>
-<A NAME=1.3.134>Win us with honest trifles, to betray's</A><br>
-<A NAME=1.3.135>In deepest consequence.</A><br>
-<A NAME=1.3.136>Cousins, a word, I pray you.</A><br>
-</blockquote>
-
-<A NAME=speech43><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.137>[Aside] Two truths are told,</A><br>
-<A NAME=1.3.138>As happy prologues to the swelling act</A><br>
-<A NAME=1.3.139>Of the imperial theme.--I thank you, gentlemen.</A><br>
-<p><i>Aside</i></p>
-<A NAME=1.3.140>Cannot be ill, cannot be good: if ill,</A><br>
-<A NAME=1.3.141>Why hath it given me earnest of success,</A><br>
-<A NAME=1.3.142>Commencing in a truth? I am thane of Cawdor:</A><br>
-<A NAME=1.3.143>If good, why do I yield to that suggestion</A><br>
-<A NAME=1.3.144>Whose horrid image doth unfix my hair</A><br>
-<A NAME=1.3.145>And make my seated heart knock at my ribs,</A><br>
-<A NAME=1.3.146>Against the use of nature? Present fears</A><br>
-<A NAME=1.3.147>Are less than horrible imaginings:</A><br>
-<A NAME=1.3.148>My thought, whose murder yet is but fantastical,</A><br>
-<A NAME=1.3.149>Shakes so my single state of man that function</A><br>
-<A NAME=1.3.150>Is smother'd in surmise, and nothing is</A><br>
-<A NAME=1.3.151>But what is not.</A><br>
-</blockquote>
-
-<A NAME=speech44><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.152> Look, how our partner's rapt.</A><br>
-</blockquote>
-
-<A NAME=speech45><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.153>[Aside] If chance will have me king, why, chance may crown me,</A><br>
-<A NAME=1.3.154>Without my stir.</A><br>
-</blockquote>
-
-<A NAME=speech46><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.155> New horrors come upon him,</A><br>
-<A NAME=1.3.156>Like our strange garments, cleave not to their mould</A><br>
-<A NAME=1.3.157>But with the aid of use.</A><br>
-</blockquote>
-
-<A NAME=speech47><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.158>[Aside] Come what come may,</A><br>
-<A NAME=1.3.159>Time and the hour runs through the roughest day.</A><br>
-</blockquote>
-
-<A NAME=speech48><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.160>Worthy Macbeth, we stay upon your leisure.</A><br>
-</blockquote>
-
-<A NAME=speech49><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.161>Give me your favour: my dull brain was wrought</A><br>
-<A NAME=1.3.162>With things forgotten. Kind gentlemen, your pains</A><br>
-<A NAME=1.3.163>Are register'd where every day I turn</A><br>
-<A NAME=1.3.164>The leaf to read them. Let us toward the king.</A><br>
-<A NAME=1.3.165>Think upon what hath chanced, and, at more time,</A><br>
-<A NAME=1.3.166>The interim having weigh'd it, let us speak</A><br>
-<A NAME=1.3.167>Our free hearts each to other.</A><br>
-</blockquote>
-
-<A NAME=speech50><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.3.168>Very gladly.</A><br>
-</blockquote>
-
-<A NAME=speech51><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.3.169>Till then, enough. Come, friends.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE IV. Forres. The palace.</h3>
-<p><blockquote>
-<i>Flourish. Enter DUNCAN, MALCOLM, DONALBAIN, LENNOX, and Attendants</i>
-</blockquote>
-
-<A NAME=speech1><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.1>Is execution done on Cawdor? Are not</A><br>
-<A NAME=1.4.2>Those in commission yet return'd?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=1.4.3>My liege,</A><br>
-<A NAME=1.4.4>They are not yet come back. But I have spoke</A><br>
-<A NAME=1.4.5>With one that saw him die: who did report</A><br>
-<A NAME=1.4.6>That very frankly he confess'd his treasons,</A><br>
-<A NAME=1.4.7>Implored your highness' pardon and set forth</A><br>
-<A NAME=1.4.8>A deep repentance: nothing in his life</A><br>
-<A NAME=1.4.9>Became him like the leaving it; he died</A><br>
-<A NAME=1.4.10>As one that had been studied in his death</A><br>
-<A NAME=1.4.11>To throw away the dearest thing he owed,</A><br>
-<A NAME=1.4.12>As 'twere a careless trifle.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.13>There's no art</A><br>
-<A NAME=1.4.14>To find the mind's construction in the face:</A><br>
-<A NAME=1.4.15>He was a gentleman on whom I built</A><br>
-<A NAME=1.4.16>An absolute trust.</A><br>
-<p><i>Enter MACBETH, BANQUO, ROSS, and ANGUS</i></p>
-<A NAME=1.4.17>O worthiest cousin!</A><br>
-<A NAME=1.4.18>The sin of my ingratitude even now</A><br>
-<A NAME=1.4.19>Was heavy on me: thou art so far before</A><br>
-<A NAME=1.4.20>That swiftest wing of recompense is slow</A><br>
-<A NAME=1.4.21>To overtake thee. Would thou hadst less deserved,</A><br>
-<A NAME=1.4.22>That the proportion both of thanks and payment</A><br>
-<A NAME=1.4.23>Might have been mine! only I have left to say,</A><br>
-<A NAME=1.4.24>More is thy due than more than all can pay.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.4.25>The service and the loyalty I owe,</A><br>
-<A NAME=1.4.26>In doing it, pays itself. Your highness' part</A><br>
-<A NAME=1.4.27>Is to receive our duties; and our duties</A><br>
-<A NAME=1.4.28>Are to your throne and state children and servants,</A><br>
-<A NAME=1.4.29>Which do but what they should, by doing every thing</A><br>
-<A NAME=1.4.30>Safe toward your love and honour.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.31>Welcome hither:</A><br>
-<A NAME=1.4.32>I have begun to plant thee, and will labour</A><br>
-<A NAME=1.4.33>To make thee full of growing. Noble Banquo,</A><br>
-<A NAME=1.4.34>That hast no less deserved, nor must be known</A><br>
-<A NAME=1.4.35>No less to have done so, let me enfold thee</A><br>
-<A NAME=1.4.36>And hold thee to my heart.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.4.37>There if I grow,</A><br>
-<A NAME=1.4.38>The harvest is your own.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.39>My plenteous joys,</A><br>
-<A NAME=1.4.40>Wanton in fulness, seek to hide themselves</A><br>
-<A NAME=1.4.41>In drops of sorrow. Sons, kinsmen, thanes,</A><br>
-<A NAME=1.4.42>And you whose places are the nearest, know</A><br>
-<A NAME=1.4.43>We will establish our estate upon</A><br>
-<A NAME=1.4.44>Our eldest, Malcolm, whom we name hereafter</A><br>
-<A NAME=1.4.45>The Prince of Cumberland; which honour must</A><br>
-<A NAME=1.4.46>Not unaccompanied invest him only,</A><br>
-<A NAME=1.4.47>But signs of nobleness, like stars, shall shine</A><br>
-<A NAME=1.4.48>On all deservers. From hence to Inverness,</A><br>
-<A NAME=1.4.49>And bind us further to you.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.4.50>The rest is labour, which is not used for you:</A><br>
-<A NAME=1.4.51>I'll be myself the harbinger and make joyful</A><br>
-<A NAME=1.4.52>The hearing of my wife with your approach;</A><br>
-<A NAME=1.4.53>So humbly take my leave.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.54>My worthy Cawdor!</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.4.55>[Aside] The Prince of Cumberland! that is a step</A><br>
-<A NAME=1.4.56>On which I must fall down, or else o'erleap,</A><br>
-<A NAME=1.4.57>For in my way it lies. Stars, hide your fires;</A><br>
-<A NAME=1.4.58>Let not light see my black and deep desires:</A><br>
-<A NAME=1.4.59>The eye wink at the hand; yet let that be,</A><br>
-<A NAME=1.4.60>Which the eye fears, when it is done, to see.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech11><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.4.61>True, worthy Banquo; he is full so valiant,</A><br>
-<A NAME=1.4.62>And in his commendations I am fed;</A><br>
-<A NAME=1.4.63>It is a banquet to me. Let's after him,</A><br>
-<A NAME=1.4.64>Whose care is gone before to bid us welcome:</A><br>
-<A NAME=1.4.65>It is a peerless kinsman.</A><br>
-<p><i>Flourish. Exeunt</i></p>
-</blockquote>
-<h3>SCENE V. Inverness. Macbeth's castle.</h3>
-<p><blockquote>
-<i>Enter LADY MACBETH, reading a letter</i>
-</blockquote>
-
-<A NAME=speech1><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.1>'They met me in the day of success: and I have</A><br>
-<A NAME=1.5.2>learned by the perfectest report, they have more in</A><br>
-<A NAME=1.5.3>them than mortal knowledge. When I burned in desire</A><br>
-<A NAME=1.5.4>to question them further, they made themselves air,</A><br>
-<A NAME=1.5.5>into which they vanished. Whiles I stood rapt in</A><br>
-<A NAME=1.5.6>the wonder of it, came missives from the king, who</A><br>
-<A NAME=1.5.7>all-hailed me 'Thane of Cawdor;' by which title,</A><br>
-<A NAME=1.5.8>before, these weird sisters saluted me, and referred</A><br>
-<A NAME=1.5.9>me to the coming on of time, with 'Hail, king that</A><br>
-<A NAME=1.5.10>shalt be!' This have I thought good to deliver</A><br>
-<A NAME=1.5.11>thee, my dearest partner of greatness, that thou</A><br>
-<A NAME=1.5.12>mightst not lose the dues of rejoicing, by being</A><br>
-<A NAME=1.5.13>ignorant of what greatness is promised thee. Lay it</A><br>
-<A NAME=1.5.14>to thy heart, and farewell.'</A><br>
-<A NAME=1.5.15>Glamis thou art, and Cawdor; and shalt be</A><br>
-<A NAME=1.5.16>What thou art promised: yet do I fear thy nature;</A><br>
-<A NAME=1.5.17>It is too full o' the milk of human kindness</A><br>
-<A NAME=1.5.18>To catch the nearest way: thou wouldst be great;</A><br>
-<A NAME=1.5.19>Art not without ambition, but without</A><br>
-<A NAME=1.5.20>The illness should attend it: what thou wouldst highly,</A><br>
-<A NAME=1.5.21>That wouldst thou holily; wouldst not play false,</A><br>
-<A NAME=1.5.22>And yet wouldst wrongly win: thou'ldst have, great Glamis,</A><br>
-<A NAME=1.5.23>That which cries 'Thus thou must do, if thou have it;</A><br>
-<A NAME=1.5.24>And that which rather thou dost fear to do</A><br>
-<A NAME=1.5.25>Than wishest should be undone.' Hie thee hither,</A><br>
-<A NAME=1.5.26>That I may pour my spirits in thine ear;</A><br>
-<A NAME=1.5.27>And chastise with the valour of my tongue</A><br>
-<A NAME=1.5.28>All that impedes thee from the golden round,</A><br>
-<A NAME=1.5.29>Which fate and metaphysical aid doth seem</A><br>
-<A NAME=1.5.30>To have thee crown'd withal.</A><br>
-<p><i>Enter a Messenger</i></p>
-<A NAME=1.5.31>What is your tidings?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Messenger</b></a>
-<blockquote>
-<A NAME=1.5.32>The king comes here to-night.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.33>Thou'rt mad to say it:</A><br>
-<A NAME=1.5.34>Is not thy master with him? who, were't so,</A><br>
-<A NAME=1.5.35>Would have inform'd for preparation.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>Messenger</b></a>
-<blockquote>
-<A NAME=1.5.36>So please you, it is true: our thane is coming:</A><br>
-<A NAME=1.5.37>One of my fellows had the speed of him,</A><br>
-<A NAME=1.5.38>Who, almost dead for breath, had scarcely more</A><br>
-<A NAME=1.5.39>Than would make up his message.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.40>Give him tending;</A><br>
-<A NAME=1.5.41>He brings great news.</A><br>
-<p><i>Exit Messenger</i></p>
-<A NAME=1.5.42>The raven himself is hoarse</A><br>
-<A NAME=1.5.43>That croaks the fatal entrance of Duncan</A><br>
-<A NAME=1.5.44>Under my battlements. Come, you spirits</A><br>
-<A NAME=1.5.45>That tend on mortal thoughts, unsex me here,</A><br>
-<A NAME=1.5.46>And fill me from the crown to the toe top-full</A><br>
-<A NAME=1.5.47>Of direst cruelty! make thick my blood;</A><br>
-<A NAME=1.5.48>Stop up the access and passage to remorse,</A><br>
-<A NAME=1.5.49>That no compunctious visitings of nature</A><br>
-<A NAME=1.5.50>Shake my fell purpose, nor keep peace between</A><br>
-<A NAME=1.5.51>The effect and it! Come to my woman's breasts,</A><br>
-<A NAME=1.5.52>And take my milk for gall, you murdering ministers,</A><br>
-<A NAME=1.5.53>Wherever in your sightless substances</A><br>
-<A NAME=1.5.54>You wait on nature's mischief! Come, thick night,</A><br>
-<A NAME=1.5.55>And pall thee in the dunnest smoke of hell,</A><br>
-<A NAME=1.5.56>That my keen knife see not the wound it makes,</A><br>
-<A NAME=1.5.57>Nor heaven peep through the blanket of the dark,</A><br>
-<A NAME=1.5.58>To cry 'Hold, hold!'</A><br>
-<p><i>Enter MACBETH</i></p>
-<A NAME=1.5.59>Great Glamis! worthy Cawdor!</A><br>
-<A NAME=1.5.60>Greater than both, by the all-hail hereafter!</A><br>
-<A NAME=1.5.61>Thy letters have transported me beyond</A><br>
-<A NAME=1.5.62>This ignorant present, and I feel now</A><br>
-<A NAME=1.5.63>The future in the instant.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.64>My dearest love,</A><br>
-<A NAME=1.5.65>Duncan comes here to-night.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.66>And when goes hence?</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.67>To-morrow, as he purposes.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.68>O, never</A><br>
-<A NAME=1.5.69>Shall sun that morrow see!</A><br>
-<A NAME=1.5.70>Your face, my thane, is as a book where men</A><br>
-<A NAME=1.5.71>May read strange matters. To beguile the time,</A><br>
-<A NAME=1.5.72>Look like the time; bear welcome in your eye,</A><br>
-<A NAME=1.5.73>Your hand, your tongue: look like the innocent flower,</A><br>
-<A NAME=1.5.74>But be the serpent under't. He that's coming</A><br>
-<A NAME=1.5.75>Must be provided for: and you shall put</A><br>
-<A NAME=1.5.76>This night's great business into my dispatch;</A><br>
-<A NAME=1.5.77>Which shall to all our nights and days to come</A><br>
-<A NAME=1.5.78>Give solely sovereign sway and masterdom.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.79>We will speak further.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.5.80>Only look up clear;</A><br>
-<A NAME=1.5.81>To alter favour ever is to fear:</A><br>
-<A NAME=1.5.82>Leave all the rest to me.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE VI. Before Macbeth's castle.</h3>
-<p><blockquote>
-<i>Hautboys and torches. Enter DUNCAN, MALCOLM, DONALBAIN, BANQUO, LENNOX, MACDUFF, ROSS, ANGUS, and Attendants</i>
-</blockquote>
-
-<A NAME=speech1><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.6.1>This castle hath a pleasant seat; the air</A><br>
-<A NAME=1.6.2>Nimbly and sweetly recommends itself</A><br>
-<A NAME=1.6.3>Unto our gentle senses.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>BANQUO</b></a>
-<blockquote>
-<A NAME=1.6.4>This guest of summer,</A><br>
-<A NAME=1.6.5>The temple-haunting martlet, does approve,</A><br>
-<A NAME=1.6.6>By his loved mansionry, that the heaven's breath</A><br>
-<A NAME=1.6.7>Smells wooingly here: no jutty, frieze,</A><br>
-<A NAME=1.6.8>Buttress, nor coign of vantage, but this bird</A><br>
-<A NAME=1.6.9>Hath made his pendent bed and procreant cradle:</A><br>
-<A NAME=1.6.10>Where they most breed and haunt, I have observed,</A><br>
-<A NAME=1.6.11>The air is delicate.</A><br>
-<p><i>Enter LADY MACBETH</i></p>
-</blockquote>
-
-<A NAME=speech3><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.6.12>See, see, our honour'd hostess!</A><br>
-<A NAME=1.6.13>The love that follows us sometime is our trouble,</A><br>
-<A NAME=1.6.14>Which still we thank as love. Herein I teach you</A><br>
-<A NAME=1.6.15>How you shall bid God 'ild us for your pains,</A><br>
-<A NAME=1.6.16>And thank us for your trouble.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.6.17>All our service</A><br>
-<A NAME=1.6.18>In every point twice done and then done double</A><br>
-<A NAME=1.6.19>Were poor and single business to contend</A><br>
-<A NAME=1.6.20>Against those honours deep and broad wherewith</A><br>
-<A NAME=1.6.21>Your majesty loads our house: for those of old,</A><br>
-<A NAME=1.6.22>And the late dignities heap'd up to them,</A><br>
-<A NAME=1.6.23>We rest your hermits.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.6.24>Where's the thane of Cawdor?</A><br>
-<A NAME=1.6.25>We coursed him at the heels, and had a purpose</A><br>
-<A NAME=1.6.26>To be his purveyor: but he rides well;</A><br>
-<A NAME=1.6.27>And his great love, sharp as his spur, hath holp him</A><br>
-<A NAME=1.6.28>To his home before us. Fair and noble hostess,</A><br>
-<A NAME=1.6.29>We are your guest to-night.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.6.30>Your servants ever</A><br>
-<A NAME=1.6.31>Have theirs, themselves and what is theirs, in compt,</A><br>
-<A NAME=1.6.32>To make their audit at your highness' pleasure,</A><br>
-<A NAME=1.6.33>Still to return your own.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>DUNCAN</b></a>
-<blockquote>
-<A NAME=1.6.34>Give me your hand;</A><br>
-<A NAME=1.6.35>Conduct me to mine host: we love him highly,</A><br>
-<A NAME=1.6.36>And shall continue our graces towards him.</A><br>
-<A NAME=1.6.37>By your leave, hostess.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE VII. Macbeth's castle.</h3>
-<p><blockquote>
-<i>Hautboys and torches. Enter a Sewer, and divers Servants with dishes and service, and pass over the stage. Then enter MACBETH</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.1>If it were done when 'tis done, then 'twere well</A><br>
-<A NAME=1.7.2>It were done quickly: if the assassination</A><br>
-<A NAME=1.7.3>Could trammel up the consequence, and catch</A><br>
-<A NAME=1.7.4>With his surcease success; that but this blow</A><br>
-<A NAME=1.7.5>Might be the be-all and the end-all here,</A><br>
-<A NAME=1.7.6>But here, upon this bank and shoal of time,</A><br>
-<A NAME=1.7.7>We'ld jump the life to come. But in these cases</A><br>
-<A NAME=1.7.8>We still have judgment here; that we but teach</A><br>
-<A NAME=1.7.9>Bloody instructions, which, being taught, return</A><br>
-<A NAME=1.7.10>To plague the inventor: this even-handed justice</A><br>
-<A NAME=1.7.11>Commends the ingredients of our poison'd chalice</A><br>
-<A NAME=1.7.12>To our own lips. He's here in double trust;</A><br>
-<A NAME=1.7.13>First, as I am his kinsman and his subject,</A><br>
-<A NAME=1.7.14>Strong both against the deed; then, as his host,</A><br>
-<A NAME=1.7.15>Who should against his murderer shut the door,</A><br>
-<A NAME=1.7.16>Not bear the knife myself. Besides, this Duncan</A><br>
-<A NAME=1.7.17>Hath borne his faculties so meek, hath been</A><br>
-<A NAME=1.7.18>So clear in his great office, that his virtues</A><br>
-<A NAME=1.7.19>Will plead like angels, trumpet-tongued, against</A><br>
-<A NAME=1.7.20>The deep damnation of his taking-off;</A><br>
-<A NAME=1.7.21>And pity, like a naked new-born babe,</A><br>
-<A NAME=1.7.22>Striding the blast, or heaven's cherubim, horsed</A><br>
-<A NAME=1.7.23>Upon the sightless couriers of the air,</A><br>
-<A NAME=1.7.24>Shall blow the horrid deed in every eye,</A><br>
-<A NAME=1.7.25>That tears shall drown the wind. I have no spur</A><br>
-<A NAME=1.7.26>To prick the sides of my intent, but only</A><br>
-<A NAME=1.7.27>Vaulting ambition, which o'erleaps itself</A><br>
-<A NAME=1.7.28>And falls on the other.</A><br>
-<p><i>Enter LADY MACBETH</i></p>
-<A NAME=1.7.29>How now! what news?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.30>He has almost supp'd: why have you left the chamber?</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.31>Hath he ask'd for me?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.32>Know you not he has?</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.33>We will proceed no further in this business:</A><br>
-<A NAME=1.7.34>He hath honour'd me of late; and I have bought</A><br>
-<A NAME=1.7.35>Golden opinions from all sorts of people,</A><br>
-<A NAME=1.7.36>Which would be worn now in their newest gloss,</A><br>
-<A NAME=1.7.37>Not cast aside so soon.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.38>Was the hope drunk</A><br>
-<A NAME=1.7.39>Wherein you dress'd yourself? hath it slept since?</A><br>
-<A NAME=1.7.40>And wakes it now, to look so green and pale</A><br>
-<A NAME=1.7.41>At what it did so freely? From this time</A><br>
-<A NAME=1.7.42>Such I account thy love. Art thou afeard</A><br>
-<A NAME=1.7.43>To be the same in thine own act and valour</A><br>
-<A NAME=1.7.44>As thou art in desire? Wouldst thou have that</A><br>
-<A NAME=1.7.45>Which thou esteem'st the ornament of life,</A><br>
-<A NAME=1.7.46>And live a coward in thine own esteem,</A><br>
-<A NAME=1.7.47>Letting 'I dare not' wait upon 'I would,'</A><br>
-<A NAME=1.7.48>Like the poor cat i' the adage?</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.49>Prithee, peace:</A><br>
-<A NAME=1.7.50>I dare do all that may become a man;</A><br>
-<A NAME=1.7.51>Who dares do more is none.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.52>What beast was't, then,</A><br>
-<A NAME=1.7.53>That made you break this enterprise to me?</A><br>
-<A NAME=1.7.54>When you durst do it, then you were a man;</A><br>
-<A NAME=1.7.55>And, to be more than what you were, you would</A><br>
-<A NAME=1.7.56>Be so much more the man. Nor time nor place</A><br>
-<A NAME=1.7.57>Did then adhere, and yet you would make both:</A><br>
-<A NAME=1.7.58>They have made themselves, and that their fitness now</A><br>
-<A NAME=1.7.59>Does unmake you. I have given suck, and know</A><br>
-<A NAME=1.7.60>How tender 'tis to love the babe that milks me:</A><br>
-<A NAME=1.7.61>I would, while it was smiling in my face,</A><br>
-<A NAME=1.7.62>Have pluck'd my nipple from his boneless gums,</A><br>
-<A NAME=1.7.63>And dash'd the brains out, had I so sworn as you</A><br>
-<A NAME=1.7.64>Have done to this.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.65> If we should fail?</A><br>
-</blockquote>
-
-<A NAME=speech10><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.66>We fail!</A><br>
-<A NAME=1.7.67>But screw your courage to the sticking-place,</A><br>
-<A NAME=1.7.68>And we'll not fail. When Duncan is asleep--</A><br>
-<A NAME=1.7.69>Whereto the rather shall his day's hard journey</A><br>
-<A NAME=1.7.70>Soundly invite him--his two chamberlains</A><br>
-<A NAME=1.7.71>Will I with wine and wassail so convince</A><br>
-<A NAME=1.7.72>That memory, the warder of the brain,</A><br>
-<A NAME=1.7.73>Shall be a fume, and the receipt of reason</A><br>
-<A NAME=1.7.74>A limbeck only: when in swinish sleep</A><br>
-<A NAME=1.7.75>Their drenched natures lie as in a death,</A><br>
-<A NAME=1.7.76>What cannot you and I perform upon</A><br>
-<A NAME=1.7.77>The unguarded Duncan? what not put upon</A><br>
-<A NAME=1.7.78>His spongy officers, who shall bear the guilt</A><br>
-<A NAME=1.7.79>Of our great quell?</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.80>Bring forth men-children only;</A><br>
-<A NAME=1.7.81>For thy undaunted mettle should compose</A><br>
-<A NAME=1.7.82>Nothing but males. Will it not be received,</A><br>
-<A NAME=1.7.83>When we have mark'd with blood those sleepy two</A><br>
-<A NAME=1.7.84>Of his own chamber and used their very daggers,</A><br>
-<A NAME=1.7.85>That they have done't?</A><br>
-</blockquote>
-
-<A NAME=speech12><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.86>Who dares receive it other,</A><br>
-<A NAME=1.7.87>As we shall make our griefs and clamour roar</A><br>
-<A NAME=1.7.88>Upon his death?</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MACBETH</b></a>
-<blockquote>
-<A NAME=1.7.89> I am settled, and bend up</A><br>
-<A NAME=1.7.90>Each corporal agent to this terrible feat.</A><br>
-<A NAME=1.7.91>Away, and mock the time with fairest show:</A><br>
-<A NAME=1.7.92>False face must hide what the false heart doth know.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote><p>
-<H3>ACT II</h3>
-<h3>SCENE I. Court of Macbeth's castle.</h3>
-<p><blockquote>
-<i>Enter BANQUO, and FLEANCE bearing a torch before him</i>
-</blockquote>
-
-<A NAME=speech1><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.1>How goes the night, boy?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>FLEANCE</b></a>
-<blockquote>
-<A NAME=2.1.2>The moon is down; I have not heard the clock.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.3>And she goes down at twelve.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>FLEANCE</b></a>
-<blockquote>
-<A NAME=2.1.4>I take't, 'tis later, sir.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.5>Hold, take my sword. There's husbandry in heaven;</A><br>
-<A NAME=2.1.6>Their candles are all out. Take thee that too.</A><br>
-<A NAME=2.1.7>A heavy summons lies like lead upon me,</A><br>
-<A NAME=2.1.8>And yet I would not sleep: merciful powers,</A><br>
-<A NAME=2.1.9>Restrain in me the cursed thoughts that nature</A><br>
-<A NAME=2.1.10>Gives way to in repose!</A><br>
-<p><i>Enter MACBETH, and a Servant with a torch</i></p>
-<A NAME=2.1.11>Give me my sword.</A><br>
-<A NAME=2.1.12>Who's there?</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.13>A friend.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.14>What, sir, not yet at rest? The king's a-bed:</A><br>
-<A NAME=2.1.15>He hath been in unusual pleasure, and</A><br>
-<A NAME=2.1.16>Sent forth great largess to your offices.</A><br>
-<A NAME=2.1.17>This diamond he greets your wife withal,</A><br>
-<A NAME=2.1.18>By the name of most kind hostess; and shut up</A><br>
-<A NAME=2.1.19>In measureless content.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.20>Being unprepared,</A><br>
-<A NAME=2.1.21>Our will became the servant to defect;</A><br>
-<A NAME=2.1.22>Which else should free have wrought.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.23>All's well.</A><br>
-<A NAME=2.1.24>I dreamt last night of the three weird sisters:</A><br>
-<A NAME=2.1.25>To you they have show'd some truth.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.26>I think not of them:</A><br>
-<A NAME=2.1.27>Yet, when we can entreat an hour to serve,</A><br>
-<A NAME=2.1.28>We would spend it in some words upon that business,</A><br>
-<A NAME=2.1.29>If you would grant the time.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.30>At your kind'st leisure.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.31>If you shall cleave to my consent, when 'tis,</A><br>
-<A NAME=2.1.32>It shall make honour for you.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.33>So I lose none</A><br>
-<A NAME=2.1.34>In seeking to augment it, but still keep</A><br>
-<A NAME=2.1.35>My bosom franchised and allegiance clear,</A><br>
-<A NAME=2.1.36>I shall be counsell'd.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.37>Good repose the while!</A><br>
-</blockquote>
-
-<A NAME=speech15><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.1.38>Thanks, sir: the like to you!</A><br>
-<p><i>Exeunt BANQUO and FLEANCE</i></p>
-</blockquote>
-
-<A NAME=speech16><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.1.39>Go bid thy mistress, when my drink is ready,</A><br>
-<A NAME=2.1.40>She strike upon the bell. Get thee to bed.</A><br>
-<p><i>Exit Servant</i></p>
-<A NAME=2.1.41>Is this a dagger which I see before me,</A><br>
-<A NAME=2.1.42>The handle toward my hand? Come, let me clutch thee.</A><br>
-<A NAME=2.1.43>I have thee not, and yet I see thee still.</A><br>
-<A NAME=2.1.44>Art thou not, fatal vision, sensible</A><br>
-<A NAME=2.1.45>To feeling as to sight? or art thou but</A><br>
-<A NAME=2.1.46>A dagger of the mind, a false creation,</A><br>
-<A NAME=2.1.47>Proceeding from the heat-oppressed brain?</A><br>
-<A NAME=2.1.48>I see thee yet, in form as palpable</A><br>
-<A NAME=2.1.49>As this which now I draw.</A><br>
-<A NAME=2.1.50>Thou marshall'st me the way that I was going;</A><br>
-<A NAME=2.1.51>And such an instrument I was to use.</A><br>
-<A NAME=2.1.52>Mine eyes are made the fools o' the other senses,</A><br>
-<A NAME=2.1.53>Or else worth all the rest; I see thee still,</A><br>
-<A NAME=2.1.54>And on thy blade and dudgeon gouts of blood,</A><br>
-<A NAME=2.1.55>Which was not so before. There's no such thing:</A><br>
-<A NAME=2.1.56>It is the bloody business which informs</A><br>
-<A NAME=2.1.57>Thus to mine eyes. Now o'er the one halfworld</A><br>
-<A NAME=2.1.58>Nature seems dead, and wicked dreams abuse</A><br>
-<A NAME=2.1.59>The curtain'd sleep; witchcraft celebrates</A><br>
-<A NAME=2.1.60>Pale Hecate's offerings, and wither'd murder,</A><br>
-<A NAME=2.1.61>Alarum'd by his sentinel, the wolf,</A><br>
-<A NAME=2.1.62>Whose howl's his watch, thus with his stealthy pace.</A><br>
-<A NAME=2.1.63>With Tarquin's ravishing strides, towards his design</A><br>
-<A NAME=2.1.64>Moves like a ghost. Thou sure and firm-set earth,</A><br>
-<A NAME=2.1.65>Hear not my steps, which way they walk, for fear</A><br>
-<A NAME=2.1.66>Thy very stones prate of my whereabout,</A><br>
-<A NAME=2.1.67>And take the present horror from the time,</A><br>
-<A NAME=2.1.68>Which now suits with it. Whiles I threat, he lives:</A><br>
-<A NAME=2.1.69>Words to the heat of deeds too cold breath gives.</A><br>
-<p><i>A bell rings</i></p>
-<A NAME=2.1.70>I go, and it is done; the bell invites me.</A><br>
-<A NAME=2.1.71>Hear it not, Duncan; for it is a knell</A><br>
-<A NAME=2.1.72>That summons thee to heaven or to hell.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-<h3>SCENE II. The same.</h3>
-<p><blockquote>
-<i>Enter LADY MACBETH</i>
-</blockquote>
-
-<A NAME=speech1><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.1>That which hath made them drunk hath made me bold;</A><br>
-<A NAME=2.2.2>What hath quench'd them hath given me fire.</A><br>
-<A NAME=2.2.3>Hark! Peace!</A><br>
-<A NAME=2.2.4>It was the owl that shriek'd, the fatal bellman,</A><br>
-<A NAME=2.2.5>Which gives the stern'st good-night. He is about it:</A><br>
-<A NAME=2.2.6>The doors are open; and the surfeited grooms</A><br>
-<A NAME=2.2.7>Do mock their charge with snores: I have drugg'd</A><br>
-<A NAME=2.2.8>their possets,</A><br>
-<A NAME=2.2.9>That death and nature do contend about them,</A><br>
-<A NAME=2.2.10>Whether they live or die.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.11>[Within] Who's there? what, ho!</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.12>Alack, I am afraid they have awaked,</A><br>
-<A NAME=2.2.13>And 'tis not done. The attempt and not the deed</A><br>
-<A NAME=2.2.14>Confounds us. Hark! I laid their daggers ready;</A><br>
-<A NAME=2.2.15>He could not miss 'em. Had he not resembled</A><br>
-<A NAME=2.2.16>My father as he slept, I had done't.</A><br>
-<p><i>Enter MACBETH</i></p>
-<A NAME=2.2.17>My husband!</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.18>I have done the deed. Didst thou not hear a noise?</A><br>
-</blockquote>
-
-<A NAME=speech5><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.19>I heard the owl scream and the crickets cry.</A><br>
-<A NAME=2.2.20>Did not you speak?</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.21> When?</A><br>
-</blockquote>
-
-<A NAME=speech7><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.22>Now.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.23>As I descended?</A><br>
-</blockquote>
-
-<A NAME=speech9><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.24>Ay.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.25>Hark!</A><br>
-<A NAME=2.2.26>Who lies i' the second chamber?</A><br>
-</blockquote>
-
-<A NAME=speech11><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.27>Donalbain.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.28>This is a sorry sight.</A><br>
-<p><i>Looking on his hands</i></p>
-</blockquote>
-
-<A NAME=speech13><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.29>A foolish thought, to say a sorry sight.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.30>There's one did laugh in's sleep, and one cried</A><br>
-<A NAME=2.2.31>'Murder!'</A><br>
-<A NAME=2.2.32>That they did wake each other: I stood and heard them:</A><br>
-<A NAME=2.2.33>But they did say their prayers, and address'd them</A><br>
-<A NAME=2.2.34>Again to sleep.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.35> There are two lodged together.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.36>One cried 'God bless us!' and 'Amen' the other;</A><br>
-<A NAME=2.2.37>As they had seen me with these hangman's hands.</A><br>
-<A NAME=2.2.38>Listening their fear, I could not say 'Amen,'</A><br>
-<A NAME=2.2.39>When they did say 'God bless us!'</A><br>
-</blockquote>
-
-<A NAME=speech17><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.40>Consider it not so deeply.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.41>But wherefore could not I pronounce 'Amen'?</A><br>
-<A NAME=2.2.42>I had most need of blessing, and 'Amen'</A><br>
-<A NAME=2.2.43>Stuck in my throat.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.44>These deeds must not be thought</A><br>
-<A NAME=2.2.45>After these ways; so, it will make us mad.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.46>Methought I heard a voice cry 'Sleep no more!</A><br>
-<A NAME=2.2.47>Macbeth does murder sleep', the innocent sleep,</A><br>
-<A NAME=2.2.48>Sleep that knits up the ravell'd sleeve of care,</A><br>
-<A NAME=2.2.49>The death of each day's life, sore labour's bath,</A><br>
-<A NAME=2.2.50>Balm of hurt minds, great nature's second course,</A><br>
-<A NAME=2.2.51>Chief nourisher in life's feast,--</A><br>
-</blockquote>
-
-<A NAME=speech21><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.52>What do you mean?</A><br>
-</blockquote>
-
-<A NAME=speech22><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.53>Still it cried 'Sleep no more!' to all the house:</A><br>
-<A NAME=2.2.54>'Glamis hath murder'd sleep, and therefore Cawdor</A><br>
-<A NAME=2.2.55>Shall sleep no more; Macbeth shall sleep no more.'</A><br>
-</blockquote>
-
-<A NAME=speech23><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.56>Who was it that thus cried? Why, worthy thane,</A><br>
-<A NAME=2.2.57>You do unbend your noble strength, to think</A><br>
-<A NAME=2.2.58>So brainsickly of things. Go get some water,</A><br>
-<A NAME=2.2.59>And wash this filthy witness from your hand.</A><br>
-<A NAME=2.2.60>Why did you bring these daggers from the place?</A><br>
-<A NAME=2.2.61>They must lie there: go carry them; and smear</A><br>
-<A NAME=2.2.62>The sleepy grooms with blood.</A><br>
-</blockquote>
-
-<A NAME=speech24><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.63>I'll go no more:</A><br>
-<A NAME=2.2.64>I am afraid to think what I have done;</A><br>
-<A NAME=2.2.65>Look on't again I dare not.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.66>Infirm of purpose!</A><br>
-<A NAME=2.2.67>Give me the daggers: the sleeping and the dead</A><br>
-<A NAME=2.2.68>Are but as pictures: 'tis the eye of childhood</A><br>
-<A NAME=2.2.69>That fears a painted devil. If he do bleed,</A><br>
-<A NAME=2.2.70>I'll gild the faces of the grooms withal;</A><br>
-<A NAME=2.2.71>For it must seem their guilt.</A><br>
-<p><i>Exit. Knocking within</i></p>
-</blockquote>
-
-<A NAME=speech26><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.72>Whence is that knocking?</A><br>
-<A NAME=2.2.73>How is't with me, when every noise appals me?</A><br>
-<A NAME=2.2.74>What hands are here? ha! they pluck out mine eyes.</A><br>
-<A NAME=2.2.75>Will all great Neptune's ocean wash this blood</A><br>
-<A NAME=2.2.76>Clean from my hand? No, this my hand will rather</A><br>
-<A NAME=2.2.77>The multitudinous seas in incarnadine,</A><br>
-<A NAME=2.2.78>Making the green one red.</A><br>
-<p><i>Re-enter LADY MACBETH</i></p>
-</blockquote>
-
-<A NAME=speech27><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.79>My hands are of your colour; but I shame</A><br>
-<A NAME=2.2.80>To wear a heart so white.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.2.81>I hear a knocking</A><br>
-<A NAME=2.2.82>At the south entry: retire we to our chamber;</A><br>
-<A NAME=2.2.83>A little water clears us of this deed:</A><br>
-<A NAME=2.2.84>How easy is it, then! Your constancy</A><br>
-<A NAME=2.2.85>Hath left you unattended.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.2.86>Hark! more knocking.</A><br>
-<A NAME=2.2.87>Get on your nightgown, lest occasion call us,</A><br>
-<A NAME=2.2.88>And show us to be watchers. Be not lost</A><br>
-<A NAME=2.2.89>So poorly in your thoughts.</A><br>
-</blockquote>
-
-<A NAME=speech28><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.2.90>To know my deed, 'twere best not know myself.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.2.91>Wake Duncan with thy knocking! I would thou couldst!</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE III. The same.</h3>
-<p><blockquote>
-<i>Knocking within. Enter a Porter</i>
-</blockquote>
-
-<A NAME=speech1><b>Porter</b></a>
-<blockquote>
-<A NAME=2.3.1>Here's a knocking indeed! If a</A><br>
-<A NAME=2.3.2>man were porter of hell-gate, he should have</A><br>
-<A NAME=2.3.3>old turning the key.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.3.4>Knock,</A><br>
-<A NAME=2.3.5>knock, knock! Who's there, i' the name of</A><br>
-<A NAME=2.3.6>Beelzebub? Here's a farmer, that hanged</A><br>
-<A NAME=2.3.7>himself on the expectation of plenty: come in</A><br>
-<A NAME=2.3.8>time; have napkins enow about you; here</A><br>
-<A NAME=2.3.9>you'll sweat for't.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.3.10>Knock,</A><br>
-<A NAME=2.3.11>knock! Who's there, in the other devil's</A><br>
-<A NAME=2.3.12>name? Faith, here's an equivocator, that could</A><br>
-<A NAME=2.3.13>swear in both the scales against either scale;</A><br>
-<A NAME=2.3.14>who committed treason enough for God's sake,</A><br>
-<A NAME=2.3.15>yet could not equivocate to heaven: O, come</A><br>
-<A NAME=2.3.16>in, equivocator.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.3.17>Knock,</A><br>
-<A NAME=2.3.18>knock, knock! Who's there? Faith, here's an</A><br>
-<A NAME=2.3.19>English tailor come hither, for stealing out of</A><br>
-<A NAME=2.3.20>a French hose: come in, tailor; here you may</A><br>
-<A NAME=2.3.21>roast your goose.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.3.22>Knock,</A><br>
-<A NAME=2.3.23>knock; never at quiet! What are you? But</A><br>
-<A NAME=2.3.24>this place is too cold for hell. I'll devil-porter</A><br>
-<A NAME=2.3.25>it no further: I had thought to have let in</A><br>
-<A NAME=2.3.26>some of all professions that go the primrose</A><br>
-<A NAME=2.3.27>way to the everlasting bonfire.</A><br>
-<p><i>Knocking within</i></p>
-<A NAME=2.3.28>Anon, anon! I pray you, remember the porter.</A><br>
-<p><i>Opens the gate</i></p>
-<p><i>Enter MACDUFF and LENNOX</i></p>
-</blockquote>
-
-<A NAME=speech2><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.29>Was it so late, friend, ere you went to bed,</A><br>
-<A NAME=2.3.30>That you do lie so late?</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Porter</b></a>
-<blockquote>
-<A NAME=2.3.31>'Faith sir, we were carousing till the</A><br>
-<A NAME=2.3.32>second cock: and drink, sir, is a great</A><br>
-<A NAME=2.3.33>provoker of three things.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.34>What three things does drink especially provoke?</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Porter</b></a>
-<blockquote>
-<A NAME=2.3.35>Marry, sir, nose-painting, sleep, and</A><br>
-<A NAME=2.3.36>urine. Lechery, sir, it provokes, and unprovokes;</A><br>
-<A NAME=2.3.37>it provokes the desire, but it takes</A><br>
-<A NAME=2.3.38>away the performance: therefore, much drink</A><br>
-<A NAME=2.3.39>may be said to be an equivocator with lechery:</A><br>
-<A NAME=2.3.40>it makes him, and it mars him; it sets</A><br>
-<A NAME=2.3.41>him on, and it takes him off; it persuades him,</A><br>
-<A NAME=2.3.42>and disheartens him; makes him stand to, and</A><br>
-<A NAME=2.3.43>not stand to; in conclusion, equivocates him</A><br>
-<A NAME=2.3.44>in a sleep, and, giving him the lie, leaves him.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.45>I believe drink gave thee the lie last night.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>Porter</b></a>
-<blockquote>
-<A NAME=2.3.46>That it did, sir, i' the very throat on</A><br>
-<A NAME=2.3.47>me: but I requited him for his lie; and, I</A><br>
-<A NAME=2.3.48>think, being too strong for him, though he took</A><br>
-<A NAME=2.3.49>up my legs sometime, yet I made a shift to cast</A><br>
-<A NAME=2.3.50>him.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.51>Is thy master stirring?</A><br>
-<p><i>Enter MACBETH</i></p>
-<A NAME=2.3.52>Our knocking has awaked him; here he comes.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.53>Good morrow, noble sir.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.54>Good morrow, both.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.55>Is the king stirring, worthy thane?</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.56>Not yet.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.57>He did command me to call timely on him:</A><br>
-<A NAME=2.3.58>I have almost slipp'd the hour.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.59>I'll bring you to him.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.60>I know this is a joyful trouble to you;</A><br>
-<A NAME=2.3.61>But yet 'tis one.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.62>The labour we delight in physics pain.</A><br>
-<A NAME=2.3.63>This is the door.</A><br>
-</blockquote>
-
-<A NAME=speech17><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.64> I'll make so bold to call,</A><br>
-<A NAME=2.3.65>For 'tis my limited service.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech18><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.66>Goes the king hence to-day?</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.67>He does: he did appoint so.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.68>The night has been unruly: where we lay,</A><br>
-<A NAME=2.3.69>Our chimneys were blown down; and, as they say,</A><br>
-<A NAME=2.3.70>Lamentings heard i' the air; strange screams of death,</A><br>
-<A NAME=2.3.71>And prophesying with accents terrible</A><br>
-<A NAME=2.3.72>Of dire combustion and confused events</A><br>
-<A NAME=2.3.73>New hatch'd to the woeful time: the obscure bird</A><br>
-<A NAME=2.3.74>Clamour'd the livelong night: some say, the earth</A><br>
-<A NAME=2.3.75>Was feverous and did shake.</A><br>
-</blockquote>
-
-<A NAME=speech21><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.76>'Twas a rough night.</A><br>
-</blockquote>
-
-<A NAME=speech22><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.77>My young remembrance cannot parallel</A><br>
-<A NAME=2.3.78>A fellow to it.</A><br>
-<p><i>Re-enter MACDUFF</i></p>
-</blockquote>
-
-<A NAME=speech23><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.79>O horror, horror, horror! Tongue nor heart</A><br>
-<A NAME=2.3.80>Cannot conceive nor name thee!</A><br>
-</blockquote>
-
-<A NAME=speech24><b>MACBETH</b></a>
-
-<A NAME=speech25><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.81>What's the matter.</A><br>
-</blockquote>
-
-<A NAME=speech26><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.82>Confusion now hath made his masterpiece!</A><br>
-<A NAME=2.3.83>Most sacrilegious murder hath broke ope</A><br>
-<A NAME=2.3.84>The Lord's anointed temple, and stole thence</A><br>
-<A NAME=2.3.85>The life o' the building!</A><br>
-</blockquote>
-
-<A NAME=speech27><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.86>What is 't you say? the life?</A><br>
-</blockquote>
-
-<A NAME=speech28><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.87>Mean you his majesty?</A><br>
-</blockquote>
-
-<A NAME=speech29><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.88>Approach the chamber, and destroy your sight</A><br>
-<A NAME=2.3.89>With a new Gorgon: do not bid me speak;</A><br>
-<A NAME=2.3.90>See, and then speak yourselves.</A><br>
-<p><i>Exeunt MACBETH and LENNOX</i></p>
-<A NAME=2.3.91>Awake, awake!</A><br>
-<A NAME=2.3.92>Ring the alarum-bell. Murder and treason!</A><br>
-<A NAME=2.3.93>Banquo and Donalbain! Malcolm! awake!</A><br>
-<A NAME=2.3.94>Shake off this downy sleep, death's counterfeit,</A><br>
-<A NAME=2.3.95>And look on death itself! up, up, and see</A><br>
-<A NAME=2.3.96>The great doom's image! Malcolm! Banquo!</A><br>
-<A NAME=2.3.97>As from your graves rise up, and walk like sprites,</A><br>
-<A NAME=2.3.98>To countenance this horror! Ring the bell.</A><br>
-<p><i>Bell rings</i></p>
-<p><i>Enter LADY MACBETH</i></p>
-</blockquote>
-
-<A NAME=speech30><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.99>What's the business,</A><br>
-<A NAME=2.3.100>That such a hideous trumpet calls to parley</A><br>
-<A NAME=2.3.101>The sleepers of the house? speak, speak!</A><br>
-</blockquote>
-
-<A NAME=speech31><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.102>O gentle lady,</A><br>
-<A NAME=2.3.103>'Tis not for you to hear what I can speak:</A><br>
-<A NAME=2.3.104>The repetition, in a woman's ear,</A><br>
-<A NAME=2.3.105>Would murder as it fell.</A><br>
-<p><i>Enter BANQUO</i></p>
-<A NAME=2.3.106>O Banquo, Banquo,</A><br>
-<A NAME=2.3.107>Our royal master 's murder'd!</A><br>
-</blockquote>
-
-<A NAME=speech32><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.108>Woe, alas!</A><br>
-<A NAME=2.3.109>What, in our house?</A><br>
-</blockquote>
-
-<A NAME=speech33><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.3.110>Too cruel any where.</A><br>
-<A NAME=2.3.111>Dear Duff, I prithee, contradict thyself,</A><br>
-<A NAME=2.3.112>And say it is not so.</A><br>
-<p><i>Re-enter MACBETH and LENNOX, with ROSS</i></p>
-</blockquote>
-
-<A NAME=speech34><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.113>Had I but died an hour before this chance,</A><br>
-<A NAME=2.3.114>I had lived a blessed time; for, from this instant,</A><br>
-<A NAME=2.3.115>There 's nothing serious in mortality:</A><br>
-<A NAME=2.3.116>All is but toys: renown and grace is dead;</A><br>
-<A NAME=2.3.117>The wine of life is drawn, and the mere lees</A><br>
-<A NAME=2.3.118>Is left this vault to brag of.</A><br>
-<p><i>Enter MALCOLM and DONALBAIN</i></p>
-</blockquote>
-
-<A NAME=speech35><b>DONALBAIN</b></a>
-<blockquote>
-<A NAME=2.3.119>What is amiss?</A><br>
-</blockquote>
-
-<A NAME=speech36><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.120> You are, and do not know't:</A><br>
-<A NAME=2.3.121>The spring, the head, the fountain of your blood</A><br>
-<A NAME=2.3.122>Is stopp'd; the very source of it is stopp'd.</A><br>
-</blockquote>
-
-<A NAME=speech37><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.123>Your royal father 's murder'd.</A><br>
-</blockquote>
-
-<A NAME=speech38><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=2.3.124>O, by whom?</A><br>
-</blockquote>
-
-<A NAME=speech39><b>LENNOX</b></a>
-<blockquote>
-<A NAME=2.3.125>Those of his chamber, as it seem'd, had done 't:</A><br>
-<A NAME=2.3.126>Their hands and faces were an badged with blood;</A><br>
-<A NAME=2.3.127>So were their daggers, which unwiped we found</A><br>
-<A NAME=2.3.128>Upon their pillows:</A><br>
-<A NAME=2.3.129>They stared, and were distracted; no man's life</A><br>
-<A NAME=2.3.130>Was to be trusted with them.</A><br>
-</blockquote>
-
-<A NAME=speech40><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.131>O, yet I do repent me of my fury,</A><br>
-<A NAME=2.3.132>That I did kill them.</A><br>
-</blockquote>
-
-<A NAME=speech41><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.133>Wherefore did you so?</A><br>
-</blockquote>
-
-<A NAME=speech42><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.134>Who can be wise, amazed, temperate and furious,</A><br>
-<A NAME=2.3.135>Loyal and neutral, in a moment? No man:</A><br>
-<A NAME=2.3.136>The expedition my violent love</A><br>
-<A NAME=2.3.137>Outrun the pauser, reason. Here lay Duncan,</A><br>
-<A NAME=2.3.138>His silver skin laced with his golden blood;</A><br>
-<A NAME=2.3.139>And his gash'd stabs look'd like a breach in nature</A><br>
-<A NAME=2.3.140>For ruin's wasteful entrance: there, the murderers,</A><br>
-<A NAME=2.3.141>Steep'd in the colours of their trade, their daggers</A><br>
-<A NAME=2.3.142>Unmannerly breech'd with gore: who could refrain,</A><br>
-<A NAME=2.3.143>That had a heart to love, and in that heart</A><br>
-<A NAME=2.3.144>Courage to make 's love kno wn?</A><br>
-</blockquote>
-
-<A NAME=speech43><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.145>Help me hence, ho!</A><br>
-</blockquote>
-
-<A NAME=speech44><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.146>Look to the lady.</A><br>
-</blockquote>
-
-<A NAME=speech45><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=2.3.147>[Aside to DONALBAIN] Why do we hold our tongues,</A><br>
-<A NAME=2.3.148>That most may claim this argument for ours?</A><br>
-</blockquote>
-
-<A NAME=speech46><b>DONALBAIN</b></a>
-<blockquote>
-<A NAME=2.3.149>[Aside to MALCOLM] What should be spoken here,</A><br>
-<A NAME=2.3.150>where our fate,</A><br>
-<A NAME=2.3.151>Hid in an auger-hole, may rush, and seize us?</A><br>
-<A NAME=2.3.152>Let 's away;</A><br>
-<A NAME=2.3.153>Our tears are not yet brew'd.</A><br>
-</blockquote>
-
-<A NAME=speech47><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=2.3.154>[Aside to DONALBAIN] Nor our strong sorrow</A><br>
-<A NAME=2.3.155>Upon the foot of motion.</A><br>
-</blockquote>
-
-<A NAME=speech48><b>BANQUO</b></a>
-<blockquote>
-<A NAME=2.3.156>Look to the lady:</A><br>
-<p><i>LADY MACBETH is carried out</i></p>
-<A NAME=2.3.157>And when we have our naked frailties hid,</A><br>
-<A NAME=2.3.158>That suffer in exposure, let us meet,</A><br>
-<A NAME=2.3.159>And question this most bloody piece of work,</A><br>
-<A NAME=2.3.160>To know it further. Fears and scruples shake us:</A><br>
-<A NAME=2.3.161>In the great hand of God I stand; and thence</A><br>
-<A NAME=2.3.162>Against the undivulged pretence I fight</A><br>
-<A NAME=2.3.163>Of treasonous malice.</A><br>
-</blockquote>
-
-<A NAME=speech49><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.3.164>And so do I.</A><br>
-</blockquote>
-
-<A NAME=speech50><b>ALL</b></a>
-<blockquote>
-<A NAME=2.3.165>So all.</A><br>
-</blockquote>
-
-<A NAME=speech51><b>MACBETH</b></a>
-<blockquote>
-<A NAME=2.3.166>Let's briefly put on manly readiness,</A><br>
-<A NAME=2.3.167>And meet i' the hall together.</A><br>
-</blockquote>
-
-<A NAME=speech52><b>ALL</b></a>
-<blockquote>
-<A NAME=2.3.168>Well contented.</A><br>
-<p><i>Exeunt all but Malcolm and Donalbain.</i></p>
-</blockquote>
-
-<A NAME=speech53><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=2.3.169>What will you do? Let's not consort with them:</A><br>
-<A NAME=2.3.170>To show an unfelt sorrow is an office</A><br>
-<A NAME=2.3.171>Which the false man does easy. I'll to England.</A><br>
-</blockquote>
-
-<A NAME=speech54><b>DONALBAIN</b></a>
-<blockquote>
-<A NAME=2.3.172>To Ireland, I; our separated fortune</A><br>
-<A NAME=2.3.173>Shall keep us both the safer: where we are,</A><br>
-<A NAME=2.3.174>There's daggers in men's smiles: the near in blood,</A><br>
-<A NAME=2.3.175>The nearer bloody.</A><br>
-</blockquote>
-
-<A NAME=speech55><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=2.3.176> This murderous shaft that's shot</A><br>
-<A NAME=2.3.177>Hath not yet lighted, and our safest way</A><br>
-<A NAME=2.3.178>Is to avoid the aim. Therefore, to horse;</A><br>
-<A NAME=2.3.179>And let us not be dainty of leave-taking,</A><br>
-<A NAME=2.3.180>But shift away: there's warrant in that theft</A><br>
-<A NAME=2.3.181>Which steals itself, when there's no mercy left.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE IV. Outside Macbeth's castle.</h3>
-<p><blockquote>
-<i>Enter ROSS and an old Man</i>
-</blockquote>
-
-<A NAME=speech1><b>Old Man</b></a>
-<blockquote>
-<A NAME=2.4.1>Threescore and ten I can remember well:</A><br>
-<A NAME=2.4.2>Within the volume of which time I have seen</A><br>
-<A NAME=2.4.3>Hours dreadful and things strange; but this sore night</A><br>
-<A NAME=2.4.4>Hath trifled former knowings.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.5>Ah, good father,</A><br>
-<A NAME=2.4.6>Thou seest, the heavens, as troubled with man's act,</A><br>
-<A NAME=2.4.7>Threaten his bloody stage: by the clock, 'tis day,</A><br>
-<A NAME=2.4.8>And yet dark night strangles the travelling lamp:</A><br>
-<A NAME=2.4.9>Is't night's predominance, or the day's shame,</A><br>
-<A NAME=2.4.10>That darkness does the face of earth entomb,</A><br>
-<A NAME=2.4.11>When living light should kiss it?</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Old Man</b></a>
-<blockquote>
-<A NAME=2.4.12>'Tis unnatural,</A><br>
-<A NAME=2.4.13>Even like the deed that's done. On Tuesday last,</A><br>
-<A NAME=2.4.14>A falcon, towering in her pride of place,</A><br>
-<A NAME=2.4.15>Was by a mousing owl hawk'd at and kill'd.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.16>And Duncan's horses--a thing most strange and certain--</A><br>
-<A NAME=2.4.17>Beauteous and swift, the minions of their race,</A><br>
-<A NAME=2.4.18>Turn'd wild in nature, broke their stalls, flung out,</A><br>
-<A NAME=2.4.19>Contending 'gainst obedience, as they would make</A><br>
-<A NAME=2.4.20>War with mankind.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Old Man</b></a>
-<blockquote>
-<A NAME=2.4.21>'Tis said they eat each other.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.22>They did so, to the amazement of mine eyes</A><br>
-<A NAME=2.4.23>That look'd upon't. Here comes the good Macduff.</A><br>
-<p><i>Enter MACDUFF</i></p>
-<A NAME=2.4.24>How goes the world, sir, now?</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.25>Why, see you not?</A><br>
-</blockquote>
-
-<A NAME=speech8><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.26>Is't known who did this more than bloody deed?</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.27>Those that Macbeth hath slain.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.28>Alas, the day!</A><br>
-<A NAME=2.4.29>What good could they pretend?</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.30>They were suborn'd:</A><br>
-<A NAME=2.4.31>Malcolm and Donalbain, the king's two sons,</A><br>
-<A NAME=2.4.32>Are stol'n away and fled; which puts upon them</A><br>
-<A NAME=2.4.33>Suspicion of the deed.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.34>'Gainst nature still!</A><br>
-<A NAME=2.4.35>Thriftless ambition, that wilt ravin up</A><br>
-<A NAME=2.4.36>Thine own life's means! Then 'tis most like</A><br>
-<A NAME=2.4.37>The sovereignty will fall upon Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.38>He is already named, and gone to Scone</A><br>
-<A NAME=2.4.39>To be invested.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.40> Where is Duncan's body?</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.41>Carried to Colmekill,</A><br>
-<A NAME=2.4.42>The sacred storehouse of his predecessors,</A><br>
-<A NAME=2.4.43>And guardian of their bones.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.44>Will you to Scone?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.45>No, cousin, I'll to Fife.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.46>Well, I will thither.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=2.4.47>Well, may you see things well done there: adieu!</A><br>
-<A NAME=2.4.48>Lest our old robes sit easier than our new!</A><br>
-</blockquote>
-
-<A NAME=speech20><b>ROSS</b></a>
-<blockquote>
-<A NAME=2.4.49>Farewell, father.</A><br>
-</blockquote>
-
-<A NAME=speech21><b>Old Man</b></a>
-<blockquote>
-<A NAME=2.4.50>God's benison go with you; and with those</A><br>
-<A NAME=2.4.51>That would make good of bad, and friends of foes!</A><br>
-<p><i>Exeunt</i></p>
-</blockquote><p>
-<H3>ACT III</h3>
-<h3>SCENE I. Forres. The palace.</h3>
-<p><blockquote>
-<i>Enter BANQUO</i>
-</blockquote>
-
-<A NAME=speech1><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.1>Thou hast it now: king, Cawdor, Glamis, all,</A><br>
-<A NAME=3.1.2>As the weird women promised, and, I fear,</A><br>
-<A NAME=3.1.3>Thou play'dst most foully for't: yet it was said</A><br>
-<A NAME=3.1.4>It should not stand in thy posterity,</A><br>
-<A NAME=3.1.5>But that myself should be the root and father</A><br>
-<A NAME=3.1.6>Of many kings. If there come truth from them--</A><br>
-<A NAME=3.1.7>As upon thee, Macbeth, their speeches shine--</A><br>
-<A NAME=3.1.8>Why, by the verities on thee made good,</A><br>
-<A NAME=3.1.9>May they not be my oracles as well,</A><br>
-<A NAME=3.1.10>And set me up in hope? But hush! no more.</A><br>
-<p><i>Sennet sounded. Enter MACBETH, as king, LADY MACBETH, as queen, LENNOX, ROSS, Lords, Ladies, and Attendants</i></p>
-</blockquote>
-
-<A NAME=speech2><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.11>Here's our chief guest.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.12>If he had been forgotten,</A><br>
-<A NAME=3.1.13>It had been as a gap in our great feast,</A><br>
-<A NAME=3.1.14>And all-thing unbecoming.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.15>To-night we hold a solemn supper sir,</A><br>
-<A NAME=3.1.16>And I'll request your presence.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.17>Let your highness</A><br>
-<A NAME=3.1.18>Command upon me; to the which my duties</A><br>
-<A NAME=3.1.19>Are with a most indissoluble tie</A><br>
-<A NAME=3.1.20>For ever knit.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.21> Ride you this afternoon?</A><br>
-</blockquote>
-
-<A NAME=speech7><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.22>Ay, my good lord.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.23>We should have else desired your good advice,</A><br>
-<A NAME=3.1.24>Which still hath been both grave and prosperous,</A><br>
-<A NAME=3.1.25>In this day's council; but we'll take to-morrow.</A><br>
-<A NAME=3.1.26>Is't far you ride?</A><br>
-</blockquote>
-
-<A NAME=speech9><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.27>As far, my lord, as will fill up the time</A><br>
-<A NAME=3.1.28>'Twixt this and supper: go not my horse the better,</A><br>
-<A NAME=3.1.29>I must become a borrower of the night</A><br>
-<A NAME=3.1.30>For a dark hour or twain.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.31>Fail not our feast.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.32>My lord, I will not.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.33>We hear, our bloody cousins are bestow'd</A><br>
-<A NAME=3.1.34>In England and in Ireland, not confessing</A><br>
-<A NAME=3.1.35>Their cruel parricide, filling their hearers</A><br>
-<A NAME=3.1.36>With strange invention: but of that to-morrow,</A><br>
-<A NAME=3.1.37>When therewithal we shall have cause of state</A><br>
-<A NAME=3.1.38>Craving us jointly. Hie you to horse: adieu,</A><br>
-<A NAME=3.1.39>Till you return at night. Goes Fleance with you?</A><br>
-</blockquote>
-
-<A NAME=speech13><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.1.40>Ay, my good lord: our time does call upon 's.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.41>I wish your horses swift and sure of foot;</A><br>
-<A NAME=3.1.42>And so I do commend you to their backs. Farewell.</A><br>
-<p><i>Exit BANQUO</i></p>
-<A NAME=3.1.43>Let every man be master of his time</A><br>
-<A NAME=3.1.44>Till seven at night: to make society</A><br>
-<A NAME=3.1.45>The sweeter welcome, we will keep ourself</A><br>
-<A NAME=3.1.46>Till supper-time alone: while then, God be with you!</A><br>
-<p><i>Exeunt all but MACBETH, and an attendant</i></p>
-<A NAME=3.1.47>Sirrah, a word with you: attend those men</A><br>
-<A NAME=3.1.48>Our pleasure?</A><br>
-</blockquote>
-
-<A NAME=speech15><b>ATTENDANT</b></a>
-<blockquote>
-<A NAME=3.1.49>They are, my lord, without the palace gate.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.50>Bring them before us.</A><br>
-<p><i>Exit Attendant</i></p>
-<A NAME=3.1.51>To be thus is nothing;</A><br>
-<A NAME=3.1.52>But to be safely thus.--Our fears in Banquo</A><br>
-<A NAME=3.1.53>Stick deep; and in his royalty of nature</A><br>
-<A NAME=3.1.54>Reigns that which would be fear'd: 'tis much he dares;</A><br>
-<A NAME=3.1.55>And, to that dauntless temper of his mind,</A><br>
-<A NAME=3.1.56>He hath a wisdom that doth guide his valour</A><br>
-<A NAME=3.1.57>To act in safety. There is none but he</A><br>
-<A NAME=3.1.58>Whose being I do fear: and, under him,</A><br>
-<A NAME=3.1.59>My Genius is rebuked; as, it is said,</A><br>
-<A NAME=3.1.60>Mark Antony's was by Caesar. He chid the sisters</A><br>
-<A NAME=3.1.61>When first they put the name of king upon me,</A><br>
-<A NAME=3.1.62>And bade them speak to him: then prophet-like</A><br>
-<A NAME=3.1.63>They hail'd him father to a line of kings:</A><br>
-<A NAME=3.1.64>Upon my head they placed a fruitless crown,</A><br>
-<A NAME=3.1.65>And put a barren sceptre in my gripe,</A><br>
-<A NAME=3.1.66>Thence to be wrench'd with an unlineal hand,</A><br>
-<A NAME=3.1.67>No son of mine succeeding. If 't be so,</A><br>
-<A NAME=3.1.68>For Banquo's issue have I filed my mind;</A><br>
-<A NAME=3.1.69>For them the gracious Duncan have I murder'd;</A><br>
-<A NAME=3.1.70>Put rancours in the vessel of my peace</A><br>
-<A NAME=3.1.71>Only for them; and mine eternal jewel</A><br>
-<A NAME=3.1.72>Given to the common enemy of man,</A><br>
-<A NAME=3.1.73>To make them kings, the seed of Banquo kings!</A><br>
-<A NAME=3.1.74>Rather than so, come fate into the list.</A><br>
-<A NAME=3.1.75>And champion me to the utterance! Who's there!</A><br>
-<p><i>Re-enter Attendant, with two Murderers</i></p>
-<A NAME=3.1.76>Now go to the door, and stay there till we call.</A><br>
-<p><i>Exit Attendant</i></p>
-<A NAME=3.1.77>Was it not yesterday we spoke together?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.1.78>It was, so please your highness.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.79>Well then, now</A><br>
-<A NAME=3.1.80>Have you consider'd of my speeches? Know</A><br>
-<A NAME=3.1.81>That it was he in the times past which held you</A><br>
-<A NAME=3.1.82>So under fortune, which you thought had been</A><br>
-<A NAME=3.1.83>Our innocent self: this I made good to you</A><br>
-<A NAME=3.1.84>In our last conference, pass'd in probation with you,</A><br>
-<A NAME=3.1.85>How you were borne in hand, how cross'd,</A><br>
-<A NAME=3.1.86>the instruments,</A><br>
-<A NAME=3.1.87>Who wrought with them, and all things else that might</A><br>
-<A NAME=3.1.88>To half a soul and to a notion crazed</A><br>
-<A NAME=3.1.89>Say 'Thus did Banquo.'</A><br>
-</blockquote>
-
-<A NAME=speech19><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.1.90>You made it known to us.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.91>I did so, and went further, which is now</A><br>
-<A NAME=3.1.92>Our point of second meeting. Do you find</A><br>
-<A NAME=3.1.93>Your patience so predominant in your nature</A><br>
-<A NAME=3.1.94>That you can let this go? Are you so gospell'd</A><br>
-<A NAME=3.1.95>To pray for this good man and for his issue,</A><br>
-<A NAME=3.1.96>Whose heavy hand hath bow'd you to the grave</A><br>
-<A NAME=3.1.97>And beggar'd yours for ever?</A><br>
-</blockquote>
-
-<A NAME=speech21><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.1.98>We are men, my liege.</A><br>
-</blockquote>
-
-<A NAME=speech22><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.99>Ay, in the catalogue ye go for men;</A><br>
-<A NAME=3.1.100>As hounds and greyhounds, mongrels, spaniels, curs,</A><br>
-<A NAME=3.1.101>Shoughs, water-rugs and demi-wolves, are clept</A><br>
-<A NAME=3.1.102>All by the name of dogs: the valued file</A><br>
-<A NAME=3.1.103>Distinguishes the swift, the slow, the subtle,</A><br>
-<A NAME=3.1.104>The housekeeper, the hunter, every one</A><br>
-<A NAME=3.1.105>According to the gift which bounteous nature</A><br>
-<A NAME=3.1.106>Hath in him closed; whereby he does receive</A><br>
-<A NAME=3.1.107>Particular addition. from the bill</A><br>
-<A NAME=3.1.108>That writes them all alike: and so of men.</A><br>
-<A NAME=3.1.109>Now, if you have a station in the file,</A><br>
-<A NAME=3.1.110>Not i' the worst rank of manhood, say 't;</A><br>
-<A NAME=3.1.111>And I will put that business in your bosoms,</A><br>
-<A NAME=3.1.112>Whose execution takes your enemy off,</A><br>
-<A NAME=3.1.113>Grapples you to the heart and love of us,</A><br>
-<A NAME=3.1.114>Who wear our health but sickly in his life,</A><br>
-<A NAME=3.1.115>Which in his death were perfect.</A><br>
-</blockquote>
-
-<A NAME=speech23><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.1.116>I am one, my liege,</A><br>
-<A NAME=3.1.117>Whom the vile blows and buffets of the world</A><br>
-<A NAME=3.1.118>Have so incensed that I am reckless what</A><br>
-<A NAME=3.1.119>I do to spite the world.</A><br>
-</blockquote>
-
-<A NAME=speech24><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.1.120>And I another</A><br>
-<A NAME=3.1.121>So weary with disasters, tugg'd with fortune,</A><br>
-<A NAME=3.1.122>That I would set my lie on any chance,</A><br>
-<A NAME=3.1.123>To mend it, or be rid on't.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.124>Both of you</A><br>
-<A NAME=3.1.125>Know Banquo was your enemy.</A><br>
-</blockquote>
-
-<A NAME=speech26><b>Both Murderers</b></a>
-<blockquote>
-<A NAME=3.1.126>True, my lord.</A><br>
-</blockquote>
-
-<A NAME=speech27><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.127>So is he mine; and in such bloody distance,</A><br>
-<A NAME=3.1.128>That every minute of his being thrusts</A><br>
-<A NAME=3.1.129>Against my near'st of life: and though I could</A><br>
-<A NAME=3.1.130>With barefaced power sweep him from my sight</A><br>
-<A NAME=3.1.131>And bid my will avouch it, yet I must not,</A><br>
-<A NAME=3.1.132>For certain friends that are both his and mine,</A><br>
-<A NAME=3.1.133>Whose loves I may not drop, but wail his fall</A><br>
-<A NAME=3.1.134>Who I myself struck down; and thence it is,</A><br>
-<A NAME=3.1.135>That I to your assistance do make love,</A><br>
-<A NAME=3.1.136>Masking the business from the common eye</A><br>
-<A NAME=3.1.137>For sundry weighty reasons.</A><br>
-</blockquote>
-
-<A NAME=speech28><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.1.138>We shall, my lord,</A><br>
-<A NAME=3.1.139>Perform what you command us.</A><br>
-</blockquote>
-
-<A NAME=speech29><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.1.140>Though our lives--</A><br>
-</blockquote>
-
-<A NAME=speech30><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.141>Your spirits shine through you. Within this hour at most</A><br>
-<A NAME=3.1.142>I will advise you where to plant yourselves;</A><br>
-<A NAME=3.1.143>Acquaint you with the perfect spy o' the time,</A><br>
-<A NAME=3.1.144>The moment on't; for't must be done to-night,</A><br>
-<A NAME=3.1.145>And something from the palace; always thought</A><br>
-<A NAME=3.1.146>That I require a clearness: and with him--</A><br>
-<A NAME=3.1.147>To leave no rubs nor botches in the work--</A><br>
-<A NAME=3.1.148>Fleance his son, that keeps him company,</A><br>
-<A NAME=3.1.149>Whose absence is no less material to me</A><br>
-<A NAME=3.1.150>Than is his father's, must embrace the fate</A><br>
-<A NAME=3.1.151>Of that dark hour. Resolve yourselves apart:</A><br>
-<A NAME=3.1.152>I'll come to you anon.</A><br>
-</blockquote>
-
-<A NAME=speech31><b>Both Murderers</b></a>
-<blockquote>
-<A NAME=3.1.153>We are resolved, my lord.</A><br>
-</blockquote>
-
-<A NAME=speech32><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.1.154>I'll call upon you straight: abide within.</A><br>
-<p><i>Exeunt Murderers</i></p>
-<A NAME=3.1.155>It is concluded. Banquo, thy soul's flight,</A><br>
-<A NAME=3.1.156>If it find heaven, must find it out to-night.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-<h3>SCENE II. The palace.</h3>
-<p><blockquote>
-<i>Enter LADY MACBETH and a Servant</i>
-</blockquote>
-
-<A NAME=speech1><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.1>Is Banquo gone from court?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Servant</b></a>
-<blockquote>
-<A NAME=3.2.2>Ay, madam, but returns again to-night.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.3>Say to the king, I would attend his leisure</A><br>
-<A NAME=3.2.4>For a few words.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>Servant</b></a>
-<blockquote>
-<A NAME=3.2.5> Madam, I will.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech5><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.6>Nought's had, all's spent,</A><br>
-<A NAME=3.2.7>Where our desire is got without content:</A><br>
-<A NAME=3.2.8>'Tis safer to be that which we destroy</A><br>
-<A NAME=3.2.9>Than by destruction dwell in doubtful joy.</A><br>
-<p><i>Enter MACBETH</i></p>
-<A NAME=3.2.10>How now, my lord! why do you keep alone,</A><br>
-<A NAME=3.2.11>Of sorriest fancies your companions making,</A><br>
-<A NAME=3.2.12>Using those thoughts which should indeed have died</A><br>
-<A NAME=3.2.13>With them they think on? Things without all remedy</A><br>
-<A NAME=3.2.14>Should be without regard: what's done is done.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.15>We have scotch'd the snake, not kill'd it:</A><br>
-<A NAME=3.2.16>She'll close and be herself, whilst our poor malice</A><br>
-<A NAME=3.2.17>Remains in danger of her former tooth.</A><br>
-<A NAME=3.2.18>But let the frame of things disjoint, both the</A><br>
-<A NAME=3.2.19>worlds suffer,</A><br>
-<A NAME=3.2.20>Ere we will eat our meal in fear and sleep</A><br>
-<A NAME=3.2.21>In the affliction of these terrible dreams</A><br>
-<A NAME=3.2.22>That shake us nightly: better be with the dead,</A><br>
-<A NAME=3.2.23>Whom we, to gain our peace, have sent to peace,</A><br>
-<A NAME=3.2.24>Than on the torture of the mind to lie</A><br>
-<A NAME=3.2.25>In restless ecstasy. Duncan is in his grave;</A><br>
-<A NAME=3.2.26>After life's fitful fever he sleeps well;</A><br>
-<A NAME=3.2.27>Treason has done his worst: nor steel, nor poison,</A><br>
-<A NAME=3.2.28>Malice domestic, foreign levy, nothing,</A><br>
-<A NAME=3.2.29>Can touch him further.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.30>Come on;</A><br>
-<A NAME=3.2.31>Gentle my lord, sleek o'er your rugged looks;</A><br>
-<A NAME=3.2.32>Be bright and jovial among your guests to-night.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.33>So shall I, love; and so, I pray, be you:</A><br>
-<A NAME=3.2.34>Let your remembrance apply to Banquo;</A><br>
-<A NAME=3.2.35>Present him eminence, both with eye and tongue:</A><br>
-<A NAME=3.2.36>Unsafe the while, that we</A><br>
-<A NAME=3.2.37>Must lave our honours in these flattering streams,</A><br>
-<A NAME=3.2.38>And make our faces vizards to our hearts,</A><br>
-<A NAME=3.2.39>Disguising what they are.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.40>You must leave this.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.41>O, full of scorpions is my mind, dear wife!</A><br>
-<A NAME=3.2.42>Thou know'st that Banquo, and his Fleance, lives.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.43>But in them nature's copy's not eterne.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.44>There's comfort yet; they are assailable;</A><br>
-<A NAME=3.2.45>Then be thou jocund: ere the bat hath flown</A><br>
-<A NAME=3.2.46>His cloister'd flight, ere to black Hecate's summons</A><br>
-<A NAME=3.2.47>The shard-borne beetle with his drowsy hums</A><br>
-<A NAME=3.2.48>Hath rung night's yawning peal, there shall be done</A><br>
-<A NAME=3.2.49>A deed of dreadful note.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.50>What's to be done?</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.2.51>Be innocent of the knowledge, dearest chuck,</A><br>
-<A NAME=3.2.52>Till thou applaud the deed. Come, seeling night,</A><br>
-<A NAME=3.2.53>Scarf up the tender eye of pitiful day;</A><br>
-<A NAME=3.2.54>And with thy bloody and invisible hand</A><br>
-<A NAME=3.2.55>Cancel and tear to pieces that great bond</A><br>
-<A NAME=3.2.56>Which keeps me pale! Light thickens; and the crow</A><br>
-<A NAME=3.2.57>Makes wing to the rooky wood:</A><br>
-<A NAME=3.2.58>Good things of day begin to droop and drowse;</A><br>
-<A NAME=3.2.59>While night's black agents to their preys do rouse.</A><br>
-<A NAME=3.2.60>Thou marvell'st at my words: but hold thee still;</A><br>
-<A NAME=3.2.61>Things bad begun make strong themselves by ill.</A><br>
-<A NAME=3.2.62>So, prithee, go with me.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE III. A park near the palace.</h3>
-<p><blockquote>
-<i>Enter three Murderers</i>
-</blockquote>
-
-<A NAME=speech1><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.1>But who did bid thee join with us?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.2>Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.3.3>He needs not our mistrust, since he delivers</A><br>
-<A NAME=3.3.4>Our offices and what we have to do</A><br>
-<A NAME=3.3.5>To the direction just.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.6>Then stand with us.</A><br>
-<A NAME=3.3.7>The west yet glimmers with some streaks of day:</A><br>
-<A NAME=3.3.8>Now spurs the lated traveller apace</A><br>
-<A NAME=3.3.9>To gain the timely inn; and near approaches</A><br>
-<A NAME=3.3.10>The subject of our watch.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.11>Hark! I hear horses.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.3.12>[Within] Give us a light there, ho!</A><br>
-</blockquote>
-
-<A NAME=speech7><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.3.13>Then 'tis he: the rest</A><br>
-<A NAME=3.3.14>That are within the note of expectation</A><br>
-<A NAME=3.3.15>Already are i' the court.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.16>His horses go about.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.17>Almost a mile: but he does usually,</A><br>
-<A NAME=3.3.18>So all men do, from hence to the palace gate</A><br>
-<A NAME=3.3.19>Make it their walk.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.3.20>A light, a light!</A><br>
-<p><i>Enter BANQUO, and FLEANCE with a torch</i></p>
-</blockquote>
-
-<A NAME=speech11><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.21>'Tis he.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.22>Stand to't.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.3.23>It will be rain to-night.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.24>Let it come down.</A><br>
-<p><i>They set upon BANQUO</i></p>
-</blockquote>
-
-<A NAME=speech15><b>BANQUO</b></a>
-<blockquote>
-<A NAME=3.3.25>O, treachery! Fly, good Fleance, fly, fly, fly!</A><br>
-<A NAME=3.3.26>Thou mayst revenge. O slave!</A><br>
-<p><i>Dies. FLEANCE escapes</i></p>
-</blockquote>
-
-<A NAME=speech16><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.27>Who did strike out the light?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.28>Wast not the way?</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Third Murderer</b></a>
-<blockquote>
-<A NAME=3.3.29>There's but one down; the son is fled.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>Second Murderer</b></a>
-<blockquote>
-<A NAME=3.3.30>We have lost</A><br>
-<A NAME=3.3.31>Best half of our affair.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.3.32>Well, let's away, and say how much is done.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE IV. The same. Hall in the palace.</h3>
-<p><blockquote>
-<i>A banquet prepared. Enter MACBETH, LADY MACBETH, ROSS, LENNOX, Lords, and Attendants</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.1>You know your own degrees; sit down: at first</A><br>
-<A NAME=3.4.2>And last the hearty welcome.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Lords</b></a>
-<blockquote>
-<A NAME=3.4.3>Thanks to your majesty.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.4>Ourself will mingle with society,</A><br>
-<A NAME=3.4.5>And play the humble host.</A><br>
-<A NAME=3.4.6>Our hostess keeps her state, but in best time</A><br>
-<A NAME=3.4.7>We will require her welcome.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.8>Pronounce it for me, sir, to all our friends;</A><br>
-<A NAME=3.4.9>For my heart speaks they are welcome.</A><br>
-<p><i>First Murderer appears at the door</i></p>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.10>See, they encounter thee with their hearts' thanks.</A><br>
-<A NAME=3.4.11>Both sides are even: here I'll sit i' the midst:</A><br>
-<A NAME=3.4.12>Be large in mirth; anon we'll drink a measure</A><br>
-<A NAME=3.4.13>The table round.</A><br>
-<p><i>Approaching the door</i></p>
-<A NAME=3.4.14>There's blood on thy face.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.4.15>'Tis Banquo's then.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.16>'Tis better thee without than he within.</A><br>
-<A NAME=3.4.17>Is he dispatch'd?</A><br>
-</blockquote>
-
-<A NAME=speech8><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.4.18>My lord, his throat is cut; that I did for him.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.19>Thou art the best o' the cut-throats: yet he's good</A><br>
-<A NAME=3.4.20>That did the like for Fleance: if thou didst it,</A><br>
-<A NAME=3.4.21>Thou art the nonpareil.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.4.22>Most royal sir,</A><br>
-<A NAME=3.4.23>Fleance is 'scaped.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.24>Then comes my fit again: I had else been perfect,</A><br>
-<A NAME=3.4.25>Whole as the marble, founded as the rock,</A><br>
-<A NAME=3.4.26>As broad and general as the casing air:</A><br>
-<A NAME=3.4.27>But now I am cabin'd, cribb'd, confined, bound in</A><br>
-<A NAME=3.4.28>To saucy doubts and fears. But Banquo's safe?</A><br>
-</blockquote>
-
-<A NAME=speech12><b>First Murderer</b></a>
-<blockquote>
-<A NAME=3.4.29>Ay, my good lord: safe in a ditch he bides,</A><br>
-<A NAME=3.4.30>With twenty trenched gashes on his head;</A><br>
-<A NAME=3.4.31>The least a death to nature.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.32>Thanks for that:</A><br>
-<A NAME=3.4.33>There the grown serpent lies; the worm that's fled</A><br>
-<A NAME=3.4.34>Hath nature that in time will venom breed,</A><br>
-<A NAME=3.4.35>No teeth for the present. Get thee gone: to-morrow</A><br>
-<A NAME=3.4.36>We'll hear, ourselves, again.</A><br>
-<p><i>Exit Murderer</i></p>
-</blockquote>
-
-<A NAME=speech14><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.37>My royal lord,</A><br>
-<A NAME=3.4.38>You do not give the cheer: the feast is sold</A><br>
-<A NAME=3.4.39>That is not often vouch'd, while 'tis a-making,</A><br>
-<A NAME=3.4.40>'Tis given with welcome: to feed were best at home;</A><br>
-<A NAME=3.4.41>From thence the sauce to meat is ceremony;</A><br>
-<A NAME=3.4.42>Meeting were bare without it.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.43>Sweet remembrancer!</A><br>
-<A NAME=3.4.44>Now, good digestion wait on appetite,</A><br>
-<A NAME=3.4.45>And health on both!</A><br>
-</blockquote>
-
-<A NAME=speech16><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.4.46>May't please your highness sit.</A><br>
-<p><i>The GHOST OF BANQUO enters, and sits in MACBETH's place</i></p>
-</blockquote>
-
-<A NAME=speech17><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.47>Here had we now our country's honour roof'd,</A><br>
-<A NAME=3.4.48>Were the graced person of our Banquo present;</A><br>
-<A NAME=3.4.49>Who may I rather challenge for unkindness</A><br>
-<A NAME=3.4.50>Than pity for mischance!</A><br>
-</blockquote>
-
-<A NAME=speech18><b>ROSS</b></a>
-<blockquote>
-<A NAME=3.4.51>His absence, sir,</A><br>
-<A NAME=3.4.52>Lays blame upon his promise. Please't your highness</A><br>
-<A NAME=3.4.53>To grace us with your royal company.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.54>The table's full.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.4.55> Here is a place reserved, sir.</A><br>
-</blockquote>
-
-<A NAME=speech21><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.56>Where?</A><br>
-</blockquote>
-
-<A NAME=speech22><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.4.57>Here, my good lord. What is't that moves your highness?</A><br>
-</blockquote>
-
-<A NAME=speech23><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.58>Which of you have done this?</A><br>
-</blockquote>
-
-<A NAME=speech24><b>Lords</b></a>
-<blockquote>
-<A NAME=3.4.59>What, my good lord?</A><br>
-</blockquote>
-
-<A NAME=speech25><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.60>Thou canst not say I did it: never shake</A><br>
-<A NAME=3.4.61>Thy gory locks at me.</A><br>
-</blockquote>
-
-<A NAME=speech26><b>ROSS</b></a>
-<blockquote>
-<A NAME=3.4.62>Gentlemen, rise: his highness is not well.</A><br>
-</blockquote>
-
-<A NAME=speech27><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.63>Sit, worthy friends: my lord is often thus,</A><br>
-<A NAME=3.4.64>And hath been from his youth: pray you, keep seat;</A><br>
-<A NAME=3.4.65>The fit is momentary; upon a thought</A><br>
-<A NAME=3.4.66>He will again be well: if much you note him,</A><br>
-<A NAME=3.4.67>You shall offend him and extend his passion:</A><br>
-<A NAME=3.4.68>Feed, and regard him not. Are you a man?</A><br>
-</blockquote>
-
-<A NAME=speech28><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.69>Ay, and a bold one, that dare look on that</A><br>
-<A NAME=3.4.70>Which might appal the devil.</A><br>
-</blockquote>
-
-<A NAME=speech29><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.71>O proper stuff!</A><br>
-<A NAME=3.4.72>This is the very painting of your fear:</A><br>
-<A NAME=3.4.73>This is the air-drawn dagger which, you said,</A><br>
-<A NAME=3.4.74>Led you to Duncan. O, these flaws and starts,</A><br>
-<A NAME=3.4.75>Impostors to true fear, would well become</A><br>
-<A NAME=3.4.76>A woman's story at a winter's fire,</A><br>
-<A NAME=3.4.77>Authorized by her grandam. Shame itself!</A><br>
-<A NAME=3.4.78>Why do you make such faces? When all's done,</A><br>
-<A NAME=3.4.79>You look but on a stool.</A><br>
-</blockquote>
-
-<A NAME=speech30><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.80>Prithee, see there! behold! look! lo!</A><br>
-<A NAME=3.4.81>how say you?</A><br>
-<A NAME=3.4.82>Why, what care I? If thou canst nod, speak too.</A><br>
-<A NAME=3.4.83>If charnel-houses and our graves must send</A><br>
-<A NAME=3.4.84>Those that we bury back, our monuments</A><br>
-<A NAME=3.4.85>Shall be the maws of kites.</A><br>
-<p><i>GHOST OF BANQUO vanishes</i></p>
-</blockquote>
-
-<A NAME=speech31><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.86>What, quite unmann'd in folly?</A><br>
-</blockquote>
-
-<A NAME=speech32><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.87>If I stand here, I saw him.</A><br>
-</blockquote>
-
-<A NAME=speech33><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.88>Fie, for shame!</A><br>
-</blockquote>
-
-<A NAME=speech34><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.89>Blood hath been shed ere now, i' the olden time,</A><br>
-<A NAME=3.4.90>Ere human statute purged the gentle weal;</A><br>
-<A NAME=3.4.91>Ay, and since too, murders have been perform'd</A><br>
-<A NAME=3.4.92>Too terrible for the ear: the times have been,</A><br>
-<A NAME=3.4.93>That, when the brains were out, the man would die,</A><br>
-<A NAME=3.4.94>And there an end; but now they rise again,</A><br>
-<A NAME=3.4.95>With twenty mortal murders on their crowns,</A><br>
-<A NAME=3.4.96>And push us from our stools: this is more strange</A><br>
-<A NAME=3.4.97>Than such a murder is.</A><br>
-</blockquote>
-
-<A NAME=speech35><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.98>My worthy lord,</A><br>
-<A NAME=3.4.99>Your noble friends do lack you.</A><br>
-</blockquote>
-
-<A NAME=speech36><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.100>I do forget.</A><br>
-<A NAME=3.4.101>Do not muse at me, my most worthy friends,</A><br>
-<A NAME=3.4.102>I have a strange infirmity, which is nothing</A><br>
-<A NAME=3.4.103>To those that know me. Come, love and health to all;</A><br>
-<A NAME=3.4.104>Then I'll sit down. Give me some wine; fill full.</A><br>
-<A NAME=3.4.105>I drink to the general joy o' the whole table,</A><br>
-<A NAME=3.4.106>And to our dear friend Banquo, whom we miss;</A><br>
-<A NAME=3.4.107>Would he were here! to all, and him, we thirst,</A><br>
-<A NAME=3.4.108>And all to all.</A><br>
-</blockquote>
-
-<A NAME=speech37><b>Lords</b></a>
-<blockquote>
-<A NAME=3.4.109> Our duties, and the pledge.</A><br>
-<p><i>Re-enter GHOST OF BANQUO</i></p>
-</blockquote>
-
-<A NAME=speech38><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.110>Avaunt! and quit my sight! let the earth hide thee!</A><br>
-<A NAME=3.4.111>Thy bones are marrowless, thy blood is cold;</A><br>
-<A NAME=3.4.112>Thou hast no speculation in those eyes</A><br>
-<A NAME=3.4.113>Which thou dost glare with!</A><br>
-</blockquote>
-
-<A NAME=speech39><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.114>Think of this, good peers,</A><br>
-<A NAME=3.4.115>But as a thing of custom: 'tis no other;</A><br>
-<A NAME=3.4.116>Only it spoils the pleasure of the time.</A><br>
-</blockquote>
-
-<A NAME=speech40><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.117>What man dare, I dare:</A><br>
-<A NAME=3.4.118>Approach thou like the rugged Russian bear,</A><br>
-<A NAME=3.4.119>The arm'd rhinoceros, or the Hyrcan tiger;</A><br>
-<A NAME=3.4.120>Take any shape but that, and my firm nerves</A><br>
-<A NAME=3.4.121>Shall never tremble: or be alive again,</A><br>
-<A NAME=3.4.122>And dare me to the desert with thy sword;</A><br>
-<A NAME=3.4.123>If trembling I inhabit then, protest me</A><br>
-<A NAME=3.4.124>The baby of a girl. Hence, horrible shadow!</A><br>
-<A NAME=3.4.125>Unreal mockery, hence!</A><br>
-<p><i>GHOST OF BANQUO vanishes</i></p>
-<A NAME=3.4.126>Why, so: being gone,</A><br>
-<A NAME=3.4.127>I am a man again. Pray you, sit still.</A><br>
-</blockquote>
-
-<A NAME=speech41><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.128>You have displaced the mirth, broke the good meeting,</A><br>
-<A NAME=3.4.129>With most admired disorder.</A><br>
-</blockquote>
-
-<A NAME=speech42><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.130>Can such things be,</A><br>
-<A NAME=3.4.131>And overcome us like a summer's cloud,</A><br>
-<A NAME=3.4.132>Without our special wonder? You make me strange</A><br>
-<A NAME=3.4.133>Even to the disposition that I owe,</A><br>
-<A NAME=3.4.134>When now I think you can behold such sights,</A><br>
-<A NAME=3.4.135>And keep the natural ruby of your cheeks,</A><br>
-<A NAME=3.4.136>When mine is blanched with fear.</A><br>
-</blockquote>
-
-<A NAME=speech43><b>ROSS</b></a>
-<blockquote>
-<A NAME=3.4.137>What sights, my lord?</A><br>
-</blockquote>
-
-<A NAME=speech44><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.138>I pray you, speak not; he grows worse and worse;</A><br>
-<A NAME=3.4.139>Question enrages him. At once, good night:</A><br>
-<A NAME=3.4.140>Stand not upon the order of your going,</A><br>
-<A NAME=3.4.141>But go at once.</A><br>
-</blockquote>
-
-<A NAME=speech45><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.4.142> Good night; and better health</A><br>
-<A NAME=3.4.143>Attend his majesty!</A><br>
-</blockquote>
-
-<A NAME=speech46><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.144>A kind good night to all!</A><br>
-<p><i>Exeunt all but MACBETH and LADY MACBETH</i></p>
-</blockquote>
-
-<A NAME=speech47><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.145>It will have blood; they say, blood will have blood:</A><br>
-<A NAME=3.4.146>Stones have been known to move and trees to speak;</A><br>
-<A NAME=3.4.147>Augurs and understood relations have</A><br>
-<A NAME=3.4.148>By magot-pies and choughs and rooks brought forth</A><br>
-<A NAME=3.4.149>The secret'st man of blood. What is the night?</A><br>
-</blockquote>
-
-<A NAME=speech48><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.150>Almost at odds with morning, which is which.</A><br>
-</blockquote>
-
-<A NAME=speech49><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.151>How say'st thou, that Macduff denies his person</A><br>
-<A NAME=3.4.152>At our great bidding?</A><br>
-</blockquote>
-
-<A NAME=speech50><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.153>Did you send to him, sir?</A><br>
-</blockquote>
-
-<A NAME=speech51><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.154>I hear it by the way; but I will send:</A><br>
-<A NAME=3.4.155>There's not a one of them but in his house</A><br>
-<A NAME=3.4.156>I keep a servant fee'd. I will to-morrow,</A><br>
-<A NAME=3.4.157>And betimes I will, to the weird sisters:</A><br>
-<A NAME=3.4.158>More shall they speak; for now I am bent to know,</A><br>
-<A NAME=3.4.159>By the worst means, the worst. For mine own good,</A><br>
-<A NAME=3.4.160>All causes shall give way: I am in blood</A><br>
-<A NAME=3.4.161>Stepp'd in so far that, should I wade no more,</A><br>
-<A NAME=3.4.162>Returning were as tedious as go o'er:</A><br>
-<A NAME=3.4.163>Strange things I have in head, that will to hand;</A><br>
-<A NAME=3.4.164>Which must be acted ere they may be scann'd.</A><br>
-</blockquote>
-
-<A NAME=speech52><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.165>You lack the season of all natures, sleep.</A><br>
-</blockquote>
-
-<A NAME=speech53><b>MACBETH</b></a>
-<blockquote>
-<A NAME=3.4.166>Come, we'll to sleep. My strange and self-abuse</A><br>
-<A NAME=3.4.167>Is the initiate fear that wants hard use:</A><br>
-<A NAME=3.4.168>We are yet but young in deed.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE V. A Heath.</h3>
-<p><blockquote>
-<i>Thunder. Enter the three Witches meeting HECATE</i>
-</blockquote>
-
-<A NAME=speech1><b>First Witch</b></a>
-<blockquote>
-<A NAME=3.5.1>Why, how now, Hecate! you look angerly.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>HECATE</b></a>
-<blockquote>
-<A NAME=3.5.2>Have I not reason, beldams as you are,</A><br>
-<A NAME=3.5.3>Saucy and overbold? How did you dare</A><br>
-<A NAME=3.5.4>To trade and traffic with Macbeth</A><br>
-<A NAME=3.5.5>In riddles and affairs of death;</A><br>
-<A NAME=3.5.6>And I, the mistress of your charms,</A><br>
-<A NAME=3.5.7>The close contriver of all harms,</A><br>
-<A NAME=3.5.8>Was never call'd to bear my part,</A><br>
-<A NAME=3.5.9>Or show the glory of our art?</A><br>
-<A NAME=3.5.10>And, which is worse, all you have done</A><br>
-<A NAME=3.5.11>Hath been but for a wayward son,</A><br>
-<A NAME=3.5.12>Spiteful and wrathful, who, as others do,</A><br>
-<A NAME=3.5.13>Loves for his own ends, not for you.</A><br>
-<A NAME=3.5.14>But make amends now: get you gone,</A><br>
-<A NAME=3.5.15>And at the pit of Acheron</A><br>
-<A NAME=3.5.16>Meet me i' the morning: thither he</A><br>
-<A NAME=3.5.17>Will come to know his destiny:</A><br>
-<A NAME=3.5.18>Your vessels and your spells provide,</A><br>
-<A NAME=3.5.19>Your charms and every thing beside.</A><br>
-<A NAME=3.5.20>I am for the air; this night I'll spend</A><br>
-<A NAME=3.5.21>Unto a dismal and a fatal end:</A><br>
-<A NAME=3.5.22>Great business must be wrought ere noon:</A><br>
-<A NAME=3.5.23>Upon the corner of the moon</A><br>
-<A NAME=3.5.24>There hangs a vaporous drop profound;</A><br>
-<A NAME=3.5.25>I'll catch it ere it come to ground:</A><br>
-<A NAME=3.5.26>And that distill'd by magic sleights</A><br>
-<A NAME=3.5.27>Shall raise such artificial sprites</A><br>
-<A NAME=3.5.28>As by the strength of their illusion</A><br>
-<A NAME=3.5.29>Shall draw him on to his confusion:</A><br>
-<A NAME=3.5.30>He shall spurn fate, scorn death, and bear</A><br>
-<A NAME=3.5.31>He hopes 'bove wisdom, grace and fear:</A><br>
-<A NAME=3.5.32>And you all know, security</A><br>
-<A NAME=3.5.33>Is mortals' chiefest enemy.</A><br>
-<p><i>Music and a song within: 'Come away, come away,' & c</i></p>
-<A NAME=3.5.34>Hark! I am call'd; my little spirit, see,</A><br>
-<A NAME=3.5.35>Sits in a foggy cloud, and stays for me.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech3><b>First Witch</b></a>
-<blockquote>
-<A NAME=3.5.36>Come, let's make haste; she'll soon be back again.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE VI. Forres. The palace.</h3>
-<p><blockquote>
-<i>Enter LENNOX and another Lord</i>
-</blockquote>
-
-<A NAME=speech1><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.6.1>My former speeches have but hit your thoughts,</A><br>
-<A NAME=3.6.2>Which can interpret further: only, I say,</A><br>
-<A NAME=3.6.3>Things have been strangely borne. The</A><br>
-<A NAME=3.6.4>gracious Duncan</A><br>
-<A NAME=3.6.5>Was pitied of Macbeth: marry, he was dead:</A><br>
-<A NAME=3.6.6>And the right-valiant Banquo walk'd too late;</A><br>
-<A NAME=3.6.7>Whom, you may say, if't please you, Fleance kill'd,</A><br>
-<A NAME=3.6.8>For Fleance fled: men must not walk too late.</A><br>
-<A NAME=3.6.9>Who cannot want the thought how monstrous</A><br>
-<A NAME=3.6.10>It was for Malcolm and for Donalbain</A><br>
-<A NAME=3.6.11>To kill their gracious father? damned fact!</A><br>
-<A NAME=3.6.12>How it did grieve Macbeth! did he not straight</A><br>
-<A NAME=3.6.13>In pious rage the two delinquents tear,</A><br>
-<A NAME=3.6.14>That were the slaves of drink and thralls of sleep?</A><br>
-<A NAME=3.6.15>Was not that nobly done? Ay, and wisely too;</A><br>
-<A NAME=3.6.16>For 'twould have anger'd any heart alive</A><br>
-<A NAME=3.6.17>To hear the men deny't. So that, I say,</A><br>
-<A NAME=3.6.18>He has borne all things well: and I do think</A><br>
-<A NAME=3.6.19>That had he Duncan's sons under his key--</A><br>
-<A NAME=3.6.20>As, an't please heaven, he shall not--they</A><br>
-<A NAME=3.6.21>should find</A><br>
-<A NAME=3.6.22>What 'twere to kill a father; so should Fleance.</A><br>
-<A NAME=3.6.23>But, peace! for from broad words and 'cause he fail'd</A><br>
-<A NAME=3.6.24>His presence at the tyrant's feast, I hear</A><br>
-<A NAME=3.6.25>Macduff lives in disgrace: sir, can you tell</A><br>
-<A NAME=3.6.26>Where he bestows himself?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Lord</b></a>
-<blockquote>
-<A NAME=3.6.27>The son of Duncan,</A><br>
-<A NAME=3.6.28>From whom this tyrant holds the due of birth</A><br>
-<A NAME=3.6.29>Lives in the English court, and is received</A><br>
-<A NAME=3.6.30>Of the most pious Edward with such grace</A><br>
-<A NAME=3.6.31>That the malevolence of fortune nothing</A><br>
-<A NAME=3.6.32>Takes from his high respect: thither Macduff</A><br>
-<A NAME=3.6.33>Is gone to pray the holy king, upon his aid</A><br>
-<A NAME=3.6.34>To wake Northumberland and warlike Siward:</A><br>
-<A NAME=3.6.35>That, by the help of these--with Him above</A><br>
-<A NAME=3.6.36>To ratify the work--we may again</A><br>
-<A NAME=3.6.37>Give to our tables meat, sleep to our nights,</A><br>
-<A NAME=3.6.38>Free from our feasts and banquets bloody knives,</A><br>
-<A NAME=3.6.39>Do faithful homage and receive free honours:</A><br>
-<A NAME=3.6.40>All which we pine for now: and this report</A><br>
-<A NAME=3.6.41>Hath so exasperate the king that he</A><br>
-<A NAME=3.6.42>Prepares for some attempt of war.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.6.43>Sent he to Macduff?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>Lord</b></a>
-<blockquote>
-<A NAME=3.6.44>He did: and with an absolute 'Sir, not I,'</A><br>
-<A NAME=3.6.45>The cloudy messenger turns me his back,</A><br>
-<A NAME=3.6.46>And hums, as who should say 'You'll rue the time</A><br>
-<A NAME=3.6.47>That clogs me with this answer.'</A><br>
-</blockquote>
-
-<A NAME=speech5><b>LENNOX</b></a>
-<blockquote>
-<A NAME=3.6.48>And that well might</A><br>
-<A NAME=3.6.49>Advise him to a caution, to hold what distance</A><br>
-<A NAME=3.6.50>His wisdom can provide. Some holy angel</A><br>
-<A NAME=3.6.51>Fly to the court of England and unfold</A><br>
-<A NAME=3.6.52>His message ere he come, that a swift blessing</A><br>
-<A NAME=3.6.53>May soon return to this our suffering country</A><br>
-<A NAME=3.6.54>Under a hand accursed!</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Lord</b></a>
-<blockquote>
-<A NAME=3.6.55>I'll send my prayers with him.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote><p>
-<H3>ACT IV</h3>
-<h3>SCENE I. A cavern. In the middle, a boiling cauldron.</h3>
-<p><blockquote>
-<i>Thunder. Enter the three Witches</i>
-</blockquote>
-
-<A NAME=speech1><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.1>Thrice the brinded cat hath mew'd.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.2>Thrice and once the hedge-pig whined.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Third Witch</b></a>
-<blockquote>
-<A NAME=4.1.3>Harpier cries 'Tis time, 'tis time.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.4>Round about the cauldron go;</A><br>
-<A NAME=4.1.5>In the poison'd entrails throw.</A><br>
-<A NAME=4.1.6>Toad, that under cold stone</A><br>
-<A NAME=4.1.7>Days and nights has thirty-one</A><br>
-<A NAME=4.1.8>Swelter'd venom sleeping got,</A><br>
-<A NAME=4.1.9>Boil thou first i' the charmed pot.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.10>Double, double toil and trouble;</A><br>
-<A NAME=4.1.11>Fire burn, and cauldron bubble.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.12>Fillet of a fenny snake,</A><br>
-<A NAME=4.1.13>In the cauldron boil and bake;</A><br>
-<A NAME=4.1.14>Eye of newt and toe of frog,</A><br>
-<A NAME=4.1.15>Wool of bat and tongue of dog,</A><br>
-<A NAME=4.1.16>Adder's fork and blind-worm's sting,</A><br>
-<A NAME=4.1.17>Lizard's leg and owlet's wing,</A><br>
-<A NAME=4.1.18>For a charm of powerful trouble,</A><br>
-<A NAME=4.1.19>Like a hell-broth boil and bubble.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.20>Double, double toil and trouble;</A><br>
-<A NAME=4.1.21>Fire burn and cauldron bubble.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>Third Witch</b></a>
-<blockquote>
-<A NAME=4.1.22>Scale of dragon, tooth of wolf,</A><br>
-<A NAME=4.1.23>Witches' mummy, maw and gulf</A><br>
-<A NAME=4.1.24>Of the ravin'd salt-sea shark,</A><br>
-<A NAME=4.1.25>Root of hemlock digg'd i' the dark,</A><br>
-<A NAME=4.1.26>Liver of blaspheming Jew,</A><br>
-<A NAME=4.1.27>Gall of goat, and slips of yew</A><br>
-<A NAME=4.1.28>Silver'd in the moon's eclipse,</A><br>
-<A NAME=4.1.29>Nose of Turk and Tartar's lips,</A><br>
-<A NAME=4.1.30>Finger of birth-strangled babe</A><br>
-<A NAME=4.1.31>Ditch-deliver'd by a drab,</A><br>
-<A NAME=4.1.32>Make the gruel thick and slab:</A><br>
-<A NAME=4.1.33>Add thereto a tiger's chaudron,</A><br>
-<A NAME=4.1.34>For the ingredients of our cauldron.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.35>Double, double toil and trouble;</A><br>
-<A NAME=4.1.36>Fire burn and cauldron bubble.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.37>Cool it with a baboon's blood,</A><br>
-<A NAME=4.1.38>Then the charm is firm and good.</A><br>
-<p><i>Enter HECATE to the other three Witches</i></p>
-</blockquote>
-
-<A NAME=speech11><b>HECATE</b></a>
-<blockquote>
-<A NAME=4.1.39>O well done! I commend your pains;</A><br>
-<A NAME=4.1.40>And every one shall share i' the gains;</A><br>
-<A NAME=4.1.41>And now about the cauldron sing,</A><br>
-<A NAME=4.1.42>Live elves and fairies in a ring,</A><br>
-<A NAME=4.1.43>Enchanting all that you put in.</A><br>
-<p><i>Music and a song: 'Black spirits,' & c</i></p>
-<p><i>HECATE retires</i></p>
-</blockquote>
-
-<A NAME=speech12><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.44>By the pricking of my thumbs,</A><br>
-<A NAME=4.1.45>Something wicked this way comes.</A><br>
-<A NAME=4.1.46>Open, locks,</A><br>
-<A NAME=4.1.47>Whoever knocks!</A><br>
-<p><i>Enter MACBETH</i></p>
-</blockquote>
-
-<A NAME=speech13><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.48>How now, you secret, black, and midnight hags!</A><br>
-<A NAME=4.1.49>What is't you do?</A><br>
-</blockquote>
-
-<A NAME=speech14><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.50> A deed without a name.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.51>I conjure you, by that which you profess,</A><br>
-<A NAME=4.1.52>Howe'er you come to know it, answer me:</A><br>
-<A NAME=4.1.53>Though you untie the winds and let them fight</A><br>
-<A NAME=4.1.54>Against the churches; though the yesty waves</A><br>
-<A NAME=4.1.55>Confound and swallow navigation up;</A><br>
-<A NAME=4.1.56>Though bladed corn be lodged and trees blown down;</A><br>
-<A NAME=4.1.57>Though castles topple on their warders' heads;</A><br>
-<A NAME=4.1.58>Though palaces and pyramids do slope</A><br>
-<A NAME=4.1.59>Their heads to their foundations; though the treasure</A><br>
-<A NAME=4.1.60>Of nature's germens tumble all together,</A><br>
-<A NAME=4.1.61>Even till destruction sicken; answer me</A><br>
-<A NAME=4.1.62>To what I ask you.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.63> Speak.</A><br>
-</blockquote>
-
-<A NAME=speech17><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.64>Demand.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Third Witch</b></a>
-<blockquote>
-<A NAME=4.1.65>We'll answer.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.66>Say, if thou'dst rather hear it from our mouths,</A><br>
-<A NAME=4.1.67>Or from our masters?</A><br>
-</blockquote>
-
-<A NAME=speech20><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.68>Call 'em; let me see 'em.</A><br>
-</blockquote>
-
-<A NAME=speech21><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.69>Pour in sow's blood, that hath eaten</A><br>
-<A NAME=4.1.70>Her nine farrow; grease that's sweaten</A><br>
-<A NAME=4.1.71>From the murderer's gibbet throw</A><br>
-<A NAME=4.1.72>Into the flame.</A><br>
-</blockquote>
-
-<A NAME=speech22><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.73> Come, high or low;</A><br>
-<A NAME=4.1.74>Thyself and office deftly show!</A><br>
-<p><i>Thunder. First Apparition: an armed Head</i></p>
-</blockquote>
-
-<A NAME=speech23><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.75>Tell me, thou unknown power,--</A><br>
-</blockquote>
-
-<A NAME=speech24><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.76>He knows thy thought:</A><br>
-<A NAME=4.1.77>Hear his speech, but say thou nought.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>First Apparition</b></a>
-<blockquote>
-<A NAME=4.1.78>Macbeth! Macbeth! Macbeth! beware Macduff;</A><br>
-<A NAME=4.1.79>Beware the thane of Fife. Dismiss me. Enough.</A><br>
-<p><i>Descends</i></p>
-</blockquote>
-
-<A NAME=speech26><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.80>Whate'er thou art, for thy good caution, thanks;</A><br>
-<A NAME=4.1.81>Thou hast harp'd my fear aright: but one</A><br>
-<A NAME=4.1.82>word more,--</A><br>
-</blockquote>
-
-<A NAME=speech27><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.83>He will not be commanded: here's another,</A><br>
-<A NAME=4.1.84>More potent than the first.</A><br>
-<p><i>Thunder. Second Apparition: A bloody Child</i></p>
-</blockquote>
-
-<A NAME=speech28><b>Second Apparition</b></a>
-<blockquote>
-<A NAME=4.1.85>Macbeth! Macbeth! Macbeth!</A><br>
-</blockquote>
-
-<A NAME=speech29><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.86>Had I three ears, I'ld hear thee.</A><br>
-</blockquote>
-
-<A NAME=speech30><b>Second Apparition</b></a>
-<blockquote>
-<A NAME=4.1.87>Be bloody, bold, and resolute; laugh to scorn</A><br>
-<A NAME=4.1.88>The power of man, for none of woman born</A><br>
-<A NAME=4.1.89>Shall harm Macbeth.</A><br>
-<p><i>Descends</i></p>
-</blockquote>
-
-<A NAME=speech31><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.90>Then live, Macduff: what need I fear of thee?</A><br>
-<A NAME=4.1.91>But yet I'll make assurance double sure,</A><br>
-<A NAME=4.1.92>And take a bond of fate: thou shalt not live;</A><br>
-<A NAME=4.1.93>That I may tell pale-hearted fear it lies,</A><br>
-<A NAME=4.1.94>And sleep in spite of thunder.</A><br>
-<p><i>Thunder. Third Apparition: a Child crowned, with a tree in his hand</i></p>
-<A NAME=4.1.95>What is this</A><br>
-<A NAME=4.1.96>That rises like the issue of a king,</A><br>
-<A NAME=4.1.97>And wears upon his baby-brow the round</A><br>
-<A NAME=4.1.98>And top of sovereignty?</A><br>
-</blockquote>
-
-<A NAME=speech32><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.99>Listen, but speak not to't.</A><br>
-</blockquote>
-
-<A NAME=speech33><b>Third Apparition</b></a>
-<blockquote>
-<A NAME=4.1.100>Be lion-mettled, proud; and take no care</A><br>
-<A NAME=4.1.101>Who chafes, who frets, or where conspirers are:</A><br>
-<A NAME=4.1.102>Macbeth shall never vanquish'd be until</A><br>
-<A NAME=4.1.103>Great Birnam wood to high Dunsinane hill</A><br>
-<A NAME=4.1.104>Shall come against him.</A><br>
-<p><i>Descends</i></p>
-</blockquote>
-
-<A NAME=speech34><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.105>That will never be</A><br>
-<A NAME=4.1.106>Who can impress the forest, bid the tree</A><br>
-<A NAME=4.1.107>Unfix his earth-bound root? Sweet bodements! good!</A><br>
-<A NAME=4.1.108>Rebellion's head, rise never till the wood</A><br>
-<A NAME=4.1.109>Of Birnam rise, and our high-placed Macbeth</A><br>
-<A NAME=4.1.110>Shall live the lease of nature, pay his breath</A><br>
-<A NAME=4.1.111>To time and mortal custom. Yet my heart</A><br>
-<A NAME=4.1.112>Throbs to know one thing: tell me, if your art</A><br>
-<A NAME=4.1.113>Can tell so much: shall Banquo's issue ever</A><br>
-<A NAME=4.1.114>Reign in this kingdom?</A><br>
-</blockquote>
-
-<A NAME=speech35><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.115>Seek to know no more.</A><br>
-</blockquote>
-
-<A NAME=speech36><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.116>I will be satisfied: deny me this,</A><br>
-<A NAME=4.1.117>And an eternal curse fall on you! Let me know.</A><br>
-<A NAME=4.1.118>Why sinks that cauldron? and what noise is this?</A><br>
-<p><i>Hautboys</i></p>
-</blockquote>
-
-<A NAME=speech37><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.119>Show!</A><br>
-</blockquote>
-
-<A NAME=speech38><b>Second Witch</b></a>
-<blockquote>
-<A NAME=4.1.120>Show!</A><br>
-</blockquote>
-
-<A NAME=speech39><b>Third Witch</b></a>
-<blockquote>
-<A NAME=4.1.121>Show!</A><br>
-</blockquote>
-
-<A NAME=speech40><b>ALL</b></a>
-<blockquote>
-<A NAME=4.1.122>Show his eyes, and grieve his heart;</A><br>
-<A NAME=4.1.123>Come like shadows, so depart!</A><br>
-<p><i>A show of Eight Kings, the last with a glass in his hand; GHOST OF BANQUO following</i></p>
-</blockquote>
-
-<A NAME=speech41><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.124>Thou art too like the spirit of Banquo: down!</A><br>
-<A NAME=4.1.125>Thy crown does sear mine eye-balls. And thy hair,</A><br>
-<A NAME=4.1.126>Thou other gold-bound brow, is like the first.</A><br>
-<A NAME=4.1.127>A third is like the former. Filthy hags!</A><br>
-<A NAME=4.1.128>Why do you show me this? A fourth! Start, eyes!</A><br>
-<A NAME=4.1.129>What, will the line stretch out to the crack of doom?</A><br>
-<A NAME=4.1.130>Another yet! A seventh! I'll see no more:</A><br>
-<A NAME=4.1.131>And yet the eighth appears, who bears a glass</A><br>
-<A NAME=4.1.132>Which shows me many more; and some I see</A><br>
-<A NAME=4.1.133>That two-fold balls and treble scepters carry:</A><br>
-<A NAME=4.1.134>Horrible sight! Now, I see, 'tis true;</A><br>
-<A NAME=4.1.135>For the blood-bolter'd Banquo smiles upon me,</A><br>
-<A NAME=4.1.136>And points at them for his.</A><br>
-<p><i>Apparitions vanish</i></p>
-<A NAME=4.1.137>What, is this so?</A><br>
-</blockquote>
-
-<A NAME=speech42><b>First Witch</b></a>
-<blockquote>
-<A NAME=4.1.138>Ay, sir, all this is so: but why</A><br>
-<A NAME=4.1.139>Stands Macbeth thus amazedly?</A><br>
-<A NAME=4.1.140>Come, sisters, cheer we up his sprites,</A><br>
-<A NAME=4.1.141>And show the best of our delights:</A><br>
-<A NAME=4.1.142>I'll charm the air to give a sound,</A><br>
-<A NAME=4.1.143>While you perform your antic round:</A><br>
-<A NAME=4.1.144>That this great king may kindly say,</A><br>
-<A NAME=4.1.145>Our duties did his welcome pay.</A><br>
-<p><i>Music. The witches dance and then vanish, with HECATE</i></p>
-</blockquote>
-
-<A NAME=speech43><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.146>Where are they? Gone? Let this pernicious hour</A><br>
-<A NAME=4.1.147>Stand aye accursed in the calendar!</A><br>
-<A NAME=4.1.148>Come in, without there!</A><br>
-<p><i>Enter LENNOX</i></p>
-</blockquote>
-
-<A NAME=speech44><b>LENNOX</b></a>
-<blockquote>
-<A NAME=4.1.149>What's your grace's will?</A><br>
-</blockquote>
-
-<A NAME=speech45><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.150>Saw you the weird sisters?</A><br>
-</blockquote>
-
-<A NAME=speech46><b>LENNOX</b></a>
-<blockquote>
-<A NAME=4.1.151>No, my lord.</A><br>
-</blockquote>
-
-<A NAME=speech47><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.152>Came they not by you?</A><br>
-</blockquote>
-
-<A NAME=speech48><b>LENNOX</b></a>
-<blockquote>
-<A NAME=4.1.153>No, indeed, my lord.</A><br>
-</blockquote>
-
-<A NAME=speech49><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.154>Infected be the air whereon they ride;</A><br>
-<A NAME=4.1.155>And damn'd all those that trust them! I did hear</A><br>
-<A NAME=4.1.156>The galloping of horse: who was't came by?</A><br>
-</blockquote>
-
-<A NAME=speech50><b>LENNOX</b></a>
-<blockquote>
-<A NAME=4.1.157>'Tis two or three, my lord, that bring you word</A><br>
-<A NAME=4.1.158>Macduff is fled to England.</A><br>
-</blockquote>
-
-<A NAME=speech51><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.159>Fled to England!</A><br>
-</blockquote>
-
-<A NAME=speech52><b>LENNOX</b></a>
-<blockquote>
-<A NAME=4.1.160>Ay, my good lord.</A><br>
-</blockquote>
-
-<A NAME=speech53><b>MACBETH</b></a>
-<blockquote>
-<A NAME=4.1.161>Time, thou anticipatest my dread exploits:</A><br>
-<A NAME=4.1.162>The flighty purpose never is o'ertook</A><br>
-<A NAME=4.1.163>Unless the deed go with it; from this moment</A><br>
-<A NAME=4.1.164>The very firstlings of my heart shall be</A><br>
-<A NAME=4.1.165>The firstlings of my hand. And even now,</A><br>
-<A NAME=4.1.166>To crown my thoughts with acts, be it thought and done:</A><br>
-<A NAME=4.1.167>The castle of Macduff I will surprise;</A><br>
-<A NAME=4.1.168>Seize upon Fife; give to the edge o' the sword</A><br>
-<A NAME=4.1.169>His wife, his babes, and all unfortunate souls</A><br>
-<A NAME=4.1.170>That trace him in his line. No boasting like a fool;</A><br>
-<A NAME=4.1.171>This deed I'll do before this purpose cool.</A><br>
-<A NAME=4.1.172>But no more sights!--Where are these gentlemen?</A><br>
-<A NAME=4.1.173>Come, bring me where they are.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE II. Fife. Macduff's castle.</h3>
-<p><blockquote>
-<i>Enter LADY MACDUFF, her Son, and ROSS</i>
-</blockquote>
-
-<A NAME=speech1><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.1>What had he done, to make him fly the land?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.2.2>You must have patience, madam.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.3>He had none:</A><br>
-<A NAME=4.2.4>His flight was madness: when our actions do not,</A><br>
-<A NAME=4.2.5>Our fears do make us traitors.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.2.6>You know not</A><br>
-<A NAME=4.2.7>Whether it was his wisdom or his fear.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.8>Wisdom! to leave his wife, to leave his babes,</A><br>
-<A NAME=4.2.9>His mansion and his titles in a place</A><br>
-<A NAME=4.2.10>From whence himself does fly? He loves us not;</A><br>
-<A NAME=4.2.11>He wants the natural touch: for the poor wren,</A><br>
-<A NAME=4.2.12>The most diminutive of birds, will fight,</A><br>
-<A NAME=4.2.13>Her young ones in her nest, against the owl.</A><br>
-<A NAME=4.2.14>All is the fear and nothing is the love;</A><br>
-<A NAME=4.2.15>As little is the wisdom, where the flight</A><br>
-<A NAME=4.2.16>So runs against all reason.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.2.17>My dearest coz,</A><br>
-<A NAME=4.2.18>I pray you, school yourself: but for your husband,</A><br>
-<A NAME=4.2.19>He is noble, wise, judicious, and best knows</A><br>
-<A NAME=4.2.20>The fits o' the season. I dare not speak</A><br>
-<A NAME=4.2.21>much further;</A><br>
-<A NAME=4.2.22>But cruel are the times, when we are traitors</A><br>
-<A NAME=4.2.23>And do not know ourselves, when we hold rumour</A><br>
-<A NAME=4.2.24>From what we fear, yet know not what we fear,</A><br>
-<A NAME=4.2.25>But float upon a wild and violent sea</A><br>
-<A NAME=4.2.26>Each way and move. I take my leave of you:</A><br>
-<A NAME=4.2.27>Shall not be long but I'll be here again:</A><br>
-<A NAME=4.2.28>Things at the worst will cease, or else climb upward</A><br>
-<A NAME=4.2.29>To what they were before. My pretty cousin,</A><br>
-<A NAME=4.2.30>Blessing upon you!</A><br>
-</blockquote>
-
-<A NAME=speech7><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.31>Father'd he is, and yet he's fatherless.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.2.32>I am so much a fool, should I stay longer,</A><br>
-<A NAME=4.2.33>It would be my disgrace and your discomfort:</A><br>
-<A NAME=4.2.34>I take my leave at once.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech9><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.35>Sirrah, your father's dead;</A><br>
-<A NAME=4.2.36>And what will you do now? How will you live?</A><br>
-</blockquote>
-
-<A NAME=speech10><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.37>As birds do, mother.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.38>What, with worms and flies?</A><br>
-</blockquote>
-
-<A NAME=speech12><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.39>With what I get, I mean; and so do they.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.40>Poor bird! thou'ldst never fear the net nor lime,</A><br>
-<A NAME=4.2.41>The pitfall nor the gin.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.42>Why should I, mother? Poor birds they are not set for.</A><br>
-<A NAME=4.2.43>My father is not dead, for all your saying.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.44>Yes, he is dead; how wilt thou do for a father?</A><br>
-</blockquote>
-
-<A NAME=speech16><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.45>Nay, how will you do for a husband?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.46>Why, I can buy me twenty at any market.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.47>Then you'll buy 'em to sell again.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.48>Thou speak'st with all thy wit: and yet, i' faith,</A><br>
-<A NAME=4.2.49>With wit enough for thee.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.50>Was my father a traitor, mother?</A><br>
-</blockquote>
-
-<A NAME=speech21><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.51>Ay, that he was.</A><br>
-</blockquote>
-
-<A NAME=speech22><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.52>What is a traitor?</A><br>
-</blockquote>
-
-<A NAME=speech23><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.53>Why, one that swears and lies.</A><br>
-</blockquote>
-
-<A NAME=speech24><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.54>And be all traitors that do so?</A><br>
-</blockquote>
-
-<A NAME=speech25><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.55>Every one that does so is a traitor, and must be hanged.</A><br>
-</blockquote>
-
-<A NAME=speech26><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.56>And must they all be hanged that swear and lie?</A><br>
-</blockquote>
-
-<A NAME=speech27><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.57>Every one.</A><br>
-</blockquote>
-
-<A NAME=speech28><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.58>Who must hang them?</A><br>
-</blockquote>
-
-<A NAME=speech29><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.59>Why, the honest men.</A><br>
-</blockquote>
-
-<A NAME=speech30><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.60>Then the liars and swearers are fools,</A><br>
-<A NAME=4.2.61>for there are liars and swearers enow to beat</A><br>
-<A NAME=4.2.62>the honest men and hang up them.</A><br>
-</blockquote>
-
-<A NAME=speech31><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.63>Now, God help thee, poor monkey!</A><br>
-<A NAME=4.2.64>But how wilt thou do for a father?</A><br>
-</blockquote>
-
-<A NAME=speech32><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.65>If he were dead, you'ld weep for</A><br>
-<A NAME=4.2.66>him: if you would not, it were a good sign</A><br>
-<A NAME=4.2.67>that I should quickly have a new father.</A><br>
-</blockquote>
-
-<A NAME=speech33><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.68>Poor prattler, how thou talk'st!</A><br>
-<p><i>Enter a Messenger</i></p>
-</blockquote>
-
-<A NAME=speech34><b>Messenger</b></a>
-<blockquote>
-<A NAME=4.2.69>Bless you, fair dame! I am not to you known,</A><br>
-<A NAME=4.2.70>Though in your state of honour I am perfect.</A><br>
-<A NAME=4.2.71>I doubt some danger does approach you nearly:</A><br>
-<A NAME=4.2.72>If you will take a homely man's advice,</A><br>
-<A NAME=4.2.73>Be not found here; hence, with your little ones.</A><br>
-<A NAME=4.2.74>To fright you thus, methinks, I am too savage;</A><br>
-<A NAME=4.2.75>To do worse to you were fell cruelty,</A><br>
-<A NAME=4.2.76>Which is too nigh your person. Heaven preserve you!</A><br>
-<A NAME=4.2.77>I dare abide no longer.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech35><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.78>Whither should I fly?</A><br>
-<A NAME=4.2.79>I have done no harm. But I remember now</A><br>
-<A NAME=4.2.80>I am in this earthly world; where to do harm</A><br>
-<A NAME=4.2.81>Is often laudable, to do good sometime</A><br>
-<A NAME=4.2.82>Accounted dangerous folly: why then, alas,</A><br>
-<A NAME=4.2.83>Do I put up that womanly defence,</A><br>
-<A NAME=4.2.84>To say I have done no harm?</A><br>
-<p><i>Enter Murderers</i></p>
-<A NAME=4.2.85>What are these faces?</A><br>
-</blockquote>
-
-<A NAME=speech36><b>First Murderer</b></a>
-<blockquote>
-<A NAME=4.2.86>Where is your husband?</A><br>
-</blockquote>
-
-<A NAME=speech37><b>LADY MACDUFF</b></a>
-<blockquote>
-<A NAME=4.2.87>I hope, in no place so unsanctified</A><br>
-<A NAME=4.2.88>Where such as thou mayst find him.</A><br>
-</blockquote>
-
-<A NAME=speech38><b>First Murderer</b></a>
-<blockquote>
-<A NAME=4.2.89>He's a traitor.</A><br>
-</blockquote>
-
-<A NAME=speech39><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.90>Thou liest, thou shag-hair'd villain!</A><br>
-</blockquote>
-
-<A NAME=speech40><b>First Murderer</b></a>
-<blockquote>
-<A NAME=4.2.91>What, you egg!</A><br>
-<p><i>Stabbing him</i></p>
-<A NAME=4.2.92>Young fry of treachery!</A><br>
-</blockquote>
-
-<A NAME=speech41><b>Son</b></a>
-<blockquote>
-<A NAME=4.2.93>He has kill'd me, mother:</A><br>
-<A NAME=4.2.94>Run away, I pray you!</A><br>
-<p><i>Dies</i></p>
-<p><i>Exit LADY MACDUFF, crying 'Murder!' Exeunt Murderers, following her</i></p>
-</blockquote>
-<h3>SCENE III. England. Before the King's palace.</h3>
-<p><blockquote>
-<i>Enter MALCOLM and MACDUFF</i>
-</blockquote>
-
-<A NAME=speech1><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.1>Let us seek out some desolate shade, and there</A><br>
-<A NAME=4.3.2>Weep our sad bosoms empty.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.3>Let us rather</A><br>
-<A NAME=4.3.4>Hold fast the mortal sword, and like good men</A><br>
-<A NAME=4.3.5>Bestride our down-fall'n birthdom: each new morn</A><br>
-<A NAME=4.3.6>New widows howl, new orphans cry, new sorrows</A><br>
-<A NAME=4.3.7>Strike heaven on the face, that it resounds</A><br>
-<A NAME=4.3.8>As if it felt with Scotland and yell'd out</A><br>
-<A NAME=4.3.9>Like syllable of dolour.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.10>What I believe I'll wail,</A><br>
-<A NAME=4.3.11>What know believe, and what I can redress,</A><br>
-<A NAME=4.3.12>As I shall find the time to friend, I will.</A><br>
-<A NAME=4.3.13>What you have spoke, it may be so perchance.</A><br>
-<A NAME=4.3.14>This tyrant, whose sole name blisters our tongues,</A><br>
-<A NAME=4.3.15>Was once thought honest: you have loved him well.</A><br>
-<A NAME=4.3.16>He hath not touch'd you yet. I am young;</A><br>
-<A NAME=4.3.17>but something</A><br>
-<A NAME=4.3.18>You may deserve of him through me, and wisdom</A><br>
-<A NAME=4.3.19>To offer up a weak poor innocent lamb</A><br>
-<A NAME=4.3.20>To appease an angry god.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.21>I am not treacherous.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.22>But Macbeth is.</A><br>
-<A NAME=4.3.23>A good and virtuous nature may recoil</A><br>
-<A NAME=4.3.24>In an imperial charge. But I shall crave</A><br>
-<A NAME=4.3.25>your pardon;</A><br>
-<A NAME=4.3.26>That which you are my thoughts cannot transpose:</A><br>
-<A NAME=4.3.27>Angels are bright still, though the brightest fell;</A><br>
-<A NAME=4.3.28>Though all things foul would wear the brows of grace,</A><br>
-<A NAME=4.3.29>Yet grace must still look so.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.30>I have lost my hopes.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.31>Perchance even there where I did find my doubts.</A><br>
-<A NAME=4.3.32>Why in that rawness left you wife and child,</A><br>
-<A NAME=4.3.33>Those precious motives, those strong knots of love,</A><br>
-<A NAME=4.3.34>Without leave-taking? I pray you,</A><br>
-<A NAME=4.3.35>Let not my jealousies be your dishonours,</A><br>
-<A NAME=4.3.36>But mine own safeties. You may be rightly just,</A><br>
-<A NAME=4.3.37>Whatever I shall think.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.38>Bleed, bleed, poor country!</A><br>
-<A NAME=4.3.39>Great tyranny! lay thou thy basis sure,</A><br>
-<A NAME=4.3.40>For goodness dare not cheque thee: wear thou</A><br>
-<A NAME=4.3.41>thy wrongs;</A><br>
-<A NAME=4.3.42>The title is affeer'd! Fare thee well, lord:</A><br>
-<A NAME=4.3.43>I would not be the villain that thou think'st</A><br>
-<A NAME=4.3.44>For the whole space that's in the tyrant's grasp,</A><br>
-<A NAME=4.3.45>And the rich East to boot.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.46>Be not offended:</A><br>
-<A NAME=4.3.47>I speak not as in absolute fear of you.</A><br>
-<A NAME=4.3.48>I think our country sinks beneath the yoke;</A><br>
-<A NAME=4.3.49>It weeps, it bleeds; and each new day a gash</A><br>
-<A NAME=4.3.50>Is added to her wounds: I think withal</A><br>
-<A NAME=4.3.51>There would be hands uplifted in my right;</A><br>
-<A NAME=4.3.52>And here from gracious England have I offer</A><br>
-<A NAME=4.3.53>Of goodly thousands: but, for all this,</A><br>
-<A NAME=4.3.54>When I shall tread upon the tyrant's head,</A><br>
-<A NAME=4.3.55>Or wear it on my sword, yet my poor country</A><br>
-<A NAME=4.3.56>Shall have more vices than it had before,</A><br>
-<A NAME=4.3.57>More suffer and more sundry ways than ever,</A><br>
-<A NAME=4.3.58>By him that shall succeed.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.59>What should he be?</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.60>It is myself I mean: in whom I know</A><br>
-<A NAME=4.3.61>All the particulars of vice so grafted</A><br>
-<A NAME=4.3.62>That, when they shall be open'd, black Macbeth</A><br>
-<A NAME=4.3.63>Will seem as pure as snow, and the poor state</A><br>
-<A NAME=4.3.64>Esteem him as a lamb, being compared</A><br>
-<A NAME=4.3.65>With my confineless harms.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.66>Not in the legions</A><br>
-<A NAME=4.3.67>Of horrid hell can come a devil more damn'd</A><br>
-<A NAME=4.3.68>In evils to top Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.69>I grant him bloody,</A><br>
-<A NAME=4.3.70>Luxurious, avaricious, false, deceitful,</A><br>
-<A NAME=4.3.71>Sudden, malicious, smacking of every sin</A><br>
-<A NAME=4.3.72>That has a name: but there's no bottom, none,</A><br>
-<A NAME=4.3.73>In my voluptuousness: your wives, your daughters,</A><br>
-<A NAME=4.3.74>Your matrons and your maids, could not fill up</A><br>
-<A NAME=4.3.75>The cistern of my lust, and my desire</A><br>
-<A NAME=4.3.76>All continent impediments would o'erbear</A><br>
-<A NAME=4.3.77>That did oppose my will: better Macbeth</A><br>
-<A NAME=4.3.78>Than such an one to reign.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.79>Boundless intemperance</A><br>
-<A NAME=4.3.80>In nature is a tyranny; it hath been</A><br>
-<A NAME=4.3.81>The untimely emptying of the happy throne</A><br>
-<A NAME=4.3.82>And fall of many kings. But fear not yet</A><br>
-<A NAME=4.3.83>To take upon you what is yours: you may</A><br>
-<A NAME=4.3.84>Convey your pleasures in a spacious plenty,</A><br>
-<A NAME=4.3.85>And yet seem cold, the time you may so hoodwink.</A><br>
-<A NAME=4.3.86>We have willing dames enough: there cannot be</A><br>
-<A NAME=4.3.87>That vulture in you, to devour so many</A><br>
-<A NAME=4.3.88>As will to greatness dedicate themselves,</A><br>
-<A NAME=4.3.89>Finding it so inclined.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.90>With this there grows</A><br>
-<A NAME=4.3.91>In my most ill-composed affection such</A><br>
-<A NAME=4.3.92>A stanchless avarice that, were I king,</A><br>
-<A NAME=4.3.93>I should cut off the nobles for their lands,</A><br>
-<A NAME=4.3.94>Desire his jewels and this other's house:</A><br>
-<A NAME=4.3.95>And my more-having would be as a sauce</A><br>
-<A NAME=4.3.96>To make me hunger more; that I should forge</A><br>
-<A NAME=4.3.97>Quarrels unjust against the good and loyal,</A><br>
-<A NAME=4.3.98>Destroying them for wealth.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.99>This avarice</A><br>
-<A NAME=4.3.100>Sticks deeper, grows with more pernicious root</A><br>
-<A NAME=4.3.101>Than summer-seeming lust, and it hath been</A><br>
-<A NAME=4.3.102>The sword of our slain kings: yet do not fear;</A><br>
-<A NAME=4.3.103>Scotland hath foisons to fill up your will.</A><br>
-<A NAME=4.3.104>Of your mere own: all these are portable,</A><br>
-<A NAME=4.3.105>With other graces weigh'd.</A><br>
-</blockquote>
-
-<A NAME=speech17><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.106>But I have none: the king-becoming graces,</A><br>
-<A NAME=4.3.107>As justice, verity, temperance, stableness,</A><br>
-<A NAME=4.3.108>Bounty, perseverance, mercy, lowliness,</A><br>
-<A NAME=4.3.109>Devotion, patience, courage, fortitude,</A><br>
-<A NAME=4.3.110>I have no relish of them, but abound</A><br>
-<A NAME=4.3.111>In the division of each several crime,</A><br>
-<A NAME=4.3.112>Acting it many ways. Nay, had I power, I should</A><br>
-<A NAME=4.3.113>Pour the sweet milk of concord into hell,</A><br>
-<A NAME=4.3.114>Uproar the universal peace, confound</A><br>
-<A NAME=4.3.115>All unity on earth.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.116>O Scotland, Scotland!</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.117>If such a one be fit to govern, speak:</A><br>
-<A NAME=4.3.118>I am as I have spoken.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.119>Fit to govern!</A><br>
-<A NAME=4.3.120>No, not to live. O nation miserable,</A><br>
-<A NAME=4.3.121>With an untitled tyrant bloody-scepter'd,</A><br>
-<A NAME=4.3.122>When shalt thou see thy wholesome days again,</A><br>
-<A NAME=4.3.123>Since that the truest issue of thy throne</A><br>
-<A NAME=4.3.124>By his own interdiction stands accursed,</A><br>
-<A NAME=4.3.125>And does blaspheme his breed? Thy royal father</A><br>
-<A NAME=4.3.126>Was a most sainted king: the queen that bore thee,</A><br>
-<A NAME=4.3.127>Oftener upon her knees than on her feet,</A><br>
-<A NAME=4.3.128>Died every day she lived. Fare thee well!</A><br>
-<A NAME=4.3.129>These evils thou repeat'st upon thyself</A><br>
-<A NAME=4.3.130>Have banish'd me from Scotland. O my breast,</A><br>
-<A NAME=4.3.131>Thy hope ends here!</A><br>
-</blockquote>
-
-<A NAME=speech21><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.132>Macduff, this noble passion,</A><br>
-<A NAME=4.3.133>Child of integrity, hath from my soul</A><br>
-<A NAME=4.3.134>Wiped the black scruples, reconciled my thoughts</A><br>
-<A NAME=4.3.135>To thy good truth and honour. Devilish Macbeth</A><br>
-<A NAME=4.3.136>By many of these trains hath sought to win me</A><br>
-<A NAME=4.3.137>Into his power, and modest wisdom plucks me</A><br>
-<A NAME=4.3.138>From over-credulous haste: but God above</A><br>
-<A NAME=4.3.139>Deal between thee and me! for even now</A><br>
-<A NAME=4.3.140>I put myself to thy direction, and</A><br>
-<A NAME=4.3.141>Unspeak mine own detraction, here abjure</A><br>
-<A NAME=4.3.142>The taints and blames I laid upon myself,</A><br>
-<A NAME=4.3.143>For strangers to my nature. I am yet</A><br>
-<A NAME=4.3.144>Unknown to woman, never was forsworn,</A><br>
-<A NAME=4.3.145>Scarcely have coveted what was mine own,</A><br>
-<A NAME=4.3.146>At no time broke my faith, would not betray</A><br>
-<A NAME=4.3.147>The devil to his fellow and delight</A><br>
-<A NAME=4.3.148>No less in truth than life: my first false speaking</A><br>
-<A NAME=4.3.149>Was this upon myself: what I am truly,</A><br>
-<A NAME=4.3.150>Is thine and my poor country's to command:</A><br>
-<A NAME=4.3.151>Whither indeed, before thy here-approach,</A><br>
-<A NAME=4.3.152>Old Siward, with ten thousand warlike men,</A><br>
-<A NAME=4.3.153>Already at a point, was setting forth.</A><br>
-<A NAME=4.3.154>Now we'll together; and the chance of goodness</A><br>
-<A NAME=4.3.155>Be like our warranted quarrel! Why are you silent?</A><br>
-</blockquote>
-
-<A NAME=speech22><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.156>Such welcome and unwelcome things at once</A><br>
-<A NAME=4.3.157>'Tis hard to reconcile.</A><br>
-<p><i>Enter a Doctor</i></p>
-</blockquote>
-
-<A NAME=speech23><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.158>Well; more anon.--Comes the king forth, I pray you?</A><br>
-</blockquote>
-
-<A NAME=speech24><b>Doctor</b></a>
-<blockquote>
-<A NAME=4.3.159>Ay, sir; there are a crew of wretched souls</A><br>
-<A NAME=4.3.160>That stay his cure: their malady convinces</A><br>
-<A NAME=4.3.161>The great assay of art; but at his touch--</A><br>
-<A NAME=4.3.162>Such sanctity hath heaven given his hand--</A><br>
-<A NAME=4.3.163>They presently amend.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.164>I thank you, doctor.</A><br>
-<p><i>Exit Doctor</i></p>
-</blockquote>
-
-<A NAME=speech26><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.165>What's the disease he means?</A><br>
-</blockquote>
-
-<A NAME=speech27><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.166>'Tis call'd the evil:</A><br>
-<A NAME=4.3.167>A most miraculous work in this good king;</A><br>
-<A NAME=4.3.168>Which often, since my here-remain in England,</A><br>
-<A NAME=4.3.169>I have seen him do. How he solicits heaven,</A><br>
-<A NAME=4.3.170>Himself best knows: but strangely-visited people,</A><br>
-<A NAME=4.3.171>All swoln and ulcerous, pitiful to the eye,</A><br>
-<A NAME=4.3.172>The mere despair of surgery, he cures,</A><br>
-<A NAME=4.3.173>Hanging a golden stamp about their necks,</A><br>
-<A NAME=4.3.174>Put on with holy prayers: and 'tis spoken,</A><br>
-<A NAME=4.3.175>To the succeeding royalty he leaves</A><br>
-<A NAME=4.3.176>The healing benediction. With this strange virtue,</A><br>
-<A NAME=4.3.177>He hath a heavenly gift of prophecy,</A><br>
-<A NAME=4.3.178>And sundry blessings hang about his throne,</A><br>
-<A NAME=4.3.179>That speak him full of grace.</A><br>
-<p><i>Enter ROSS</i></p>
-</blockquote>
-
-<A NAME=speech28><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.180>See, who comes here?</A><br>
-</blockquote>
-
-<A NAME=speech29><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.181>My countryman; but yet I know him not.</A><br>
-</blockquote>
-
-<A NAME=speech30><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.182>My ever-gentle cousin, welcome hither.</A><br>
-</blockquote>
-
-<A NAME=speech31><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.183>I know him now. Good God, betimes remove</A><br>
-<A NAME=4.3.184>The means that makes us strangers!</A><br>
-</blockquote>
-
-<A NAME=speech32><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.185>Sir, amen.</A><br>
-</blockquote>
-
-<A NAME=speech33><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.186>Stands Scotland where it did?</A><br>
-</blockquote>
-
-<A NAME=speech34><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.187>Alas, poor country!</A><br>
-<A NAME=4.3.188>Almost afraid to know itself. It cannot</A><br>
-<A NAME=4.3.189>Be call'd our mother, but our grave; where nothing,</A><br>
-<A NAME=4.3.190>But who knows nothing, is once seen to smile;</A><br>
-<A NAME=4.3.191>Where sighs and groans and shrieks that rend the air</A><br>
-<A NAME=4.3.192>Are made, not mark'd; where violent sorrow seems</A><br>
-<A NAME=4.3.193>A modern ecstasy; the dead man's knell</A><br>
-<A NAME=4.3.194>Is there scarce ask'd for who; and good men's lives</A><br>
-<A NAME=4.3.195>Expire before the flowers in their caps,</A><br>
-<A NAME=4.3.196>Dying or ere they sicken.</A><br>
-</blockquote>
-
-<A NAME=speech35><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.197>O, relation</A><br>
-<A NAME=4.3.198>Too nice, and yet too true!</A><br>
-</blockquote>
-
-<A NAME=speech36><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.199>What's the newest grief?</A><br>
-</blockquote>
-
-<A NAME=speech37><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.200>That of an hour's age doth hiss the speaker:</A><br>
-<A NAME=4.3.201>Each minute teems a new one.</A><br>
-</blockquote>
-
-<A NAME=speech38><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.202>How does my wife?</A><br>
-</blockquote>
-
-<A NAME=speech39><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.203>Why, well.</A><br>
-</blockquote>
-
-<A NAME=speech40><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.204> And all my children?</A><br>
-</blockquote>
-
-<A NAME=speech41><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.205>Well too.</A><br>
-</blockquote>
-
-<A NAME=speech42><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.206>The tyrant has not batter'd at their peace?</A><br>
-</blockquote>
-
-<A NAME=speech43><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.207>No; they were well at peace when I did leave 'em.</A><br>
-</blockquote>
-
-<A NAME=speech44><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.208>But not a niggard of your speech: how goes't?</A><br>
-</blockquote>
-
-<A NAME=speech45><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.209>When I came hither to transport the tidings,</A><br>
-<A NAME=4.3.210>Which I have heavily borne, there ran a rumour</A><br>
-<A NAME=4.3.211>Of many worthy fellows that were out;</A><br>
-<A NAME=4.3.212>Which was to my belief witness'd the rather,</A><br>
-<A NAME=4.3.213>For that I saw the tyrant's power a-foot:</A><br>
-<A NAME=4.3.214>Now is the time of help; your eye in Scotland</A><br>
-<A NAME=4.3.215>Would create soldiers, make our women fight,</A><br>
-<A NAME=4.3.216>To doff their dire distresses.</A><br>
-</blockquote>
-
-<A NAME=speech46><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.217>Be't their comfort</A><br>
-<A NAME=4.3.218>We are coming thither: gracious England hath</A><br>
-<A NAME=4.3.219>Lent us good Siward and ten thousand men;</A><br>
-<A NAME=4.3.220>An older and a better soldier none</A><br>
-<A NAME=4.3.221>That Christendom gives out.</A><br>
-</blockquote>
-
-<A NAME=speech47><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.222>Would I could answer</A><br>
-<A NAME=4.3.223>This comfort with the like! But I have words</A><br>
-<A NAME=4.3.224>That would be howl'd out in the desert air,</A><br>
-<A NAME=4.3.225>Where hearing should not latch them.</A><br>
-</blockquote>
-
-<A NAME=speech48><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.226>What concern they?</A><br>
-<A NAME=4.3.227>The general cause? or is it a fee-grief</A><br>
-<A NAME=4.3.228>Due to some single breast?</A><br>
-</blockquote>
-
-<A NAME=speech49><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.229>No mind that's honest</A><br>
-<A NAME=4.3.230>But in it shares some woe; though the main part</A><br>
-<A NAME=4.3.231>Pertains to you alone.</A><br>
-</blockquote>
-
-<A NAME=speech50><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.232>If it be mine,</A><br>
-<A NAME=4.3.233>Keep it not from me, quickly let me have it.</A><br>
-</blockquote>
-
-<A NAME=speech51><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.234>Let not your ears despise my tongue for ever,</A><br>
-<A NAME=4.3.235>Which shall possess them with the heaviest sound</A><br>
-<A NAME=4.3.236>That ever yet they heard.</A><br>
-</blockquote>
-
-<A NAME=speech52><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.237>Hum! I guess at it.</A><br>
-</blockquote>
-
-<A NAME=speech53><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.238>Your castle is surprised; your wife and babes</A><br>
-<A NAME=4.3.239>Savagely slaughter'd: to relate the manner,</A><br>
-<A NAME=4.3.240>Were, on the quarry of these murder'd deer,</A><br>
-<A NAME=4.3.241>To add the death of you.</A><br>
-</blockquote>
-
-<A NAME=speech54><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.242>Merciful heaven!</A><br>
-<A NAME=4.3.243>What, man! ne'er pull your hat upon your brows;</A><br>
-<A NAME=4.3.244>Give sorrow words: the grief that does not speak</A><br>
-<A NAME=4.3.245>Whispers the o'er-fraught heart and bids it break.</A><br>
-</blockquote>
-
-<A NAME=speech55><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.246>My children too?</A><br>
-</blockquote>
-
-<A NAME=speech56><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.247> Wife, children, servants, all</A><br>
-<A NAME=4.3.248>That could be found.</A><br>
-</blockquote>
-
-<A NAME=speech57><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.249>And I must be from thence!</A><br>
-<A NAME=4.3.250>My wife kill'd too?</A><br>
-</blockquote>
-
-<A NAME=speech58><b>ROSS</b></a>
-<blockquote>
-<A NAME=4.3.251>I have said.</A><br>
-</blockquote>
-
-<A NAME=speech59><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.252>Be comforted:</A><br>
-<A NAME=4.3.253>Let's make us medicines of our great revenge,</A><br>
-<A NAME=4.3.254>To cure this deadly grief.</A><br>
-</blockquote>
-
-<A NAME=speech60><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.255>He has no children. All my pretty ones?</A><br>
-<A NAME=4.3.256>Did you say all? O hell-kite! All?</A><br>
-<A NAME=4.3.257>What, all my pretty chickens and their dam</A><br>
-<A NAME=4.3.258>At one fell swoop?</A><br>
-</blockquote>
-
-<A NAME=speech61><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.259>Dispute it like a man.</A><br>
-</blockquote>
-
-<A NAME=speech62><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.260>I shall do so;</A><br>
-<A NAME=4.3.261>But I must also feel it as a man:</A><br>
-<A NAME=4.3.262>I cannot but remember such things were,</A><br>
-<A NAME=4.3.263>That were most precious to me. Did heaven look on,</A><br>
-<A NAME=4.3.264>And would not take their part? Sinful Macduff,</A><br>
-<A NAME=4.3.265>They were all struck for thee! naught that I am,</A><br>
-<A NAME=4.3.266>Not for their own demerits, but for mine,</A><br>
-<A NAME=4.3.267>Fell slaughter on their souls. Heaven rest them now!</A><br>
-</blockquote>
-
-<A NAME=speech63><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.268>Be this the whetstone of your sword: let grief</A><br>
-<A NAME=4.3.269>Convert to anger; blunt not the heart, enrage it.</A><br>
-</blockquote>
-
-<A NAME=speech64><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=4.3.270>O, I could play the woman with mine eyes</A><br>
-<A NAME=4.3.271>And braggart with my tongue! But, gentle heavens,</A><br>
-<A NAME=4.3.272>Cut short all intermission; front to front</A><br>
-<A NAME=4.3.273>Bring thou this fiend of Scotland and myself;</A><br>
-<A NAME=4.3.274>Within my sword's length set him; if he 'scape,</A><br>
-<A NAME=4.3.275>Heaven forgive him too!</A><br>
-</blockquote>
-
-<A NAME=speech65><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=4.3.276>This tune goes manly.</A><br>
-<A NAME=4.3.277>Come, go we to the king; our power is ready;</A><br>
-<A NAME=4.3.278>Our lack is nothing but our leave; Macbeth</A><br>
-<A NAME=4.3.279>Is ripe for shaking, and the powers above</A><br>
-<A NAME=4.3.280>Put on their instruments. Receive what cheer you may:</A><br>
-<A NAME=4.3.281>The night is long that never finds the day.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote><p>
-<H3>ACT V</h3>
-<h3>SCENE I. Dunsinane. Ante-room in the castle.</h3>
-<p><blockquote>
-<i>Enter a Doctor of Physic and a Waiting-Gentlewoman</i>
-</blockquote>
-
-<A NAME=speech1><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.1>I have two nights watched with you, but can perceive</A><br>
-<A NAME=5.1.2>no truth in your report. When was it she last walked?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.3>Since his majesty went into the field, I have seen</A><br>
-<A NAME=5.1.4>her rise from her bed, throw her night-gown upon</A><br>
-<A NAME=5.1.5>her, unlock her closet, take forth paper, fold it,</A><br>
-<A NAME=5.1.6>write upon't, read it, afterwards seal it, and again</A><br>
-<A NAME=5.1.7>return to bed; yet all this while in a most fast sleep.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.8>A great perturbation in nature, to receive at once</A><br>
-<A NAME=5.1.9>the benefit of sleep, and do the effects of</A><br>
-<A NAME=5.1.10>watching! In this slumbery agitation, besides her</A><br>
-<A NAME=5.1.11>walking and other actual performances, what, at any</A><br>
-<A NAME=5.1.12>time, have you heard her say?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.13>That, sir, which I will not report after her.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.14>You may to me: and 'tis most meet you should.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.15>Neither to you nor any one; having no witness to</A><br>
-<A NAME=5.1.16>confirm my speech.</A><br>
-<p><i>Enter LADY MACBETH, with a taper</i></p>
-<A NAME=5.1.17>Lo you, here she comes! This is her very guise;</A><br>
-<A NAME=5.1.18>and, upon my life, fast asleep. Observe her; stand close.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.19>How came she by that light?</A><br>
-</blockquote>
-
-<A NAME=speech8><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.20>Why, it stood by her: she has light by her</A><br>
-<A NAME=5.1.21>continually; 'tis her command.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.22>You see, her eyes are open.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.23>Ay, but their sense is shut.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.24>What is it she does now? Look, how she rubs her hands.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.25>It is an accustomed action with her, to seem thus</A><br>
-<A NAME=5.1.26>washing her hands: I have known her continue in</A><br>
-<A NAME=5.1.27>this a quarter of an hour.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.28>Yet here's a spot.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.29>Hark! she speaks: I will set down what comes from</A><br>
-<A NAME=5.1.30>her, to satisfy my remembrance the more strongly.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.31>Out, damned spot! out, I say!--One: two: why,</A><br>
-<A NAME=5.1.32>then, 'tis time to do't.--Hell is murky!--Fie, my</A><br>
-<A NAME=5.1.33>lord, fie! a soldier, and afeard? What need we</A><br>
-<A NAME=5.1.34>fear who knows it, when none can call our power to</A><br>
-<A NAME=5.1.35>account?--Yet who would have thought the old man</A><br>
-<A NAME=5.1.36>to have had so much blood in him.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.37>Do you mark that?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.38>The thane of Fife had a wife: where is she now?--</A><br>
-<A NAME=5.1.39>What, will these hands ne'er be clean?--No more o'</A><br>
-<A NAME=5.1.40>that, my lord, no more o' that: you mar all with</A><br>
-<A NAME=5.1.41>this starting.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.42>Go to, go to; you have known what you should not.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.43>She has spoke what she should not, I am sure of</A><br>
-<A NAME=5.1.44>that: heaven knows what she has known.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.45>Here's the smell of the blood still: all the</A><br>
-<A NAME=5.1.46>perfumes of Arabia will not sweeten this little</A><br>
-<A NAME=5.1.47>hand. Oh, oh, oh!</A><br>
-</blockquote>
-
-<A NAME=speech21><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.48>What a sigh is there! The heart is sorely charged.</A><br>
-</blockquote>
-
-<A NAME=speech22><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.49>I would not have such a heart in my bosom for the</A><br>
-<A NAME=5.1.50>dignity of the whole body.</A><br>
-</blockquote>
-
-<A NAME=speech23><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.51>Well, well, well,--</A><br>
-</blockquote>
-
-<A NAME=speech24><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.52>Pray God it be, sir.</A><br>
-</blockquote>
-
-<A NAME=speech25><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.53>This disease is beyond my practise: yet I have known</A><br>
-<A NAME=5.1.54>those which have walked in their sleep who have died</A><br>
-<A NAME=5.1.55>holily in their beds.</A><br>
-</blockquote>
-
-<A NAME=speech26><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.56>Wash your hands, put on your nightgown; look not so</A><br>
-<A NAME=5.1.57>pale.--I tell you yet again, Banquo's buried; he</A><br>
-<A NAME=5.1.58>cannot come out on's grave.</A><br>
-</blockquote>
-
-<A NAME=speech27><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.59>Even so?</A><br>
-</blockquote>
-
-<A NAME=speech28><b>LADY MACBETH</b></a>
-<blockquote>
-<A NAME=5.1.60>To bed, to bed! there's knocking at the gate:</A><br>
-<A NAME=5.1.61>come, come, come, come, give me your hand. What's</A><br>
-<A NAME=5.1.62>done cannot be undone.--To bed, to bed, to bed!</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech29><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.63>Will she go now to bed?</A><br>
-</blockquote>
-
-<A NAME=speech30><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.64>Directly.</A><br>
-</blockquote>
-
-<A NAME=speech31><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.1.65>Foul whisperings are abroad: unnatural deeds</A><br>
-<A NAME=5.1.66>Do breed unnatural troubles: infected minds</A><br>
-<A NAME=5.1.67>To their deaf pillows will discharge their secrets:</A><br>
-<A NAME=5.1.68>More needs she the divine than the physician.</A><br>
-<A NAME=5.1.69>God, God forgive us all! Look after her;</A><br>
-<A NAME=5.1.70>Remove from her the means of all annoyance,</A><br>
-<A NAME=5.1.71>And still keep eyes upon her. So, good night:</A><br>
-<A NAME=5.1.72>My mind she has mated, and amazed my sight.</A><br>
-<A NAME=5.1.73>I think, but dare not speak.</A><br>
-</blockquote>
-
-<A NAME=speech32><b>Gentlewoman</b></a>
-<blockquote>
-<A NAME=5.1.74>Good night, good doctor.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE II. The country near Dunsinane.</h3>
-<p><blockquote>
-<i>Drum and colours. Enter MENTEITH, CAITHNESS, ANGUS, LENNOX, and Soldiers</i>
-</blockquote>
-
-<A NAME=speech1><b>MENTEITH</b></a>
-<blockquote>
-<A NAME=5.2.1>The English power is near, led on by Malcolm,</A><br>
-<A NAME=5.2.2>His uncle Siward and the good Macduff:</A><br>
-<A NAME=5.2.3>Revenges burn in them; for their dear causes</A><br>
-<A NAME=5.2.4>Would to the bleeding and the grim alarm</A><br>
-<A NAME=5.2.5>Excite the mortified man.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>ANGUS</b></a>
-<blockquote>
-<A NAME=5.2.6>Near Birnam wood</A><br>
-<A NAME=5.2.7>Shall we well meet them; that way are they coming.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>CAITHNESS</b></a>
-<blockquote>
-<A NAME=5.2.8>Who knows if Donalbain be with his brother?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>LENNOX</b></a>
-<blockquote>
-<A NAME=5.2.9>For certain, sir, he is not: I have a file</A><br>
-<A NAME=5.2.10>Of all the gentry: there is Siward's son,</A><br>
-<A NAME=5.2.11>And many unrough youths that even now</A><br>
-<A NAME=5.2.12>Protest their first of manhood.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MENTEITH</b></a>
-<blockquote>
-<A NAME=5.2.13>What does the tyrant?</A><br>
-</blockquote>
-
-<A NAME=speech6><b>CAITHNESS</b></a>
-<blockquote>
-<A NAME=5.2.14>Great Dunsinane he strongly fortifies:</A><br>
-<A NAME=5.2.15>Some say he's mad; others that lesser hate him</A><br>
-<A NAME=5.2.16>Do call it valiant fury: but, for certain,</A><br>
-<A NAME=5.2.17>He cannot buckle his distemper'd cause</A><br>
-<A NAME=5.2.18>Within the belt of rule.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>ANGUS</b></a>
-<blockquote>
-<A NAME=5.2.19>Now does he feel</A><br>
-<A NAME=5.2.20>His secret murders sticking on his hands;</A><br>
-<A NAME=5.2.21>Now minutely revolts upbraid his faith-breach;</A><br>
-<A NAME=5.2.22>Those he commands move only in command,</A><br>
-<A NAME=5.2.23>Nothing in love: now does he feel his title</A><br>
-<A NAME=5.2.24>Hang loose about him, like a giant's robe</A><br>
-<A NAME=5.2.25>Upon a dwarfish thief.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MENTEITH</b></a>
-<blockquote>
-<A NAME=5.2.26>Who then shall blame</A><br>
-<A NAME=5.2.27>His pester'd senses to recoil and start,</A><br>
-<A NAME=5.2.28>When all that is within him does condemn</A><br>
-<A NAME=5.2.29>Itself for being there?</A><br>
-</blockquote>
-
-<A NAME=speech9><b>CAITHNESS</b></a>
-<blockquote>
-<A NAME=5.2.30>Well, march we on,</A><br>
-<A NAME=5.2.31>To give obedience where 'tis truly owed:</A><br>
-<A NAME=5.2.32>Meet we the medicine of the sickly weal,</A><br>
-<A NAME=5.2.33>And with him pour we in our country's purge</A><br>
-<A NAME=5.2.34>Each drop of us.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>LENNOX</b></a>
-<blockquote>
-<A NAME=5.2.35> Or so much as it needs,</A><br>
-<A NAME=5.2.36>To dew the sovereign flower and drown the weeds.</A><br>
-<A NAME=5.2.37>Make we our march towards Birnam.</A><br>
-<p><i>Exeunt, marching</i></p>
-</blockquote>
-<h3>SCENE III. Dunsinane. A room in the castle.</h3>
-<p><blockquote>
-<i>Enter MACBETH, Doctor, and Attendants</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.1>Bring me no more reports; let them fly all:</A><br>
-<A NAME=5.3.2>Till Birnam wood remove to Dunsinane,</A><br>
-<A NAME=5.3.3>I cannot taint with fear. What's the boy Malcolm?</A><br>
-<A NAME=5.3.4>Was he not born of woman? The spirits that know</A><br>
-<A NAME=5.3.5>All mortal consequences have pronounced me thus:</A><br>
-<A NAME=5.3.6>'Fear not, Macbeth; no man that's born of woman</A><br>
-<A NAME=5.3.7>Shall e'er have power upon thee.' Then fly,</A><br>
-<A NAME=5.3.8>false thanes,</A><br>
-<A NAME=5.3.9>And mingle with the English epicures:</A><br>
-<A NAME=5.3.10>The mind I sway by and the heart I bear</A><br>
-<A NAME=5.3.11>Shall never sag with doubt nor shake with fear.</A><br>
-<p><i>Enter a Servant</i></p>
-<A NAME=5.3.12>The devil damn thee black, thou cream-faced loon!</A><br>
-<A NAME=5.3.13>Where got'st thou that goose look?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>Servant</b></a>
-<blockquote>
-<A NAME=5.3.14>There is ten thousand--</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.15>Geese, villain!</A><br>
-</blockquote>
-
-<A NAME=speech4><b>Servant</b></a>
-<blockquote>
-<A NAME=5.3.16>Soldiers, sir.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.17>Go prick thy face, and over-red thy fear,</A><br>
-<A NAME=5.3.18>Thou lily-liver'd boy. What soldiers, patch?</A><br>
-<A NAME=5.3.19>Death of thy soul! those linen cheeks of thine</A><br>
-<A NAME=5.3.20>Are counsellors to fear. What soldiers, whey-face?</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Servant</b></a>
-<blockquote>
-<A NAME=5.3.21>The English force, so please you.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.22>Take thy face hence.</A><br>
-<p><i>Exit Servant</i></p>
-<A NAME=5.3.23>Seyton!--I am sick at heart,</A><br>
-<A NAME=5.3.24>When I behold--Seyton, I say!--This push</A><br>
-<A NAME=5.3.25>Will cheer me ever, or disseat me now.</A><br>
-<A NAME=5.3.26>I have lived long enough: my way of life</A><br>
-<A NAME=5.3.27>Is fall'n into the sear, the yellow leaf;</A><br>
-<A NAME=5.3.28>And that which should accompany old age,</A><br>
-<A NAME=5.3.29>As honour, love, obedience, troops of friends,</A><br>
-<A NAME=5.3.30>I must not look to have; but, in their stead,</A><br>
-<A NAME=5.3.31>Curses, not loud but deep, mouth-honour, breath,</A><br>
-<A NAME=5.3.32>Which the poor heart would fain deny, and dare not. Seyton!</A><br>
-<p><i>Enter SEYTON</i></p>
-</blockquote>
-
-<A NAME=speech8><b>SEYTON</b></a>
-<blockquote>
-<A NAME=5.3.33>What is your gracious pleasure?</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.34>What news more?</A><br>
-</blockquote>
-
-<A NAME=speech10><b>SEYTON</b></a>
-<blockquote>
-<A NAME=5.3.35>All is confirm'd, my lord, which was reported.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.36>I'll fight till from my bones my flesh be hack'd.</A><br>
-<A NAME=5.3.37>Give me my armour.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>SEYTON</b></a>
-<blockquote>
-<A NAME=5.3.38>'Tis not needed yet.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.39>I'll put it on.</A><br>
-<A NAME=5.3.40>Send out more horses; skirr the country round;</A><br>
-<A NAME=5.3.41>Hang those that talk of fear. Give me mine armour.</A><br>
-<A NAME=5.3.42>How does your patient, doctor?</A><br>
-</blockquote>
-
-<A NAME=speech14><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.3.43>Not so sick, my lord,</A><br>
-<A NAME=5.3.44>As she is troubled with thick coming fancies,</A><br>
-<A NAME=5.3.45>That keep her from her rest.</A><br>
-</blockquote>
-
-<A NAME=speech15><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.46>Cure her of that.</A><br>
-<A NAME=5.3.47>Canst thou not minister to a mind diseased,</A><br>
-<A NAME=5.3.48>Pluck from the memory a rooted sorrow,</A><br>
-<A NAME=5.3.49>Raze out the written troubles of the brain</A><br>
-<A NAME=5.3.50>And with some sweet oblivious antidote</A><br>
-<A NAME=5.3.51>Cleanse the stuff'd bosom of that perilous stuff</A><br>
-<A NAME=5.3.52>Which weighs upon the heart?</A><br>
-</blockquote>
-
-<A NAME=speech16><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.3.53>Therein the patient</A><br>
-<A NAME=5.3.54>Must minister to himself.</A><br>
-</blockquote>
-
-<A NAME=speech17><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.55>Throw physic to the dogs; I'll none of it.</A><br>
-<A NAME=5.3.56>Come, put mine armour on; give me my staff.</A><br>
-<A NAME=5.3.57>Seyton, send out. Doctor, the thanes fly from me.</A><br>
-<A NAME=5.3.58>Come, sir, dispatch. If thou couldst, doctor, cast</A><br>
-<A NAME=5.3.59>The water of my land, find her disease,</A><br>
-<A NAME=5.3.60>And purge it to a sound and pristine health,</A><br>
-<A NAME=5.3.61>I would applaud thee to the very echo,</A><br>
-<A NAME=5.3.62>That should applaud again.--Pull't off, I say.--</A><br>
-<A NAME=5.3.63>What rhubarb, cyme, or what purgative drug,</A><br>
-<A NAME=5.3.64>Would scour these English hence? Hear'st thou of them?</A><br>
-</blockquote>
-
-<A NAME=speech18><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.3.65>Ay, my good lord; your royal preparation</A><br>
-<A NAME=5.3.66>Makes us hear something.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.3.67>Bring it after me.</A><br>
-<A NAME=5.3.68>I will not be afraid of death and bane,</A><br>
-<A NAME=5.3.69>Till Birnam forest come to Dunsinane.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>Doctor</b></a>
-<blockquote>
-<A NAME=5.3.70>[Aside] Were I from Dunsinane away and clear,</A><br>
-<A NAME=5.3.71>Profit again should hardly draw me here.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE IV. Country near Birnam wood.</h3>
-<p><blockquote>
-<i>Drum and colours. Enter MALCOLM, SIWARD and YOUNG SIWARD, MACDUFF, MENTEITH, CAITHNESS, ANGUS, LENNOX, ROSS, and Soldiers, marching</i>
-</blockquote>
-
-<A NAME=speech1><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.4.1>Cousins, I hope the days are near at hand</A><br>
-<A NAME=5.4.2>That chambers will be safe.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>MENTEITH</b></a>
-<blockquote>
-<A NAME=5.4.3>We doubt it nothing.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.4.4>What wood is this before us?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MENTEITH</b></a>
-<blockquote>
-<A NAME=5.4.5>The wood of Birnam.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.4.6>Let every soldier hew him down a bough</A><br>
-<A NAME=5.4.7>And bear't before him: thereby shall we shadow</A><br>
-<A NAME=5.4.8>The numbers of our host and make discovery</A><br>
-<A NAME=5.4.9>Err in report of us.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Soldiers</b></a>
-<blockquote>
-<A NAME=5.4.10>It shall be done.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.4.11>We learn no other but the confident tyrant</A><br>
-<A NAME=5.4.12>Keeps still in Dunsinane, and will endure</A><br>
-<A NAME=5.4.13>Our setting down before 't.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.4.14>'Tis his main hope:</A><br>
-<A NAME=5.4.15>For where there is advantage to be given,</A><br>
-<A NAME=5.4.16>Both more and less have given him the revolt,</A><br>
-<A NAME=5.4.17>And none serve with him but constrained things</A><br>
-<A NAME=5.4.18>Whose hearts are absent too.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.4.19>Let our just censures</A><br>
-<A NAME=5.4.20>Attend the true event, and put we on</A><br>
-<A NAME=5.4.21>Industrious soldiership.</A><br>
-</blockquote>
-
-<A NAME=speech10><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.4.22>The time approaches</A><br>
-<A NAME=5.4.23>That will with due decision make us know</A><br>
-<A NAME=5.4.24>What we shall say we have and what we owe.</A><br>
-<A NAME=5.4.25>Thoughts speculative their unsure hopes relate,</A><br>
-<A NAME=5.4.26>But certain issue strokes must arbitrate:</A><br>
-<A NAME=5.4.27>Towards which advance the war.</A><br>
-<p><i>Exeunt, marching</i></p>
-</blockquote>
-<h3>SCENE V. Dunsinane. Within the castle.</h3>
-<p><blockquote>
-<i>Enter MACBETH, SEYTON, and Soldiers, with drum and colours</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.1>Hang out our banners on the outward walls;</A><br>
-<A NAME=5.5.2>The cry is still 'They come:' our castle's strength</A><br>
-<A NAME=5.5.3>Will laugh a siege to scorn: here let them lie</A><br>
-<A NAME=5.5.4>Till famine and the ague eat them up:</A><br>
-<A NAME=5.5.5>Were they not forced with those that should be ours,</A><br>
-<A NAME=5.5.6>We might have met them dareful, beard to beard,</A><br>
-<A NAME=5.5.7>And beat them backward home.</A><br>
-<p><i>A cry of women within</i></p>
-<A NAME=5.5.8>What is that noise?</A><br>
-</blockquote>
-
-<A NAME=speech2><b>SEYTON</b></a>
-<blockquote>
-<A NAME=5.5.9>It is the cry of women, my good lord.</A><br>
-<p><i>Exit</i></p>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.10>I have almost forgot the taste of fears;</A><br>
-<A NAME=5.5.11>The time has been, my senses would have cool'd</A><br>
-<A NAME=5.5.12>To hear a night-shriek; and my fell of hair</A><br>
-<A NAME=5.5.13>Would at a dismal treatise rouse and stir</A><br>
-<A NAME=5.5.14>As life were in't: I have supp'd full with horrors;</A><br>
-<A NAME=5.5.15>Direness, familiar to my slaughterous thoughts</A><br>
-<A NAME=5.5.16>Cannot once start me.</A><br>
-<p><i>Re-enter SEYTON</i></p>
-<A NAME=5.5.17>Wherefore was that cry?</A><br>
-</blockquote>
-
-<A NAME=speech4><b>SEYTON</b></a>
-<blockquote>
-<A NAME=5.5.18>The queen, my lord, is dead.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.19>She should have died hereafter;</A><br>
-<A NAME=5.5.20>There would have been a time for such a word.</A><br>
-<A NAME=5.5.21>To-morrow, and to-morrow, and to-morrow,</A><br>
-<A NAME=5.5.22>Creeps in this petty pace from day to day</A><br>
-<A NAME=5.5.23>To the last syllable of recorded time,</A><br>
-<A NAME=5.5.24>And all our yesterdays have lighted fools</A><br>
-<A NAME=5.5.25>The way to dusty death. Out, out, brief candle!</A><br>
-<A NAME=5.5.26>Life's but a walking shadow, a poor player</A><br>
-<A NAME=5.5.27>That struts and frets his hour upon the stage</A><br>
-<A NAME=5.5.28>And then is heard no more: it is a tale</A><br>
-<A NAME=5.5.29>Told by an idiot, full of sound and fury,</A><br>
-<A NAME=5.5.30>Signifying nothing.</A><br>
-<p><i>Enter a Messenger</i></p>
-<A NAME=5.5.31>Thou comest to use thy tongue; thy story quickly.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>Messenger</b></a>
-<blockquote>
-<A NAME=5.5.32>Gracious my lord,</A><br>
-<A NAME=5.5.33>I should report that which I say I saw,</A><br>
-<A NAME=5.5.34>But know not how to do it.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.35>Well, say, sir.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>Messenger</b></a>
-<blockquote>
-<A NAME=5.5.36>As I did stand my watch upon the hill,</A><br>
-<A NAME=5.5.37>I look'd toward Birnam, and anon, methought,</A><br>
-<A NAME=5.5.38>The wood began to move.</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.39>Liar and slave!</A><br>
-</blockquote>
-
-<A NAME=speech10><b>Messenger</b></a>
-<blockquote>
-<A NAME=5.5.40>Let me endure your wrath, if't be not so:</A><br>
-<A NAME=5.5.41>Within this three mile may you see it coming;</A><br>
-<A NAME=5.5.42>I say, a moving grove.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.5.43>If thou speak'st false,</A><br>
-<A NAME=5.5.44>Upon the next tree shalt thou hang alive,</A><br>
-<A NAME=5.5.45>Till famine cling thee: if thy speech be sooth,</A><br>
-<A NAME=5.5.46>I care not if thou dost for me as much.</A><br>
-<A NAME=5.5.47>I pull in resolution, and begin</A><br>
-<A NAME=5.5.48>To doubt the equivocation of the fiend</A><br>
-<A NAME=5.5.49>That lies like truth: 'Fear not, till Birnam wood</A><br>
-<A NAME=5.5.50>Do come to Dunsinane:' and now a wood</A><br>
-<A NAME=5.5.51>Comes toward Dunsinane. Arm, arm, and out!</A><br>
-<A NAME=5.5.52>If this which he avouches does appear,</A><br>
-<A NAME=5.5.53>There is nor flying hence nor tarrying here.</A><br>
-<A NAME=5.5.54>I gin to be aweary of the sun,</A><br>
-<A NAME=5.5.55>And wish the estate o' the world were now undone.</A><br>
-<A NAME=5.5.56>Ring the alarum-bell! Blow, wind! come, wrack!</A><br>
-<A NAME=5.5.57>At least we'll die with harness on our back.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE VI. Dunsinane. Before the castle.</h3>
-<p><blockquote>
-<i>Drum and colours. Enter MALCOLM, SIWARD, MACDUFF, and their Army, with boughs</i>
-</blockquote>
-
-<A NAME=speech1><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.6.1>Now near enough: your leafy screens throw down.</A><br>
-<A NAME=5.6.2>And show like those you are. You, worthy uncle,</A><br>
-<A NAME=5.6.3>Shall, with my cousin, your right-noble son,</A><br>
-<A NAME=5.6.4>Lead our first battle: worthy Macduff and we</A><br>
-<A NAME=5.6.5>Shall take upon 's what else remains to do,</A><br>
-<A NAME=5.6.6>According to our order.</A><br>
-</blockquote>
-
-<A NAME=speech2><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.6.7>Fare you well.</A><br>
-<A NAME=5.6.8>Do we but find the tyrant's power to-night,</A><br>
-<A NAME=5.6.9>Let us be beaten, if we cannot fight.</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.6.10>Make all our trumpets speak; give them all breath,</A><br>
-<A NAME=5.6.11>Those clamorous harbingers of blood and death.</A><br>
-<p><i>Exeunt</i></p>
-</blockquote>
-<h3>SCENE VII. Another part of the field.</h3>
-<p><blockquote>
-<i>Alarums. Enter MACBETH</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.7.1>They have tied me to a stake; I cannot fly,</A><br>
-<A NAME=5.7.2>But, bear-like, I must fight the course. What's he</A><br>
-<A NAME=5.7.3>That was not born of woman? Such a one</A><br>
-<A NAME=5.7.4>Am I to fear, or none.</A><br>
-<p><i>Enter YOUNG SIWARD</i></p>
-</blockquote>
-
-<A NAME=speech2><b>YOUNG SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.5>What is thy name?</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.7.6> Thou'lt be afraid to hear it.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>YOUNG SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.7>No; though thou call'st thyself a hotter name</A><br>
-<A NAME=5.7.8>Than any is in hell.</A><br>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.7.9>My name's Macbeth.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>YOUNG SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.10>The devil himself could not pronounce a title</A><br>
-<A NAME=5.7.11>More hateful to mine ear.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.7.12>No, nor more fearful.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>YOUNG SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.13>Thou liest, abhorred tyrant; with my sword</A><br>
-<A NAME=5.7.14>I'll prove the lie thou speak'st.</A><br>
-<p><i>They fight and YOUNG SIWARD is slain</i></p>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.7.15>Thou wast born of woman</A><br>
-<A NAME=5.7.16>But swords I smile at, weapons laugh to scorn,</A><br>
-<A NAME=5.7.17>Brandish'd by man that's of a woman born.</A><br>
-<p><i>Exit</i></p>
-<p><i>Alarums. Enter MACDUFF</i></p>
-</blockquote>
-
-<A NAME=speech10><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.7.18>That way the noise is. Tyrant, show thy face!</A><br>
-<A NAME=5.7.19>If thou be'st slain and with no stroke of mine,</A><br>
-<A NAME=5.7.20>My wife and children's ghosts will haunt me still.</A><br>
-<A NAME=5.7.21>I cannot strike at wretched kerns, whose arms</A><br>
-<A NAME=5.7.22>Are hired to bear their staves: either thou, Macbeth,</A><br>
-<A NAME=5.7.23>Or else my sword with an unbatter'd edge</A><br>
-<A NAME=5.7.24>I sheathe again undeeded. There thou shouldst be;</A><br>
-<A NAME=5.7.25>By this great clatter, one of greatest note</A><br>
-<A NAME=5.7.26>Seems bruited. Let me find him, fortune!</A><br>
-<A NAME=5.7.27>And more I beg not.</A><br>
-<p><i>Exit. Alarums</i></p>
-<p><i>Enter MALCOLM and SIWARD</i></p>
-</blockquote>
-
-<A NAME=speech11><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.28>This way, my lord; the castle's gently render'd:</A><br>
-<A NAME=5.7.29>The tyrant's people on both sides do fight;</A><br>
-<A NAME=5.7.30>The noble thanes do bravely in the war;</A><br>
-<A NAME=5.7.31>The day almost itself professes yours,</A><br>
-<A NAME=5.7.32>And little is to do.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.7.33>We have met with foes</A><br>
-<A NAME=5.7.34>That strike beside us.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.7.35>Enter, sir, the castle.</A><br>
-<p><i>Exeunt. Alarums</i></p>
-</blockquote>
-<h3>SCENE VIII. Another part of the field.</h3>
-<p><blockquote>
-<i>Enter MACBETH</i>
-</blockquote>
-
-<A NAME=speech1><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.8.1>Why should I play the Roman fool, and die</A><br>
-<A NAME=5.8.2>On mine own sword? whiles I see lives, the gashes</A><br>
-<A NAME=5.8.3>Do better upon them.</A><br>
-<p><i>Enter MACDUFF</i></p>
-</blockquote>
-
-<A NAME=speech2><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.8.4>Turn, hell-hound, turn!</A><br>
-</blockquote>
-
-<A NAME=speech3><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.8.5>Of all men else I have avoided thee:</A><br>
-<A NAME=5.8.6>But get thee back; my soul is too much charged</A><br>
-<A NAME=5.8.7>With blood of thine already.</A><br>
-</blockquote>
-
-<A NAME=speech4><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.8.8>I have no words:</A><br>
-<A NAME=5.8.9>My voice is in my sword: thou bloodier villain</A><br>
-<A NAME=5.8.10>Than terms can give thee out!</A><br>
-<p><i>They fight</i></p>
-</blockquote>
-
-<A NAME=speech5><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.8.11>Thou losest labour:</A><br>
-<A NAME=5.8.12>As easy mayst thou the intrenchant air</A><br>
-<A NAME=5.8.13>With thy keen sword impress as make me bleed:</A><br>
-<A NAME=5.8.14>Let fall thy blade on vulnerable crests;</A><br>
-<A NAME=5.8.15>I bear a charmed life, which must not yield,</A><br>
-<A NAME=5.8.16>To one of woman born.</A><br>
-</blockquote>
-
-<A NAME=speech6><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.8.17>Despair thy charm;</A><br>
-<A NAME=5.8.18>And let the angel whom thou still hast served</A><br>
-<A NAME=5.8.19>Tell thee, Macduff was from his mother's womb</A><br>
-<A NAME=5.8.20>Untimely ripp'd.</A><br>
-</blockquote>
-
-<A NAME=speech7><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.8.21>Accursed be that tongue that tells me so,</A><br>
-<A NAME=5.8.22>For it hath cow'd my better part of man!</A><br>
-<A NAME=5.8.23>And be these juggling fiends no more believed,</A><br>
-<A NAME=5.8.24>That palter with us in a double sense;</A><br>
-<A NAME=5.8.25>That keep the word of promise to our ear,</A><br>
-<A NAME=5.8.26>And break it to our hope. I'll not fight with thee.</A><br>
-</blockquote>
-
-<A NAME=speech8><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.8.27>Then yield thee, coward,</A><br>
-<A NAME=5.8.28>And live to be the show and gaze o' the time:</A><br>
-<A NAME=5.8.29>We'll have thee, as our rarer monsters are,</A><br>
-<A NAME=5.8.30>Painted on a pole, and underwrit,</A><br>
-<A NAME=5.8.31>'Here may you see the tyrant.'</A><br>
-</blockquote>
-
-<A NAME=speech9><b>MACBETH</b></a>
-<blockquote>
-<A NAME=5.8.32>I will not yield,</A><br>
-<A NAME=5.8.33>To kiss the ground before young Malcolm's feet,</A><br>
-<A NAME=5.8.34>And to be baited with the rabble's curse.</A><br>
-<A NAME=5.8.35>Though Birnam wood be come to Dunsinane,</A><br>
-<A NAME=5.8.36>And thou opposed, being of no woman born,</A><br>
-<A NAME=5.8.37>Yet I will try the last. Before my body</A><br>
-<A NAME=5.8.38>I throw my warlike shield. Lay on, Macduff,</A><br>
-<A NAME=5.8.39>And damn'd be him that first cries, 'Hold, enough!'</A><br>
-<p><i>Exeunt, fighting. Alarums</i></p>
-<p><i>Retreat. Flourish. Enter, with drum and colours, MALCOLM, SIWARD, ROSS, the other Thanes, and Soldiers</i></p>
-</blockquote>
-
-<A NAME=speech10><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.8.40>I would the friends we miss were safe arrived.</A><br>
-</blockquote>
-
-<A NAME=speech11><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.8.41>Some must go off: and yet, by these I see,</A><br>
-<A NAME=5.8.42>So great a day as this is cheaply bought.</A><br>
-</blockquote>
-
-<A NAME=speech12><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.8.43>Macduff is missing, and your noble son.</A><br>
-</blockquote>
-
-<A NAME=speech13><b>ROSS</b></a>
-<blockquote>
-<A NAME=5.8.44>Your son, my lord, has paid a soldier's debt:</A><br>
-<A NAME=5.8.45>He only lived but till he was a man;</A><br>
-<A NAME=5.8.46>The which no sooner had his prowess confirm'd</A><br>
-<A NAME=5.8.47>In the unshrinking station where he fought,</A><br>
-<A NAME=5.8.48>But like a man he died.</A><br>
-</blockquote>
-
-<A NAME=speech14><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.8.49>Then he is dead?</A><br>
-</blockquote>
-
-<A NAME=speech15><b>ROSS</b></a>
-<blockquote>
-<A NAME=5.8.50>Ay, and brought off the field: your cause of sorrow</A><br>
-<A NAME=5.8.51>Must not be measured by his worth, for then</A><br>
-<A NAME=5.8.52>It hath no end.</A><br>
-</blockquote>
-
-<A NAME=speech16><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.8.53> Had he his hurts before?</A><br>
-</blockquote>
-
-<A NAME=speech17><b>ROSS</b></a>
-<blockquote>
-<A NAME=5.8.54>Ay, on the front.</A><br>
-</blockquote>
-
-<A NAME=speech18><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.8.55> Why then, God's soldier be he!</A><br>
-<A NAME=5.8.56>Had I as many sons as I have hairs,</A><br>
-<A NAME=5.8.57>I would not wish them to a fairer death:</A><br>
-<A NAME=5.8.58>And so, his knell is knoll'd.</A><br>
-</blockquote>
-
-<A NAME=speech19><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.8.59>He's worth more sorrow,</A><br>
-<A NAME=5.8.60>And that I'll spend for him.</A><br>
-</blockquote>
-
-<A NAME=speech20><b>SIWARD</b></a>
-<blockquote>
-<A NAME=5.8.61>He's worth no more</A><br>
-<A NAME=5.8.62>They say he parted well, and paid his score:</A><br>
-<A NAME=5.8.63>And so, God be with him! Here comes newer comfort.</A><br>
-<p><i>Re-enter MACDUFF, with MACBETH's head</i></p>
-</blockquote>
-
-<A NAME=speech21><b>MACDUFF</b></a>
-<blockquote>
-<A NAME=5.8.64>Hail, king! for so thou art: behold, where stands</A><br>
-<A NAME=5.8.65>The usurper's cursed head: the time is free:</A><br>
-<A NAME=5.8.66>I see thee compass'd with thy kingdom's pearl,</A><br>
-<A NAME=5.8.67>That speak my salutation in their minds;</A><br>
-<A NAME=5.8.68>Whose voices I desire aloud with mine:</A><br>
-<A NAME=5.8.69>Hail, King of Scotland!</A><br>
-</blockquote>
-
-<A NAME=speech22><b>ALL</b></a>
-<blockquote>
-<A NAME=5.8.70>Hail, King of Scotland!</A><br>
-<p><i>Flourish</i></p>
-</blockquote>
-
-<A NAME=speech23><b>MALCOLM</b></a>
-<blockquote>
-<A NAME=5.8.71>We shall not spend a large expense of time</A><br>
-<A NAME=5.8.72>Before we reckon with your several loves,</A><br>
-<A NAME=5.8.73>And make us even with you. My thanes and kinsmen,</A><br>
-<A NAME=5.8.74>Henceforth be earls, the first that ever Scotland</A><br>
-<A NAME=5.8.75>In such an honour named. What's more to do,</A><br>
-<A NAME=5.8.76>Which would be planted newly with the time,</A><br>
-<A NAME=5.8.77>As calling home our exiled friends abroad</A><br>
-<A NAME=5.8.78>That fled the snares of watchful tyranny;</A><br>
-<A NAME=5.8.79>Producing forth the cruel ministers</A><br>
-<A NAME=5.8.80>Of this dead butcher and his fiend-like queen,</A><br>
-<A NAME=5.8.81>Who, as 'tis thought, by self and violent hands</A><br>
-<A NAME=5.8.82>Took off her life; this, and what needful else</A><br>
-<A NAME=5.8.83>That calls upon us, by the grace of Grace,</A><br>
-<A NAME=5.8.84>We will perform in measure, time and place:</A><br>
-<A NAME=5.8.85>So, thanks to all at once and to each one,</A><br>
-<A NAME=5.8.86>Whom we invite to see us crown'd at Scone.</A><br>
-<p><i>Flourish. Exeunt</i></p>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/modal_dialogs.html b/testing/marionette/harness/marionette_harness/www/modal_dialogs.html
deleted file mode 100644
index 8da5b92a76..0000000000
--- a/testing/marionette/harness/marionette_harness/www/modal_dialogs.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
- <title>Marionette Test</title>
- <script type="text/javascript">
- function handleAlert () {
- window.alert('Marionette alert');
- }
-
- function handleConfirm () {
- var alertAccepted = window.confirm('Marionette confirm');
- document.getElementById('confirm-result').innerHTML = alertAccepted;
- }
-
- function handlePrompt () {
- var promptText = window.prompt('Marionette prompt');
- document.getElementById('prompt-result').innerHTML = promptText === null ? 'null' : promptText;
- }
-
- function onBeforeUnload () {
- window.onbeforeunload = function () { return "Are you sure?"; }
- }
- </script>
-</head>
-<body>
- <a href="#" id="modal-alert" onclick="handleAlert()">Open an alert dialog.</a>
- <a href="#" id="modal-confirm" onclick="handleConfirm()">Open a confirm dialog.</a>
- <a href="#" id="modal-prompt" onclick="handlePrompt()">Open a prompt dialog.</a>
- <a href="#" id="onbeforeunload-handler" onclick="onBeforeUnload()">Add an onbeforeunload handler.</a>
- <a href="#" id="click-handler" onclick="document.getElementById('click-result').innerHTML='result';">Make text appear.</a>
- <div id="confirm-result"></div>
- <div id="prompt-result"></div>
- <div id="click-result"></div>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/nestedElements.html b/testing/marionette/harness/marionette_harness/www/nestedElements.html
deleted file mode 100644
index 618bf3231b..0000000000
--- a/testing/marionette/harness/marionette_harness/www/nestedElements.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<a href="1.html">hello world</a>
-<a href="1.html">hello world</a><a href="1.html">hello world</a>
-<div name="div1">
- <a href="2.html" name="link1">hello world</a>
- <a href="2.html" name="link2">hello world</a>
-</div>
-
-<a href="1.html">hello world</a><a href="1.html">hello world</a><a href="1.html">hello world</a>
diff --git a/testing/marionette/harness/marionette_harness/www/rectangles.html b/testing/marionette/harness/marionette_harness/www/rectangles.html
deleted file mode 100644
index 59871c6de6..0000000000
--- a/testing/marionette/harness/marionette_harness/www/rectangles.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
- <title>Rectangles</title>
- <style type="text/css">
- div {
- position: absolute;
- margin: 0;
- border: 0;
- padding: 0;
- }
- #r1 {
- background-color: blue;
- left: 10px;
- top: 10px;
- width: 100px;
- height: 50px;
- }
- #r2 {
- background-color: red;
- left: 11px;
- top: 10px;
- width: 48.666666667px;
- height: 49.333333333px;
- }
- #r3 {
- background-color: yellow;
- left: 60px;
- top: 10px;
- width: 50px;
- height: 25px;
- }
- </style>
-</head>
- <body>
- <div id="r1">r1</div>
- <div id="r2">r2</div>
- <div id="r3">r3</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/resultPage.html b/testing/marionette/harness/marionette_harness/www/resultPage.html
deleted file mode 100644
index 342e9930bd..0000000000
--- a/testing/marionette/harness/marionette_harness/www/resultPage.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head>
- <title>We Arrive Here</title>
-</head>
-<body>
-
-
-<div>
- <input type='text' id='email'/>
-</div>
-</body>
-</html>
-
diff --git a/testing/marionette/harness/marionette_harness/www/scroll.html b/testing/marionette/harness/marionette_harness/www/scroll.html
deleted file mode 100644
index 8a654bb50b..0000000000
--- a/testing/marionette/harness/marionette_harness/www/scroll.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head></head>
-<body>
- <script>
- function dump(event) {
- var elt = event.target || event.srcElement;
- document.getElementById('clicked').innerHTML = elt.innerHTML;
- }
- </script>
- <div style='height: 150px'></div>
- <ul style='overflow: scroll; width: 150px; height: 80px; background-color: yellow' onclick="dump(event)">
- <li id='line1'>line1</li>
- <li id='line2'>line2</li>
- <li id='line3'>line3</li>
- <li id='line4'>line4</li>
- <li id='line5'>line5</li>
- <li id='line6'>line6</li>
- <li id='line7'>line7</li>
- <li id='line8'>line8</li>
- <li id='line9'>line9</li>
- </ul>
- <div>
- Clicked: <span id='clicked'></span>
- </div>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/scroll2.html b/testing/marionette/harness/marionette_harness/www/scroll2.html
deleted file mode 100644
index bd00f0e221..0000000000
--- a/testing/marionette/harness/marionette_harness/www/scroll2.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head></head>
-<body>
- <ul style='overflow: scroll; height: 100px;'>
- <li></li>
- <li></li>
- <li id="desired">Text</li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- <li></li>
- </ul>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/scroll3.html b/testing/marionette/harness/marionette_harness/www/scroll3.html
deleted file mode 100644
index b615e38c34..0000000000
--- a/testing/marionette/harness/marionette_harness/www/scroll3.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
- <style type="text/css"></style>
-</head>
-<body>
-<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
-<button id="button1">Button1</button>
-<br><br><br><br>
-
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="button2">Button2</button>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/scroll4.html b/testing/marionette/harness/marionette_harness/www/scroll4.html
deleted file mode 100644
index ce0df03132..0000000000
--- a/testing/marionette/harness/marionette_harness/www/scroll4.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
- <style type="text/css"></style>
-</head>
-<body>
-<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
-<input type="radio" id="radio">
-<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/scroll5.html b/testing/marionette/harness/marionette_harness/www/scroll5.html
deleted file mode 100644
index 3dd00721e6..0000000000
--- a/testing/marionette/harness/marionette_harness/www/scroll5.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!-- 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/. -->
-
-<html>
-<head></head>
-<body>
- <script>
- function dump(text) {
- document.getElementById('clicked').innerHTML = text;
- }
- </script>
- <div style='overflow: scroll; width: 150px; height: 200px; background-color: yellow' id="outer">
- <div style="width: 150px; height: 5000px; background-color: red;" onclick="dump('clicked')" id="inner"></div>
- </div>
- <div>
- Clicked: <span id='clicked'></span>
- </div>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/shim.js b/testing/marionette/harness/marionette_harness/www/shim.js
deleted file mode 100644
index 2a74e69492..0000000000
--- a/testing/marionette/harness/marionette_harness/www/shim.js
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
-* mouse_event_shim.js: generate mouse events from touch events.
-*
-* This library listens for touch events and generates mousedown, mousemove
-* mouseup, and click events to match them. It captures and dicards any
-* real mouse events (non-synthetic events with isTrusted true) that are
-* send by gecko so that there are not duplicates.
-*
-* This library does emit mouseover/mouseout and mouseenter/mouseleave
-* events. You can turn them off by setting MouseEventShim.trackMouseMoves to
-* false. This means that mousemove events will always have the same target
-* as the mousedown even that began the series. You can also call
-* MouseEventShim.setCapture() from a mousedown event handler to prevent
-* mouse tracking until the next mouseup event.
-*
-* This library does not support multi-touch but should be sufficient
-* to do drags based on mousedown/mousemove/mouseup events.
-*
-* This library does not emit dblclick events or contextmenu events
-*/
-
-'use strict';
-
-(function() {
- // Make sure we don't run more than once
- if (MouseEventShim)
- return;
-
- // Bail if we're not on running on a platform that sends touch
- // events. We don't need the shim code for mouse events.
- try {
- document.createEvent('TouchEvent');
- } catch (e) {
- return;
- }
-
- var starttouch; // The Touch object that we started with
- var target; // The element the touch is currently over
- var emitclick; // Will we be sending a click event after mouseup?
-
- // Use capturing listeners to discard all mouse events from gecko
- window.addEventListener('mousedown', discardEvent, true);
- window.addEventListener('mouseup', discardEvent, true);
- window.addEventListener('mousemove', discardEvent, true);
- window.addEventListener('click', discardEvent, true);
-
- function discardEvent(e) {
- if (e.isTrusted) {
- e.stopImmediatePropagation(); // so it goes no further
- if (e.type === 'click')
- e.preventDefault(); // so it doesn't trigger a change event
- }
- }
-
- // Listen for touch events that bubble up to the window.
- // If other code has called stopPropagation on the touch events
- // then we'll never see them. Also, we'll honor the defaultPrevented
- // state of the event and will not generate synthetic mouse events
- window.addEventListener('touchstart', handleTouchStart);
- window.addEventListener('touchmove', handleTouchMove);
- window.addEventListener('touchend', handleTouchEnd);
- window.addEventListener('touchcancel', handleTouchEnd); // Same as touchend
-
- function handleTouchStart(e) {
- // If we're already handling a touch, ignore this one
- if (starttouch)
- return;
-
- // Ignore any event that has already been prevented
- if (e.defaultPrevented)
- return;
-
- // Sometimes an unknown gecko bug causes us to get a touchstart event
- // for an iframe target that we can't use because it is cross origin.
- // Don't start handling a touch in that case
- try {
- e.changedTouches[0].target.ownerDocument;
- }
- catch (e) {
- // Ignore the event if we can't see the properties of the target
- return;
- }
-
- // If there is more than one simultaneous touch, ignore all but the first
- starttouch = e.changedTouches[0];
- target = starttouch.target;
- emitclick = true;
-
- // Move to the position of the touch
- emitEvent('mousemove', target, starttouch);
-
- // Now send a synthetic mousedown
- var result = emitEvent('mousedown', target, starttouch);
-
- // If the mousedown was prevented, pass that on to the touch event.
- // And remember not to send a click event
- if (!result) {
- e.preventDefault();
- emitclick = false;
- }
- }
-
- function handleTouchEnd(e) {
- if (!starttouch)
- return;
-
- // End a MouseEventShim.setCapture() call
- if (MouseEventShim.capturing) {
- MouseEventShim.capturing = false;
- MouseEventShim.captureTarget = null;
- }
-
- for (var i = 0; i < e.changedTouches.length; i++) {
- var touch = e.changedTouches[i];
- // If the ended touch does not have the same id, skip it
- if (touch.identifier !== starttouch.identifier)
- continue;
-
- emitEvent('mouseup', target, touch);
-
- // If target is still the same element we started and the touch did not
- // move more than the threshold and if the user did not prevent
- // the mousedown, then send a click event, too.
- if (emitclick)
- emitEvent('click', starttouch.target, touch);
-
- starttouch = null;
- return;
- }
- }
-
- function handleTouchMove(e) {
- if (!starttouch)
- return;
-
- for (var i = 0; i < e.changedTouches.length; i++) {
- var touch = e.changedTouches[i];
- // If the ended touch does not have the same id, skip it
- if (touch.identifier !== starttouch.identifier)
- continue;
-
- // Don't send a mousemove if the touchmove was prevented
- if (e.defaultPrevented)
- return;
-
- // See if we've moved too much to emit a click event
- var dx = Math.abs(touch.screenX - starttouch.screenX);
- var dy = Math.abs(touch.screenY - starttouch.screenY);
- if (dx > MouseEventShim.dragThresholdX ||
- dy > MouseEventShim.dragThresholdY) {
- emitclick = false;
- }
-
- var tracking = MouseEventShim.trackMouseMoves &&
- !MouseEventShim.capturing;
-
- if (tracking) {
- // If the touch point moves, then the element it is over
- // may have changed as well. Note that calling elementFromPoint()
- // forces a layout if one is needed.
- // XXX: how expensive is it to do this on each touchmove?
- // Can we listen for (non-standard) touchleave events instead?
- var oldtarget = target;
- var newtarget = document.elementFromPoint(touch.clientX, touch.clientY);
- if (newtarget === null) {
- // this can happen as the touch is moving off of the screen, e.g.
- newtarget = oldtarget;
- }
- if (newtarget !== oldtarget) {
- leave(oldtarget, newtarget, touch); // mouseout, mouseleave
- target = newtarget;
- }
- }
- else if (MouseEventShim.captureTarget) {
- target = MouseEventShim.captureTarget;
- }
-
- emitEvent('mousemove', target, touch);
-
- if (tracking && newtarget !== oldtarget) {
- enter(newtarget, oldtarget, touch); // mouseover, mouseenter
- }
- }
- }
-
- // Return true if element a contains element b
- function contains(a, b) {
- return (a.compareDocumentPosition(b) & 16) !== 0;
- }
-
- // A touch has left oldtarget and entered newtarget
- // Send out all the events that are required
- function leave(oldtarget, newtarget, touch) {
- emitEvent('mouseout', oldtarget, touch, newtarget);
-
- // If the touch has actually left oldtarget (and has not just moved
- // into a child of oldtarget) send a mouseleave event. mouseleave
- // events don't bubble, so we have to repeat this up the hierarchy.
- for (var e = oldtarget; !contains(e, newtarget); e = e.parentNode) {
- emitEvent('mouseleave', e, touch, newtarget);
- }
- }
-
- // A touch has entered newtarget from oldtarget
- // Send out all the events that are required.
- function enter(newtarget, oldtarget, touch) {
- emitEvent('mouseover', newtarget, touch, oldtarget);
-
- // Emit non-bubbling mouseenter events if the touch actually entered
- // newtarget and wasn't already in some child of it
- for (var e = newtarget; !contains(e, oldtarget); e = e.parentNode) {
- emitEvent('mouseenter', e, touch, oldtarget);
- }
- }
-
- function emitEvent(type, target, touch, relatedTarget) {
- var synthetic = document.createEvent('MouseEvents');
- var bubbles = (type !== 'mouseenter' && type !== 'mouseleave');
- var count =
- (type === 'mousedown' || type === 'mouseup' || type === 'click') ? 1 : 0;
-
- synthetic.initMouseEvent(type,
- bubbles, // canBubble
- true, // cancelable
- window,
- count, // detail: click count
- touch.screenX,
- touch.screenY,
- touch.clientX,
- touch.clientY,
- false, // ctrlKey: we don't have one
- false, // altKey: we don't have one
- false, // shiftKey: we don't have one
- false, // metaKey: we don't have one
- 0, // we're simulating the left button
- relatedTarget || null);
-
- try {
- return target.dispatchEvent(synthetic);
- }
- catch (e) {
- console.warn('Exception calling dispatchEvent', type, e);
- return true;
- }
- }
-}());
-
-var MouseEventShim = {
- // It is a known gecko bug that synthetic events have timestamps measured
- // in microseconds while regular events have timestamps measured in
- // milliseconds. This utility function returns a the timestamp converted
- // to milliseconds, if necessary.
- getEventTimestamp: function(e) {
- if (e.isTrusted) // XXX: Are real events always trusted?
- return e.timeStamp;
- else
- return e.timeStamp / 1000;
- },
-
- // Set this to false if you don't care about mouseover/out events
- // and don't want the target of mousemove events to follow the touch
- trackMouseMoves: true,
-
- // Call this function from a mousedown event handler if you want to guarantee
- // that the mousemove and mouseup events will go to the same element
- // as the mousedown even if they leave the bounds of the element. This is
- // like setting trackMouseMoves to false for just one drag. It is a
- // substitute for event.target.setCapture(true)
- setCapture: function(target) {
- this.capturing = true; // Will be set back to false on mouseup
- if (target)
- this.captureTarget = target;
- },
-
- capturing: false,
-
- // Keep these in sync with ui.dragThresholdX and ui.dragThresholdY prefs.
- // If a touch ever moves more than this many pixels from its starting point
- // then we will not synthesize a click event when the touch ends.
- dragThresholdX: 25,
- dragThresholdY: 25
-};
diff --git a/testing/marionette/harness/marionette_harness/www/test.html b/testing/marionette/harness/marionette_harness/www/test.html
deleted file mode 100644
index 053ff171da..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>Marionette Test</title>
-</head>
-<body>
- <h1 id="testh1">Test Page</h1>
- <script type="text/javascript">
- window.ready = true;
- function addDelayedElement() {
- setTimeout(createDiv, 2000);
- function createDiv() {
- var newDiv = document.createElement("div");
- newDiv.id = "newDiv";
- var newContent = document.createTextNode("I am a newly created div!");
- newDiv.appendChild(newContent);
- document.body.appendChild(newDiv);
- }
- }
- function clicked() {
- var link = document.getElementById("mozLink");
- link.innerHTML = "Clicked";
- }
- </script>
- <a href="#" id="mozLink" class="linkClass" onclick="clicked()">Click me!</a>
- <div id="testDiv">
- <a href="#" id="divLink" class="linkClass" onclick="clicked()">Div click me!</a>
- <a href="#" id="divLink2" class="linkClass" onclick="clicked()">Div click me!</a>
- </div>
- <input name="myInput" type="text" value="asdf"/>
- <input name="myCheckBox" type="checkbox" />
- <input id="createDivButton" type="button" value="create a div" onclick="addDelayedElement()" />
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/testAction.html b/testing/marionette/harness/marionette_harness/www/testAction.html
deleted file mode 100644
index eb7e44f3eb..0000000000
--- a/testing/marionette/harness/marionette_harness/www/testAction.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-
-<html>
-<meta charset="UTF-8">
-<head>
-<title>Marionette Test</title>
-</head>
-<body>
- <h1 id="testh1">Test Page</h1>
- <button id="button1" style="position:absolute;left:0px;top:55px;" type="button" allowevents=true>button1</button>
- <button id="button2" style="position:absolute;left:0px;top:355px;" type="button" allowevents=true>button2</button>
- <button id="button3" style="position:absolute;left:0px;top:455px;" type="button" allowevents=true>button3</button>
- <button id="button4" style="position:absolute;left:100px;top:455px;" type="button" allowevents=true>button4</button>
- <button id="buttonScroll" style="position:absolute;left:100px;top:855px;" type="button" allowevents=true>buttonScroll</button>
- <h2 id="hidden" style="visibility: hidden" class="linkClass">Hidden</h2>
- <button id="buttonFlick" style="position:absolute;left:0px;top:255px;" type="button" allowevents=true>buttonFlick</button>
- <script type="text/javascript">
- var button3Timer = null;
- var button4Timer = null;
- //appends passed in text to the innerHTML of the event's target
- function appendText(text) {
- return function(evt) {
- var element;
- if (evt.type.indexOf("touch") !== -1) {
- if (evt.type == "touchstart") {
- element = evt.target;
- }
- else {
- //since the target of touchstart is the target of all subsequent events, then
- //changedTouches holds the current coordinates of this touch event, so we
- //use these coordinates to find the element under the touch event
- var touches = evt.changedTouches;
- var x = touches[0].clientX;
- var y = touches[0].clientY;
- element = document.elementFromPoint(x,y);
- }
- }
- //handle mouse events or contextmenu
- else {
- element = evt.target;
- }
- element.innerHTML += text;
- };
- };
- //use this function outside of attachListeners when you want to test sendMouseOnlyEvents on a target
- function attachMouseListeners(element) {
- element.addEventListener("contextmenu", appendText("-contextmenu"), false);
- element.addEventListener("mousedown", appendText("-mousedown"), false);
- element.addEventListener("mousemove", appendText("-mousemove"), false);
- element.addEventListener("mouseup", appendText("-mouseup"), false);
- element.addEventListener("click", appendText("-click"), false);
- };
- function attachListeners(id) {
- var element = document.getElementById(id);
- element.addEventListener("touchstart", appendText("-touchstart"), false);
- element.addEventListener("touchmove", appendText("-touchmove"), false);
- element.addEventListener("touchend", appendText("-touchend"), false);
- element.addEventListener("touchcancel", appendText("-touchcancel"), false);
- attachMouseListeners(element);
- };
- //for tracking time on an element
- function addTimers(id, timer) {
- var element = document.getElementById(id);
- element.addEventListener("touchstart", function(evt) { timer = (new Date()).getTime();}, false);
- element.addEventListener("touchend", function(evt) { timer = (new Date()).getTime() - timer; evt.target.innerHTML += "-" + timer;}, false);
- }
- attachListeners("button1");
- attachListeners("button2");
- attachListeners("button3");
- attachListeners("button4");
- attachListeners("buttonScroll");
- addTimers("button3");
- addTimers("button4");
- var buttonFlick = document.getElementById("buttonFlick");
- attachMouseListeners(buttonFlick);
- function createDelayed() {
- var newButton = document.createElement("button");
- newButton.id = "delayed";
- newButton.setAttribute("style", "position:absolute;left:220px;top:455px;");
- var content = document.createTextNode("delayed");
- newButton.appendChild(content);
- document.body.appendChild(newButton);
- newButton.addEventListener("mousemove", appendText("-mousemove"), false);
- newButton.addEventListener("mouseup", appendText("-mouseup"), false);
- newButton.addEventListener("click", appendText("-click"), false);
- };
- window.setTimeout(createDelayed, 5000);
- </script>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/testPageSource.html b/testing/marionette/harness/marionette_harness/www/testPageSource.html
deleted file mode 100644
index f19b9d30cd..0000000000
--- a/testing/marionette/harness/marionette_harness/www/testPageSource.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>PageSource Test</title>
-</head>
-<body>
- <p> Check the PageSource
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/testPageSource.xml b/testing/marionette/harness/marionette_harness/www/testPageSource.xml
deleted file mode 100644
index 1480a1f38e..0000000000
--- a/testing/marionette/harness/marionette_harness/www/testPageSource.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<xml>
- <foo>
- <bar>baz</bar>
- </foo>
-</xml>
diff --git a/testing/marionette/harness/marionette_harness/www/testPageSourceWithUnicodeChars.html b/testing/marionette/harness/marionette_harness/www/testPageSourceWithUnicodeChars.html
deleted file mode 100644
index d16cf52c83..0000000000
--- a/testing/marionette/harness/marionette_harness/www/testPageSourceWithUnicodeChars.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8"/>
- <meta http-equiv="pragma" content="no-cache"/>
- <!--
- - the « section[id^="wifi-"] » selector.
- -->
- </body>
-</html>
-
diff --git a/testing/marionette/harness/marionette_harness/www/testSize.html b/testing/marionette/harness/marionette_harness/www/testSize.html
deleted file mode 100644
index 1df27ad23c..0000000000
--- a/testing/marionette/harness/marionette_harness/www/testSize.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>Test page for element size</title>
- </head>
- <body>
- <p>Let's get the size of <a href='#' id='linkId'>some really cool link</a></p>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_accessibility.html b/testing/marionette/harness/marionette_harness/www/test_accessibility.html
deleted file mode 100644
index 8cc9fd6493..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_accessibility.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-
-<html>
-<meta charset="UTF-8">
-<head>
-<title>Marionette Test</title>
-</head>
-<body>
- <button id="button1">button1</button>
- <button id="button2" aria-label="button2"></button>
- <span id="button3">I am a bad button with no accessible</span>
- <h1 id="button4">I am a bad button that is actually a header</h1>
- <h1 id="button5">
- I am a bad button that is actually an actionable header with a listener
- </h1>
- <button id="button6"></button>
- <button id="button7" aria-hidden="true">button7</button>
- <div aria-hidden="true">
- <button id="button8">button8</button>
- </div>
- <button id="button9" style="position:absolute;left:-100px;top:-455px;">
- button9
- </button>
- <button id="button10" style="visibility:hidden;">
- button10
- </button>
- <span id="no_accessible_but_displayed">I have no accessible object</span>
- <button id="button11" disabled>button11</button>
- <button id="button12" aria-disabled="true">button12</button>
- <span id="no_accessible_but_disabled" disabled>I have no accessible object</span>
- <span id="button13" tabindex="0" role="button" aria-label="Span button">Span button</span>
- <span id="button14" role="button" aria-label="Span button">Unexplorable Span button</span>
- <button id="button15" style="pointer-events:none;">button15</button>
- <div style="pointer-events:none;">
- <button id="button16">button16</button>
- </div>
- <div style="pointer-events:none;">
- <button style="pointer-events:all;" id="button17">button17</button>
- </div>
- <input id="input1" title="My Input 1" name="myInput1" type="text" value="asdf"/>
- <select>
- <option id="option1" value="val1">Val1</option>
- <option id="option2" value="val2" selected>Val2</option>
- </select>
- <script>
- 'use strict';
- document.getElementById('button5').addEventListener('click', function() {
- // A pseudo button that has a listener but is missing button semantics.
- return true;
- });
- </script>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_columns.html b/testing/marionette/harness/marionette_harness/www/test_carets_columns.html
deleted file mode 100644
index 4952361085..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_columns.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-
-<html>
- <head>
- <meta charset="UTF-8">
- <style>
- #columns {
- -moz-column-count: 2;
- -webkit-column-count: 2;
- -moz-column-rule: 1px solid lightgray;
- -webkit-column-rule: 1px solid lightgray;
- border: 1px solid lightblue;
- width: 450px;
- }
- </style>
- </head>
- <body>
- <div id="columns">
- <div id="columns-inner" style="border: 1px solid red;" contenteditable="true">
- <p id="before-image-1">Before image 1</p>
- <p><img width="100px" height="30px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs="></p>
- <p>After image 1</p>
- <p>Before image 2</p>
- <p><img width="100px" height="30px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs="></p>
- <p>After image 2</p>
- </div>
- </div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_cursor.html b/testing/marionette/harness/marionette_harness/www/test_carets_cursor.html
deleted file mode 100644
index fdbd6fe7a8..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_cursor.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html id="html">
- <head>
- <title>Marionette tests for AccessibleCaret in cursor mode</title>
- <style>
- .block {
- width: 10em;
- height: 6em;
- word-wrap: break-word;
- overflow: auto;
- }
- </style>
- </head>
- <body>
- <div>
- <input id="input" value="ABCDEFGHI">
- <input id="input-padding" style="padding: 1em;" value="ABCDEFGHI">
- </div>
- <br>
- <div>
- <textarea name="textarea" id="textarea" rows="4" cols="6">ABCDEFGHI</textarea>
- <textarea id="textarea-one-line" rows="3">ABCDEFGHI</textarea>
- </div>
- <br>
- <div class="block" contenteditable="true" id="contenteditable">ABCDEFGHI</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_display_none.html b/testing/marionette/harness/marionette_harness/www/test_carets_display_none.html
deleted file mode 100644
index 766f320011..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_display_none.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html id="html" style="display: none">
- <body>
- <div id="content">ABC DEF GHI</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_iframe.html b/testing/marionette/harness/marionette_harness/www/test_carets_iframe.html
deleted file mode 100644
index f6e6df9ba9..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_iframe.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html id="html">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>Marionette tests for AccessibleCaret in selection mode (iframe)</title>
- </head>
- <body>
- <style>
- *
- {
- -moz-user-select:none;
- }
- </style>
- <iframe id="frame" src="test_carets_longtext.html" style="width: 10em; height: 8em;"></iframe>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_longtext.html b/testing/marionette/harness/marionette_harness/www/test_carets_longtext.html
deleted file mode 100644
index 7e2495509b..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_longtext.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
- <head>
- <title>Bug 1094072: Orientation change test for AccessibleCaret positions</title>
- </head>
- <body id="bd">
- <h3 id="longtext">long long text for orientation change test long long text for orientation change test long long text for orientation change test long long text for orientation change test</h3>
- <div contenteditable="true" id="bottomtext">bottom text</div>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_multipleline.html b/testing/marionette/harness/marionette_harness/www/test_carets_multipleline.html
deleted file mode 100644
index ff46a954ba..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_multipleline.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html id="html">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>Bug 1019441: Marionette tests for AccessibleCaret (multiple lines)</title>
- </head>
- <body>
- <style>
- *
- {
- -moz-user-select:none;
- }
- </style>
- <div><textarea id="textarea2" style="width: 10em; height: 6em; overflow: auto;">First Line&#13;&#10;&#13;&#10;Second Line&#13;&#10;&#13;&#10;Third Line</textarea></div>
- <br>
- <div style="width: 10em; height: 6em; overflow: auto; -moz-user-select:text" id="contenteditable2" contenteditable="true">First Line<br><br>Second Line<br><br>Third Line</div>
- <br>
- <div style="width: 10em; height: 6em; overflow: auto; -moz-user-select:text" id="content2">First Line<br><br>Second Line<br><br>Third Line</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_multiplerange.html b/testing/marionette/harness/marionette_harness/www/test_carets_multiplerange.html
deleted file mode 100644
index 394630c1fa..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_multiplerange.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<style>
-h4 {
- -moz-user-select: none;
-}
-</style>
-<body id=bd>
-<h3 id=sel1>user can select this 1</h3>
-<h3 id=sel2>user can select this 2</h3>
-<h3 id=sel3>user can select this 3</h3>
-<h4 id=nonsel1>user cannot select this 1</h4>
-<h4 id=nonsel2>user cannot select this 2</h4>
-<h3 id=sel4>user can select this 4</h3>
-<h3 id=sel5>user can select this 5</h3>
-<h4 id=nonsel3>user cannot select this 3</h4>
-<h3 id=sel6>user can select this 6</h3>
-<h3 id=sel7>user can select this 7</h3>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_carets_selection.html b/testing/marionette/harness/marionette_harness/www/test_carets_selection.html
deleted file mode 100644
index f58b92fbff..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_carets_selection.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html id="html">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>Marionette tests for AccessibleCaret in selection mode</title>
- <style>
- .block {
- width: 10em;
- height: 4em;
- word-wrap: break-word;
- overflow: auto;
- }
- </style>
- </head>
- <body>
- <div>
- <input id="input" value="ABC DEF GHI">
- <input id="input-padding" style="padding: 1em;" value="ABC DEF GHI">
- </div>
- <br>
- <div>
- <textarea id="textarea" rows="4" cols="8">ABC DEF GHI JKL MNO PQR</textarea>
- <textarea id="textarea-one-line" rows="4" cols="12">ABC DEF GHI</textarea>
- </div>
- <br>
- <div><textarea dir="rtl" id="textarea-rtl" rows="8" cols="8">موزيلا ÙيرÙكس موزيلا ÙيرÙكس</textarea></div>
- <br>
- <div class="block" contenteditable="true" id="contenteditable">ABC DEF GHI</div>
- <br>
- <div class="block" id="content">ABC DEF GHI</div>
- <br>
- <div style="-moz-user-select: none;" id="non-selectable">Non-selectable</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_clearing.html b/testing/marionette/harness/marionette_harness/www/test_clearing.html
deleted file mode 100644
index 2aa3c6a21f..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_clearing.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<html>
- <!-- 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/. -->
- <body>
- <input id="writableTextInput" type="text" value="Test"/>
-
- <input id="readOnlyTextInput" type="text" readonly value="Test"/>
-
- <input id="textInputnotenabled" type="text" disabled="true" value="Test"/>
-
- <textarea id="writableTextArea" rows="2" cols="20">
- This is a sample text area which is supposed to be cleared
- </textarea>
-
- <textarea id="textAreaReadOnly" readonly rows="5" cols="20">
- text area which is not supposed to be cleared</textarea>
-
- <textarea rows="5" id="textAreaNotenabled" disabled="true" cols="20">
- text area which is not supposed to be cleared</textarea>
-
- <div id="content-editable" contentEditable="true">This is a contentEditable area</div>
- </body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_dynamic.html b/testing/marionette/harness/marionette_harness/www/test_dynamic.html
deleted file mode 100644
index dccc2c6acd..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_dynamic.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
- <head>
- <title></title>
- <script type="text/javascript">
- var next = 0;
-
- function addMore() {
- var box = document.createElement('DIV');
- box.id = 'box' + next++;
- box.className = 'redbox';
- box.style.width = '150px';
- box.style.height = '150px';
- box.style.backgroundColor = 'red';
- box.style.border = '1px solid black';
- box.style.margin = '5px';
- window.setTimeout(function() {
- document.body.appendChild(box);
- }, 1000);
- }
-
- function reveal() {
- var elem = document.getElementById('revealed');
- window.setTimeout(function() {
- elem.style.display = '';
- }, 1000);
- }
- </script>
- </head>
- <body>
- <input id="adder" type="button" value="Add a box!" onclick="addMore()"/>
-
- <input id="reveal" type="button" value="Reveal a new input" onclick="reveal();" />
-
- <input id="revealed" style="display:none;" />
- </body>
- </html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_iframe.html b/testing/marionette/harness/marionette_harness/www/test_iframe.html
deleted file mode 100644
index 7ed88665c5..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_iframe.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- 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/. -->
-
-<!doctype html>
-<html>
-<head>
-<title>Marionette IFrame Test</title>
-</head>
-<body>
- <h1 id="iframe_page_heading">This is the heading</h1>
-
- <iframe src="test.html" id="test_iframe"></iframe>
- <iframe src="test.html" id="test_iframe" name="test_iframe_name"></iframe>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_inner_iframe.html b/testing/marionette/harness/marionette_harness/www/test_inner_iframe.html
deleted file mode 100644
index c836fc6e45..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_inner_iframe.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!-- 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/. -->
-
-<!doctype html>
-<html>
-<head>
-<title>Inner Iframe</title>
-</head>
-<body>
- <iframe src="test.html" id="inner_frame"></iframe>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_nested_iframe.html b/testing/marionette/harness/marionette_harness/www/test_nested_iframe.html
deleted file mode 100644
index b4482183ea..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_nested_iframe.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!-- 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/. -->
-
-<!doctype html>
-<html>
-<head>
-<title>Marionette IFrame Test</title>
-</head>
-<body>
- <iframe src="test_inner_iframe.html" id="test_iframe"></iframe>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_oop_1.html b/testing/marionette/harness/marionette_harness/www/test_oop_1.html
deleted file mode 100644
index 62e4ad0473..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_oop_1.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>OOP Test Frame 1</title>
-</head>
-<body>
- <h1 id="testh1">OOP Test Frame 1</h1>
- Hello!
-</body>
-</html>
-
diff --git a/testing/marionette/harness/marionette_harness/www/test_oop_2.html b/testing/marionette/harness/marionette_harness/www/test_oop_2.html
deleted file mode 100644
index 05aca5adba..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_oop_2.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>OOP Test Frame 2</title>
-</head>
-<body>
- <h1 id="testh1">OOP Test Frame 2</h1>
- Hello!
-</body>
-</html>
-
diff --git a/testing/marionette/harness/marionette_harness/www/test_shadow_dom.html b/testing/marionette/harness/marionette_harness/www/test_shadow_dom.html
deleted file mode 100644
index 3ee893e6d5..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_shadow_dom.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-
-<html>
-<meta charset="UTF-8">
-<head>
-<title>Marionette Test</title>
-</head>
-<body>
- <div id="host"></div>
- <div id="empty-host"></div>
- <script>
- 'use strict';
- var host = document.getElementById('host');
- var root = host.createShadowRoot();
- root.innerHTML = '<button id="button">Foo</button>' +
- '<div id="inner-host"></div>';
- var innerHost = host.shadowRoot.getElementById('inner-host');
- var innerRoot = innerHost.createShadowRoot();
- innerRoot.innerHTML = '<button id="inner-button">Bar</button>';
- </script>
-</body>
-</html>
diff --git a/testing/marionette/harness/marionette_harness/www/test_windows.html b/testing/marionette/harness/marionette_harness/www/test_windows.html
deleted file mode 100644
index da1fd799ec..0000000000
--- a/testing/marionette/harness/marionette_harness/www/test_windows.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<!-- 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/. -->
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
- <title>XHTML Test Page</title>
-</head>
-<body>
- <p><a href="resultPage.html" onClick='javascript:window.open("resultPage.html",null, "menubar=0,location=1,resizable=1,scrollbars=1,status=0,width=700,height=375");' name="windowOne">Open new window</a></p>
-</body>
-</html>
-
diff --git a/testing/marionette/harness/marionette_harness/www/white.png b/testing/marionette/harness/marionette_harness/www/white.png
deleted file mode 100644
index 8a68c11548..0000000000
--- a/testing/marionette/harness/marionette_harness/www/white.png
+++ /dev/null
Binary files differ
diff --git a/testing/marionette/harness/marionette_harness/www/windowHandles.html b/testing/marionette/harness/marionette_harness/www/windowHandles.html
deleted file mode 100644
index 165526c8ac..0000000000
--- a/testing/marionette/harness/marionette_harness/www/windowHandles.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- 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/. -->
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>Marionette New Tab Link</title>
-</head>
-<body>
- <a href="empty.html" id="new-tab" target="_blank">New Tab</a>
- <a href="about:blank" id="new-blank-tab" target="_blank">New blank Tab</a>
-
- <a href="" id="new-window" onClick='javascript:window.open("empty.html", null, "location=1,toolbar=1");'>New Window</a>
-</body>
-</html> \ No newline at end of file
diff --git a/testing/marionette/harness/marionette_harness/www/xhtmlTest.html b/testing/marionette/harness/marionette_harness/www/xhtmlTest.html
deleted file mode 100644
index 146def33ad..0000000000
--- a/testing/marionette/harness/marionette_harness/www/xhtmlTest.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0"?>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <!-- 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/. -->
-<head>
- <title>XHTML Test Page</title>
-</head>
-<body>
-<div class="navigation">
- <p><a href="resultPage.html" target="result" name="windowOne">Open new window</a></p>
- <p><a href="iframes.html" target="_blank" name="windowTwo">Create a new anonymous window</a></p>
- <p><a href="test_iframe.html" name="sameWindow">Open page with iframes in same window</a></p>
- <p><a href="javascriptPage.html" target="result" name="windowThree">Open a window with a close button</a></p>
-</div>
-
-<a name="notext"><b></b></a>
-
-<div class="content">
- <h1 class="header">XHTML Might Be The Future</h1>
-
- <p>If you'd like to go elsewhere then <a href="resultPage.html">click me</a>.</p>
-
- <p>Alternatively, <a href="resultPage.html" id="linkId">this goes to the same place</a>.</p>
-
- <form name="someForm">
- <input id="username" type="text" value="change"/>
- </form>
-
- This link has the same text as another link: <a href="resultPage.html">click me</a>.
-</div>
-
-<div class="extraDiv">Another div starts here.<p/>
- <h2 class="nameA nameBnoise nameC">An H2 title</h2>
- <p class="nameC">Some more text</p>
-</div>
-
-<div>
- <a id="id1" href="#">Foo</a>
- <ul id="id2" />
- <span id="id3"/>
-</div>
-
-<div>
- <table id="table" ></table>
-</div>
-
-<span id="amazing">
-<div>
- <div>
- <div>
- <span/>
- <a>I have width</a>
- </div>
- </div>
-</div>
-</span>
-
-<a name="text" />
-<p id="spaces"> </p>
-<p id="empty"></p>
-<a href="foo" id="linkWithEqualsSign">Link=equalssign</a>
-
-<p class=" spaceAround ">Spaced out</p>
-
-<span id="my_span">
- <div>first_div</div>
- <div>second_div</div>
- <span>first_span</span>
- <span>second_span</span>
-</span>
-
-<div id="parent">I'm a parent
- <div id="child">I'm a child</div>
-</div>
-
-<div id="only-exists-on-xhtmltest">Woo woo</div>
-</body>
-</html>
diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
deleted file mode 100644
index 75ab9ce92b..0000000000
--- a/testing/marionette/harness/requirements.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-browsermob-proxy >= 0.6.0
-manifestparser >= 1.1
-marionette-driver >= 2.2.0
-mozcrash >= 0.5
-mozdevice >= 0.44
-mozinfo >= 0.8
-mozlog >= 3.0
-moznetwork >= 0.21
-mozprocess >= 0.9
-mozprofile >= 0.7
-mozrunner >= 6.13
-moztest >= 0.8
-mozversion >= 1.1
-wptserve >= 1.3.0
diff --git a/testing/marionette/harness/setup.py b/testing/marionette/harness/setup.py
deleted file mode 100644
index d28a970c1e..0000000000
--- a/testing/marionette/harness/setup.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import os
-import re
-
-from setuptools import find_packages, setup
-
-
-THIS_DIR = os.path.dirname(os.path.realpath(__name__))
-
-
-def read(*parts):
- with open(os.path.join(THIS_DIR, *parts)) as f:
- return f.read()
-
-
-def get_version():
- return re.findall("__version__ = '([\d\.]+)'",
- read('marionette_harness', '__init__.py'), re.M)[0]
-
-
-setup(name='marionette-harness',
- version=get_version(),
- description="Marionette test automation harness",
- long_description=open('README.rst').read(),
- # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
- 'Operating System :: MacOS :: MacOS X',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: POSIX',
- 'Topic :: Software Development :: Quality Assurance',
- 'Topic :: Software Development :: Testing',
- 'Topic :: Utilities',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2.7',
- ],
- keywords='mozilla',
- author='Auto-tools',
- author_email='tools-marionette@lists.mozilla.org',
- url='https://wiki.mozilla.org/Auto-tools/Projects/Marionette',
- license='Mozilla Public License 2.0 (MPL 2.0)',
- packages=find_packages(),
- package_data={
- 'marionette_harness': [
- 'runner/test.cert',
- 'runner/test.key'
- ],
- },
- # Needed to include package data as specified in MANIFEST.in
- include_package_data=True,
- install_requires=read('requirements.txt').splitlines(),
- zip_safe=False,
- entry_points="""
- # -*- Entry points: -*-
- [console_scripts]
- marionette = marionette_harness.runtests:cli
- """,
- )
diff --git a/testing/marionette/interaction.js b/testing/marionette/interaction.js
deleted file mode 100644
index 2392485d73..0000000000
--- a/testing/marionette/interaction.js
+++ /dev/null
@@ -1,505 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/accessibility.js");
-Cu.import("chrome://marionette/content/atom.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/event.js");
-
-Cu.importGlobalProperties(["File"]);
-
-this.EXPORTED_SYMBOLS = ["interaction"];
-
-/**
- * XUL elements that support disabled attribute.
- */
-const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
- "ARROWSCROLLBOX",
- "BUTTON",
- "CHECKBOX",
- "COLORPICKER",
- "COMMAND",
- "DATEPICKER",
- "DESCRIPTION",
- "KEY",
- "KEYSET",
- "LABEL",
- "LISTBOX",
- "LISTCELL",
- "LISTHEAD",
- "LISTHEADER",
- "LISTITEM",
- "MENU",
- "MENUITEM",
- "MENULIST",
- "MENUSEPARATOR",
- "PREFERENCE",
- "RADIO",
- "RADIOGROUP",
- "RICHLISTBOX",
- "RICHLISTITEM",
- "SCALE",
- "TAB",
- "TABS",
- "TEXTBOX",
- "TIMEPICKER",
- "TOOLBARBUTTON",
- "TREE",
-]);
-
-/**
- * XUL elements that support checked property.
- */
-const CHECKED_PROPERTY_SUPPORTED_XUL = new Set([
- "BUTTON",
- "CHECKBOX",
- "LISTITEM",
- "TOOLBARBUTTON",
-]);
-
-/**
- * XUL elements that support selected property.
- */
-const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([
- "LISTITEM",
- "MENU",
- "MENUITEM",
- "MENUSEPARATOR",
- "RADIO",
- "RICHLISTITEM",
- "TAB",
-]);
-
-/**
- * Common form controls that user can change the value property interactively.
- */
-const COMMON_FORM_CONTROLS = new Set([
- "input",
- "textarea",
- "select",
-]);
-
-/**
- * Input elements that do not fire "input" and "change" events when value
- * property changes.
- */
-const INPUT_TYPES_NO_EVENT = new Set([
- "checkbox",
- "radio",
- "file",
- "hidden",
- "image",
- "reset",
- "button",
- "submit",
-]);
-
-this.interaction = {};
-
-/**
- * Interact with an element by clicking it.
- *
- * The element is scrolled into view before visibility- or interactability
- * checks are performed.
- *
- * Selenium-style visibility checks will be performed if |specCompat|
- * is false (default). Otherwise pointer-interactability checks will be
- * performed. If either of these fail an
- * {@code ElementNotInteractableError} is thrown.
- *
- * If |strict| is enabled (defaults to disabled), further accessibility
- * checks will be performed, and these may result in an
- * {@code ElementNotAccessibleError} being returned.
- *
- * When |el| is not enabled, an {@code InvalidElementStateError}
- * is returned.
- *
- * @param {DOMElement|XULElement} el
- * Element to click.
- * @param {boolean=} strict
- * Enforce strict accessibility tests.
- * @param {boolean=} specCompat
- * Use WebDriver specification compatible interactability definition.
- *
- * @throws {ElementNotInteractableError}
- * If either Selenium-style visibility check or
- * pointer-interactability check fails.
- * @throws {ElementClickInterceptedError}
- * If |el| is obscured by another element and a click would not hit,
- * in |specCompat| mode.
- * @throws {ElementNotAccessibleError}
- * If |strict| is true and element is not accessible.
- * @throws {InvalidElementStateError}
- * If |el| is not enabled.
- */
-interaction.clickElement = function* (el, strict = false, specCompat = false) {
- const a11y = accessibility.get(strict);
- if (specCompat) {
- yield webdriverClickElement(el, a11y);
- } else {
- yield seleniumClickElement(el, a11y);
- }
-};
-
-function* webdriverClickElement (el, a11y) {
- const win = getWindow(el);
- const doc = win.document;
-
- // step 3
- if (el.localName == "input" && el.type == "file") {
- throw new InvalidArgumentError(
- "Cannot click <input type=file> elements");
- }
-
- let containerEl = element.getContainer(el);
-
- // step 4
- if (!element.isInView(containerEl)) {
- element.scrollIntoView(containerEl);
- }
-
- // step 5
- // TODO(ato): wait for containerEl to be in view
-
- // step 6
- // if we cannot bring the container element into the viewport
- // there is no point in checking if it is pointer-interactable
- if (!element.isInView(containerEl)) {
- throw new ElementNotInteractableError(
- error.pprint`Element ${el} could not be scrolled into view`);
- }
-
- // step 7
- let rects = containerEl.getClientRects();
- let clickPoint = element.getInViewCentrePoint(rects[0], win);
-
- if (!element.isPointerInteractable(containerEl)) {
- throw new ElementClickInterceptedError(containerEl, clickPoint);
- }
-
- yield a11y.getAccessible(el, true).then(acc => {
- a11y.assertVisible(acc, el, true);
- a11y.assertEnabled(acc, el, true);
- a11y.assertActionable(acc, el);
- });
-
- // step 8
-
- // chrome elements
- if (element.isXULElement(el)) {
- if (el.localName == "option") {
- interaction.selectOption(el);
- } else {
- el.click();
- }
-
- // content elements
- } else {
- if (el.localName == "option") {
- interaction.selectOption(el);
- } else {
- event.synthesizeMouseAtPoint(clickPoint.x, clickPoint.y, {}, win);
- }
- }
-
- // step 9
- yield interaction.flushEventLoop(win);
-
- // step 10
- // TODO(ato): if the click causes navigation,
- // run post-navigation checks
-}
-
-function* seleniumClickElement (el, a11y) {
- let win = getWindow(el);
-
- let visibilityCheckEl = el;
- if (el.localName == "option") {
- visibilityCheckEl = element.getContainer(el);
- }
-
- if (!element.isVisible(visibilityCheckEl)) {
- throw new ElementNotInteractableError();
- }
-
- if (!atom.isElementEnabled(el)) {
- throw new InvalidElementStateError("Element is not enabled");
- }
-
- yield a11y.getAccessible(el, true).then(acc => {
- a11y.assertVisible(acc, el, true);
- a11y.assertEnabled(acc, el, true);
- a11y.assertActionable(acc, el);
- });
-
- // chrome elements
- if (element.isXULElement(el)) {
- if (el.localName == "option") {
- interaction.selectOption(el);
- } else {
- el.click();
- }
-
- // content elements
- } else {
- if (el.localName == "option") {
- interaction.selectOption(el);
- } else {
- let rects = el.getClientRects();
- let centre = element.getInViewCentrePoint(rects[0], win);
- let opts = {};
- event.synthesizeMouseAtPoint(centre.x, centre.y, opts, win);
- }
- }
-};
-
-/**
- * Select <option> element in a <select> list.
- *
- * Because the dropdown list of select elements are implemented using
- * native widget technology, our trusted synthesised events are not able
- * to reach them. Dropdowns are instead handled mimicking DOM events,
- * which for obvious reasons is not ideal, but at the current point in
- * time considered to be good enough.
- *
- * @param {HTMLOptionElement} option
- * Option element to select.
- *
- * @throws TypeError
- * If |el| is a XUL element or not an <option> element.
- * @throws Error
- * If unable to find |el|'s parent <select> element.
- */
-interaction.selectOption = function (el) {
- if (element.isXULElement(el)) {
- throw new Error("XUL dropdowns not supported");
- }
- if (el.localName != "option") {
- throw new TypeError("Invalid elements");
- }
-
- let win = getWindow(el);
- let containerEl = element.getContainer(el);
-
- event.mouseover(containerEl);
- event.mousemove(containerEl);
- event.mousedown(containerEl);
- event.focus(containerEl);
- event.input(containerEl);
-
- // toggle selectedness the way holding down control works
- el.selected = !el.selected;
-
- event.change(containerEl);
- event.mouseup(containerEl);
- event.click(containerEl);
-};
-
-/**
- * Flushes the event loop by requesting an animation frame.
- *
- * This will wait for the browser to repaint before returning, typically
- * flushing any queued events.
- *
- * If the document is unloaded during this request, the promise is
- * rejected.
- *
- * @param {Window} win
- * Associated window.
- *
- * @return {Promise}
- * Promise is accepted once event queue is flushed, or rejected if
- * |win| is unloaded before the queue can be flushed.
- */
-interaction.flushEventLoop = function* (win) {
- let unloadEv;
- return new Promise((resolve, reject) => {
- unloadEv = reject;
- win.addEventListener("unload", unloadEv, {once: true});
- win.requestAnimationFrame(resolve);
- }).then(() => {
- win.removeEventListener("unload", unloadEv);
- });
-};
-
-/**
- * Appends |path| to an <input type=file>'s file list.
- *
- * @param {HTMLInputElement} el
- * An <input type=file> element.
- * @param {string} path
- * Full path to file.
- */
-interaction.uploadFile = function (el, path) {
- let file;
- try {
- file = File.createFromFileName(path);
- } catch (e) {
- throw new InvalidArgumentError("File not found: " + path);
- }
-
- let fs = Array.prototype.slice.call(el.files);
- fs.push(file);
-
- // <input type=file> opens OS widget dialogue
- // which means the mousedown/focus/mouseup/click events
- // occur before the change event
- event.mouseover(el);
- event.mousemove(el);
- event.mousedown(el);
- event.focus(el);
- event.mouseup(el);
- event.click(el);
-
- el.mozSetFileArray(fs);
-
- event.change(el);
-};
-
-/**
- * Sets a form element's value.
- *
- * @param {DOMElement} el
- * An form element, e.g. input, textarea, etc.
- * @param {string} value
- * The value to be set.
- *
- * @throws TypeError
- * If |el| is not an supported form element.
- */
-interaction.setFormControlValue = function* (el, value) {
- if (!COMMON_FORM_CONTROLS.has(el.localName)) {
- throw new TypeError("This function is for form elements only");
- }
-
- el.value = value;
-
- if (INPUT_TYPES_NO_EVENT.has(el.type)) {
- return;
- }
-
- event.input(el);
- event.change(el);
-};
-
-/**
- * Send keys to element.
- *
- * @param {DOMElement|XULElement} el
- * Element to send key events to.
- * @param {Array.<string>} value
- * Sequence of keystrokes to send to the element.
- * @param {boolean} ignoreVisibility
- * Flag to enable or disable element visibility tests.
- * @param {boolean=} strict
- * Enforce strict accessibility tests.
- */
-interaction.sendKeysToElement = function (el, value, ignoreVisibility, strict = false) {
- let win = getWindow(el);
- let a11y = accessibility.get(strict);
- return a11y.getAccessible(el, true).then(acc => {
- a11y.assertActionable(acc, el);
- event.sendKeysToElement(value, el, {ignoreVisibility: false}, win);
- });
-};
-
-/**
- * Determine the element displayedness of an element.
- *
- * @param {DOMElement|XULElement} el
- * Element to determine displayedness of.
- * @param {boolean=} strict
- * Enforce strict accessibility tests.
- *
- * @return {boolean}
- * True if element is displayed, false otherwise.
- */
-interaction.isElementDisplayed = function (el, strict = false) {
- let win = getWindow(el);
- let displayed = atom.isElementDisplayed(el, win);
-
- let a11y = accessibility.get(strict);
- return a11y.getAccessible(el).then(acc => {
- a11y.assertVisible(acc, el, displayed);
- return displayed;
- });
-};
-
-/**
- * Check if element is enabled.
- *
- * @param {DOMElement|XULElement} el
- * Element to test if is enabled.
- *
- * @return {boolean}
- * True if enabled, false otherwise.
- */
-interaction.isElementEnabled = function (el, strict = false) {
- let enabled = true;
- let win = getWindow(el);
-
- if (element.isXULElement(el)) {
- // check if XUL element supports disabled attribute
- if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
- let disabled = atom.getElementAttribute(el, "disabled", win);
- if (disabled && disabled === "true") {
- enabled = false;
- }
- }
- } else {
- enabled = atom.isElementEnabled(el, {frame: win});
- }
-
- let a11y = accessibility.get(strict);
- return a11y.getAccessible(el).then(acc => {
- a11y.assertEnabled(acc, el, enabled);
- return enabled;
- });
-};
-
-/**
- * Determines if the referenced element is selected or not.
- *
- * This operation only makes sense on input elements of the Checkbox-
- * and Radio Button states, or option elements.
- *
- * @param {DOMElement|XULElement} el
- * Element to test if is selected.
- * @param {boolean=} strict
- * Enforce strict accessibility tests.
- *
- * @return {boolean}
- * True if element is selected, false otherwise.
- */
-interaction.isElementSelected = function (el, strict = false) {
- let selected = true;
- let win = getWindow(el);
-
- if (element.isXULElement(el)) {
- let tagName = el.tagName.toUpperCase();
- if (CHECKED_PROPERTY_SUPPORTED_XUL.has(tagName)) {
- selected = el.checked;
- }
- if (SELECTED_PROPERTY_SUPPORTED_XUL.has(tagName)) {
- selected = el.selected;
- }
- } else {
- selected = atom.isElementSelected(el, win);
- }
-
- let a11y = accessibility.get(strict);
- return a11y.getAccessible(el).then(acc => {
- a11y.assertSelected(acc, el, selected);
- return selected;
- });
-};
-
-function getWindow(el) {
- return el.ownerDocument.defaultView;
-}
diff --git a/testing/marionette/jar.mn b/testing/marionette/jar.mn
deleted file mode 100644
index c9ea8b213f..0000000000
--- a/testing/marionette/jar.mn
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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/.
-
-marionette.jar:
-% content marionette %content/
- content/server.js (server.js)
- content/driver.js (driver.js)
- content/action.js (action.js)
- content/legacyaction.js (legacyaction.js)
- content/browser.js (browser.js)
- content/interaction.js (interaction.js)
- content/accessibility.js (accessibility.js)
- content/listener.js (listener.js)
- content/element.js (element.js)
- content/simpletest.js (simpletest.js)
- content/frame.js (frame.js)
- content/cert.js (cert.js)
- content/event.js (event.js)
- content/error.js (error.js)
- content/message.js (message.js)
- content/dispatcher.js (dispatcher.js)
- content/modal.js (modal.js)
- content/proxy.js (proxy.js)
- content/capture.js (capture.js)
- content/cookies.js (cookies.js)
- content/atom.js (atom.js)
- content/evaluate.js (evaluate.js)
- content/logging.js (logging.js)
- content/navigate.js (navigate.js)
- content/l10n.js (l10n.js)
- content/assert.js (assert.js)
- content/addon.js (addon.js)
- content/session.js (session.js)
-#ifdef ENABLE_TESTS
- content/test.xul (chrome/test.xul)
- content/test2.xul (chrome/test2.xul)
- content/test_dialog.dtd (chrome/test_dialog.dtd)
- content/test_dialog.properties (chrome/test_dialog.properties)
- content/test_dialog.xul (chrome/test_dialog.xul)
- content/test_nested_iframe.xul (chrome/test_nested_iframe.xul)
- content/test_anonymous_content.xul (chrome/test_anonymous_content.xul)
-#endif
diff --git a/testing/marionette/l10n.js b/testing/marionette/l10n.js
deleted file mode 100644
index de5dbf2a78..0000000000
--- a/testing/marionette/l10n.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-/**
- * An API which allows Marionette to handle localized content.
- *
- * The localization (https://mzl.la/2eUMjyF) of UI elements in Gecko based
- * applications is done via entities and properties. For static values entities
- * are used, which are located in .dtd files. Whereby for dynamically updated
- * content the values come from .property files. Both types of elements can be
- * identifed via a unique id, and the translated content retrieved.
- */
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(
- this, "domParser", "@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["l10n"];
-
-this.l10n = {};
-
-/**
- * Retrieve the localized string for the specified entity id.
- *
- * Example:
- * localizeEntity(["chrome://global/locale/about.dtd"], "about.version")
- *
- * @param {Array.<string>} urls
- * Array of .dtd URLs.
- * @param {string} id
- * The ID of the entity to retrieve the localized string for.
- *
- * @return {string}
- * The localized string for the requested entity.
- */
-l10n.localizeEntity = function (urls, id) {
- // Build a string which contains all possible entity locations
- let locations = [];
- urls.forEach((url, index) => {
- locations.push(`<!ENTITY % dtd_${index} SYSTEM "${url}">%dtd_${index};`);
- })
-
- // Use the DOM parser to resolve the entity and extract its real value
- let header = `<?xml version="1.0"?><!DOCTYPE elem [${locations.join("")}]>`;
- let elem = `<elem id="elementID">&${id};</elem>`;
- let doc = domParser.parseFromString(header + elem, "text/xml");
- let element = doc.querySelector("elem[id='elementID']");
-
- if (element === null) {
- throw new NoSuchElementError(`Entity with id='${id}' hasn't been found`);
- }
-
- return element.textContent;
-};
-
-/**
- * Retrieve the localized string for the specified property id.
- *
- * Example:
- * localizeProperty(["chrome://global/locale/findbar.properties"], "FastFind")
- *
- * @param {Array.<string>} urls
- * Array of .properties URLs.
- * @param {string} id
- * The ID of the property to retrieve the localized string for.
- *
- * @return {string}
- * The localized string for the requested property.
- */
-l10n.localizeProperty = function (urls, id) {
- let property = null;
-
- for (let url of urls) {
- let bundle = Services.strings.createBundle(url);
- try {
- property = bundle.GetStringFromName(id);
- break;
- } catch (e) {}
- };
-
- if (property === null) {
- throw new NoSuchElementError(`Property with id='${id}' hasn't been found`);
- }
-
- return property;
-};
diff --git a/testing/marionette/legacyaction.js b/testing/marionette/legacyaction.js
deleted file mode 100644
index 5d108210c9..0000000000
--- a/testing/marionette/legacyaction.js
+++ /dev/null
@@ -1,477 +0,0 @@
-/* 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/. */
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/event.js");
-
-const CONTEXT_MENU_DELAY_PREF = "ui.click_hold_context_menus.delay";
-const DEFAULT_CONTEXT_MENU_DELAY = 750; // ms
-
-this.EXPORTED_SYMBOLS = ["legacyaction"];
-
-const logger = Log.repository.getLogger("Marionette");
-
-this.legacyaction = this.action = {};
-
-/**
- * Functionality for (single finger) action chains.
- */
-action.Chain = function (checkForInterrupted) {
- // for assigning unique ids to all touches
- this.nextTouchId = 1000;
- // keep track of active Touches
- this.touchIds = {};
- // last touch for each fingerId
- this.lastCoordinates = null;
- this.isTap = false;
- this.scrolling = false;
- // whether to send mouse event
- this.mouseEventsOnly = false;
- this.checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-
- if (typeof checkForInterrupted == "function") {
- this.checkForInterrupted = checkForInterrupted;
- } else {
- this.checkForInterrupted = () => {};
- }
-
- // determines if we create touch events
- this.inputSource = null;
-};
-
-action.Chain.prototype.dispatchActions = function (
- args,
- touchId,
- container,
- seenEls,
- touchProvider) {
- // Some touch events code in the listener needs to do ipc, so we can't
- // share this code across chrome/content.
- if (touchProvider) {
- this.touchProvider = touchProvider;
- }
-
- this.seenEls = seenEls;
- this.container = container;
- let commandArray = element.fromJson(
- args, seenEls, container.frame, container.shadowRoot);
-
- if (touchId == null) {
- touchId = this.nextTouchId++;
- }
-
- if (!container.frame.document.createTouch) {
- this.mouseEventsOnly = true;
- }
-
- let keyModifiers = {
- shiftKey: false,
- ctrlKey: false,
- altKey: false,
- metaKey: false,
- };
-
- return new Promise(resolve => {
- this.actions(commandArray, touchId, 0, keyModifiers, resolve);
- }).catch(this.resetValues);
-};
-
-/**
- * This function emit mouse event.
- *
- * @param {Document} doc
- * Current document.
- * @param {string} type
- * Type of event to dispatch.
- * @param {number} clickCount
- * Number of clicks, button notes the mouse button.
- * @param {number} elClientX
- * X coordinate of the mouse relative to the viewport.
- * @param {number} elClientY
- * Y coordinate of the mouse relative to the viewport.
- * @param {Object} modifiers
- * An object of modifier keys present.
- */
-action.Chain.prototype.emitMouseEvent = function (
- doc,
- type,
- elClientX,
- elClientY,
- button,
- clickCount,
- modifiers) {
- if (!this.checkForInterrupted()) {
- logger.debug(`Emitting ${type} mouse event ` +
- `at coordinates (${elClientX}, ${elClientY}) ` +
- `relative to the viewport, ` +
- `button: ${button}, ` +
- `clickCount: ${clickCount}`);
-
- let win = doc.defaultView;
- let domUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
-
- let mods;
- if (typeof modifiers != "undefined") {
- mods = event.parseModifiers_(modifiers);
- } else {
- mods = 0;
- }
-
- domUtils.sendMouseEvent(
- type,
- elClientX,
- elClientY,
- button || 0,
- clickCount || 1,
- mods,
- false,
- 0,
- this.inputSource);
- }
-};
-
-/**
- * Reset any persisted values after a command completes.
- */
-action.Chain.prototype.resetValues = function() {
- this.container = null;
- this.seenEls = null;
- this.touchProvider = null;
- this.mouseEventsOnly = false;
-};
-
-/**
- * Emit events for each action in the provided chain.
- *
- * To emit touch events for each finger, one might send a [["press", id],
- * ["wait", 5], ["release"]] chain.
- *
- * @param {Array.<Array<?>>} chain
- * A multi-dimensional array of actions.
- * @param {Object.<string, number>} touchId
- * Represents the finger ID.
- * @param {number} i
- * Keeps track of the current action of the chain.
- * @param {Object.<string, boolean>} keyModifiers
- * Keeps track of keyDown/keyUp pairs through an action chain.
- * @param {function(?)} cb
- * Called on success.
- *
- * @return {Object.<string, number>}
- * Last finger ID, or an empty object.
- */
-action.Chain.prototype.actions = function (chain, touchId, i, keyModifiers, cb) {
- if (i == chain.length) {
- cb(touchId || null);
- this.resetValues();
- return;
- }
-
- let pack = chain[i];
- let command = pack[0];
- let el;
- let c;
- i++;
-
- if (["press", "wait", "keyDown", "keyUp", "click"].indexOf(command) == -1) {
- // if mouseEventsOnly, then touchIds isn't used
- if (!(touchId in this.touchIds) && !this.mouseEventsOnly) {
- this.resetValues();
- throw new WebDriverError("Element has not been pressed");
- }
- }
-
- switch (command) {
- case "keyDown":
- event.sendKeyDown(pack[1], keyModifiers, this.container.frame);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "keyUp":
- event.sendKeyUp(pack[1], keyModifiers, this.container.frame);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "click":
- el = this.seenEls.get(pack[1], this.container);
- let button = pack[2];
- let clickCount = pack[3];
- c = element.coordinates(el);
- this.mouseTap(el.ownerDocument, c.x, c.y, button, clickCount, keyModifiers);
- if (button == 2) {
- this.emitMouseEvent(el.ownerDocument, "contextmenu", c.x, c.y,
- button, clickCount, keyModifiers);
- }
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "press":
- if (this.lastCoordinates) {
- this.generateEvents(
- "cancel",
- this.lastCoordinates[0],
- this.lastCoordinates[1],
- touchId,
- null,
- keyModifiers);
- this.resetValues();
- throw new WebDriverError(
- "Invalid Command: press cannot follow an active touch event");
- }
-
- // look ahead to check if we're scrolling,
- // needed for APZ touch dispatching
- if ((i != chain.length) && (chain[i][0].indexOf('move') !== -1)) {
- this.scrolling = true;
- }
- el = this.seenEls.get(pack[1], this.container);
- c = element.coordinates(el, pack[2], pack[3]);
- touchId = this.generateEvents("press", c.x, c.y, null, el, keyModifiers);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "release":
- this.generateEvents(
- "release",
- this.lastCoordinates[0],
- this.lastCoordinates[1],
- touchId,
- null,
- keyModifiers);
- this.actions(chain, null, i, keyModifiers, cb);
- this.scrolling = false;
- break;
-
- case "move":
- el = this.seenEls.get(pack[1], this.container);
- c = element.coordinates(el);
- this.generateEvents("move", c.x, c.y, touchId, null, keyModifiers);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "moveByOffset":
- this.generateEvents(
- "move",
- this.lastCoordinates[0] + pack[1],
- this.lastCoordinates[1] + pack[2],
- touchId,
- null,
- keyModifiers);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
-
- case "wait":
- if (pack[1] != null) {
- let time = pack[1] * 1000;
-
- // standard waiting time to fire contextmenu
- let standard = Preferences.get(
- CONTEXT_MENU_DELAY_PREF,
- DEFAULT_CONTEXT_MENU_DELAY);
-
- if (time >= standard && this.isTap) {
- chain.splice(i, 0, ["longPress"], ["wait", (time - standard) / 1000]);
- time = standard;
- }
- this.checkTimer.initWithCallback(
- () => this.actions(chain, touchId, i, keyModifiers, cb),
- time, Ci.nsITimer.TYPE_ONE_SHOT);
- } else {
- this.actions(chain, touchId, i, keyModifiers, cb);
- }
- break;
-
- case "cancel":
- this.generateEvents(
- "cancel",
- this.lastCoordinates[0],
- this.lastCoordinates[1],
- touchId,
- null,
- keyModifiers);
- this.actions(chain, touchId, i, keyModifiers, cb);
- this.scrolling = false;
- break;
-
- case "longPress":
- this.generateEvents(
- "contextmenu",
- this.lastCoordinates[0],
- this.lastCoordinates[1],
- touchId,
- null,
- keyModifiers);
- this.actions(chain, touchId, i, keyModifiers, cb);
- break;
- }
-};
-
-/**
- * Given an element and a pair of coordinates, returns an array of the
- * form [clientX, clientY, pageX, pageY, screenX, screenY].
- */
-action.Chain.prototype.getCoordinateInfo = function (el, corx, cory) {
- let win = el.ownerDocument.defaultView;
- return [
- corx, // clientX
- cory, // clientY
- corx + win.pageXOffset, // pageX
- cory + win.pageYOffset, // pageY
- corx + win.mozInnerScreenX, // screenX
- cory + win.mozInnerScreenY // screenY
- ];
-};
-
-/**
- * @param {number} x
- * X coordinate of the location to generate the event that is relative
- * to the viewport.
- * @param {number} y
- * Y coordinate of the location to generate the event that is relative
- * to the viewport.
- */
-action.Chain.prototype.generateEvents = function (
- type, x, y, touchId, target, keyModifiers) {
- this.lastCoordinates = [x, y];
- let doc = this.container.frame.document;
-
- switch (type) {
- case "tap":
- if (this.mouseEventsOnly) {
- this.mouseTap(
- touch.target.ownerDocument,
- touch.clientX,
- touch.clientY,
- null,
- null,
- keyModifiers);
- } else {
- touchId = this.nextTouchId++;
- let touch = this.touchProvider.createATouch(target, x, y, touchId);
- this.touchProvider.emitTouchEvent("touchstart", touch);
- this.touchProvider.emitTouchEvent("touchend", touch);
- this.mouseTap(
- touch.target.ownerDocument,
- touch.clientX,
- touch.clientY,
- null,
- null,
- keyModifiers);
- }
- this.lastCoordinates = null;
- break;
-
- case "press":
- this.isTap = true;
- if (this.mouseEventsOnly) {
- this.emitMouseEvent(doc, "mousemove", x, y, null, null, keyModifiers);
- this.emitMouseEvent(doc, "mousedown", x, y, null, null, keyModifiers);
- } else {
- touchId = this.nextTouchId++;
- let touch = this.touchProvider.createATouch(target, x, y, touchId);
- this.touchProvider.emitTouchEvent("touchstart", touch);
- this.touchIds[touchId] = touch;
- return touchId;
- }
- break;
-
- case "release":
- if (this.mouseEventsOnly) {
- let [x, y] = this.lastCoordinates;
- this.emitMouseEvent(doc, "mouseup", x, y, null, null, keyModifiers);
- } else {
- let touch = this.touchIds[touchId];
- let [x, y] = this.lastCoordinates;
-
- touch = this.touchProvider.createATouch(touch.target, x, y, touchId);
- this.touchProvider.emitTouchEvent("touchend", touch);
-
- if (this.isTap) {
- this.mouseTap(
- touch.target.ownerDocument,
- touch.clientX,
- touch.clientY,
- null,
- null,
- keyModifiers);
- }
- delete this.touchIds[touchId];
- }
-
- this.isTap = false;
- this.lastCoordinates = null;
- break;
-
- case "cancel":
- this.isTap = false;
- if (this.mouseEventsOnly) {
- let [x, y] = this.lastCoordinates;
- this.emitMouseEvent(doc, "mouseup", x, y, null, null, keyModifiers);
- } else {
- this.touchProvider.emitTouchEvent("touchcancel", this.touchIds[touchId]);
- delete this.touchIds[touchId];
- }
- this.lastCoordinates = null;
- break;
-
- case "move":
- this.isTap = false;
- if (this.mouseEventsOnly) {
- this.emitMouseEvent(doc, "mousemove", x, y, null, null, keyModifiers);
- } else {
- let touch = this.touchProvider.createATouch(
- this.touchIds[touchId].target, x, y, touchId);
- this.touchIds[touchId] = touch;
- this.touchProvider.emitTouchEvent("touchmove", touch);
- }
- break;
-
- case "contextmenu":
- this.isTap = false;
- let event = this.container.frame.document.createEvent("MouseEvents");
- if (this.mouseEventsOnly) {
- target = doc.elementFromPoint(this.lastCoordinates[0], this.lastCoordinates[1]);
- } else {
- target = this.touchIds[touchId].target;
- }
-
- let [clientX, clientY, pageX, pageY, screenX, screenY] =
- this.getCoordinateInfo(target, x, y);
-
- event.initMouseEvent(
- "contextmenu",
- true,
- true,
- target.ownerDocument.defaultView,
- 1,
- screenX,
- screenY,
- clientX,
- clientY,
- false,
- false,
- false,
- false,
- 0,
- null);
- target.dispatchEvent(event);
- break;
-
- default:
- throw new WebDriverError("Unknown event type: " + type);
- }
- this.checkForInterrupted();
-};
-
-action.Chain.prototype.mouseTap = function (doc, x, y, button, count, mod) {
- this.emitMouseEvent(doc, "mousemove", x, y, button, count, mod);
- this.emitMouseEvent(doc, "mousedown", x, y, button, count, mod);
- this.emitMouseEvent(doc, "mouseup", x, y, button, count, mod);
-};
diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js
deleted file mode 100644
index 619ac249d1..0000000000
--- a/testing/marionette/listener.js
+++ /dev/null
@@ -1,1816 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-var uuidGen = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
-
-var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Ci.mozIJSSubScriptLoader);
-
-Cu.import("chrome://marionette/content/accessibility.js");
-Cu.import("chrome://marionette/content/action.js");
-Cu.import("chrome://marionette/content/atom.js");
-Cu.import("chrome://marionette/content/capture.js");
-Cu.import("chrome://marionette/content/cookies.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/evaluate.js");
-Cu.import("chrome://marionette/content/event.js");
-Cu.import("chrome://marionette/content/interaction.js");
-Cu.import("chrome://marionette/content/legacyaction.js");
-Cu.import("chrome://marionette/content/logging.js");
-Cu.import("chrome://marionette/content/navigate.js");
-Cu.import("chrome://marionette/content/proxy.js");
-Cu.import("chrome://marionette/content/session.js");
-Cu.import("chrome://marionette/content/simpletest.js");
-
-Cu.import("resource://gre/modules/FileUtils.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-Cu.importGlobalProperties(["URL"]);
-
-var contentLog = new logging.ContentLogger();
-
-var isB2G = false;
-
-var marionetteTestName;
-var winUtil = content.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
-var listenerId = null; // unique ID of this listener
-var curContainer = { frame: content, shadowRoot: null };
-var isRemoteBrowser = () => curContainer.frame.contentWindow !== null;
-var previousContainer = null;
-
-var seenEls = new element.Store();
-var SUPPORTED_STRATEGIES = new Set([
- element.Strategy.ClassName,
- element.Strategy.Selector,
- element.Strategy.ID,
- element.Strategy.Name,
- element.Strategy.LinkText,
- element.Strategy.PartialLinkText,
- element.Strategy.TagName,
- element.Strategy.XPath,
-]);
-
-var capabilities;
-
-var legacyactions = new legacyaction.Chain(checkForInterrupted);
-
-// the unload handler
-var onunload;
-
-// Flag to indicate whether an async script is currently running or not.
-var asyncTestRunning = false;
-var asyncTestCommandId;
-var asyncTestTimeoutId;
-
-var inactivityTimeoutId = null;
-
-var originalOnError;
-//timer for doc changes
-var checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-//timer for readystate
-var readyStateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-// timer for navigation commands.
-var navTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-var onDOMContentLoaded;
-// Send move events about this often
-var EVENT_INTERVAL = 30; // milliseconds
-// last touch for each fingerId
-var multiLast = {};
-var asyncChrome = proxy.toChromeAsync({
- addMessageListener: addMessageListenerId.bind(this),
- removeMessageListener: removeMessageListenerId.bind(this),
- sendAsyncMessage: sendAsyncMessage.bind(this),
-});
-var syncChrome = proxy.toChrome(sendSyncMessage.bind(this));
-var cookies = new Cookies(() => curContainer.frame.document, syncChrome);
-var importedScripts = new evaluate.ScriptStorageServiceClient(syncChrome);
-
-Cu.import("resource://gre/modules/Log.jsm");
-var logger = Log.repository.getLogger("Marionette");
-logger.debug("loaded listener.js");
-
-var modalHandler = function() {
- // This gets called on the system app only since it receives the mozbrowserprompt event
- sendSyncMessage("Marionette:switchedToFrame", {frameValue: null, storePrevious: true});
- let isLocal = sendSyncMessage("MarionetteFrame:handleModal", {})[0].value;
- if (isLocal) {
- previousContainer = curContainer;
- }
- curContainer = {frame: content, shadowRoot: null};
-};
-
-// sandbox storage and name of the current sandbox
-var sandboxes = new Sandboxes(() => curContainer.frame);
-var sandboxName = "default";
-
-/**
- * Called when listener is first started up.
- * The listener sends its unique window ID and its current URI to the actor.
- * If the actor returns an ID, we start the listeners. Otherwise, nothing happens.
- */
-function registerSelf() {
- let msg = {value: winUtil.outerWindowID};
- // register will have the ID and a boolean describing if this is the main process or not
- let register = sendSyncMessage("Marionette:register", msg);
-
- if (register[0]) {
- let {id, remotenessChange} = register[0][0];
- capabilities = session.Capabilities.fromJSON(register[0][2]);
- listenerId = id;
- if (typeof id != "undefined") {
- // check if we're the main process
- if (register[0][1]) {
- addMessageListener("MarionetteMainListener:emitTouchEvent", emitTouchEventForIFrame);
- }
- startListeners();
- let rv = {};
- if (remotenessChange) {
- rv.listenerId = id;
- }
- sendAsyncMessage("Marionette:listenersAttached", rv);
- }
- }
-}
-
-function emitTouchEventForIFrame(message) {
- message = message.json;
- let identifier = legacyactions.nextTouchId;
-
- let domWindowUtils = curContainer.frame.
- QueryInterface(Components.interfaces.nsIInterfaceRequestor).
- getInterface(Components.interfaces.nsIDOMWindowUtils);
- var ratio = domWindowUtils.screenPixelsPerCSSPixel;
-
- var typeForUtils;
- switch (message.type) {
- case 'touchstart':
- typeForUtils = domWindowUtils.TOUCH_CONTACT;
- break;
- case 'touchend':
- typeForUtils = domWindowUtils.TOUCH_REMOVE;
- break;
- case 'touchcancel':
- typeForUtils = domWindowUtils.TOUCH_CANCEL;
- break;
- case 'touchmove':
- typeForUtils = domWindowUtils.TOUCH_CONTACT;
- break;
- }
- domWindowUtils.sendNativeTouchPoint(identifier, typeForUtils,
- Math.round(message.screenX * ratio), Math.round(message.screenY * ratio),
- message.force, 90);
-}
-
-// Eventually we will not have a closure for every single command, but
-// use a generic dispatch for all listener commands.
-//
-// Perhaps one could even conceive having a separate instance of
-// CommandProcessor for the listener, because the code is mostly the same.
-function dispatch(fn) {
- if (typeof fn != "function") {
- throw new TypeError("Provided dispatch handler is not a function");
- }
-
- return function (msg) {
- let id = msg.json.command_id;
-
- let req = Task.spawn(function*() {
- if (typeof msg.json == "undefined" || msg.json instanceof Array) {
- return yield fn.apply(null, msg.json);
- } else {
- return yield fn(msg.json);
- }
- });
-
- let okOrValueResponse = rv => {
- if (typeof rv == "undefined") {
- sendOk(id);
- } else {
- sendResponse(rv, id);
- }
- };
-
- req.then(okOrValueResponse, err => sendError(err, id))
- .catch(error.report);
- };
-}
-
-/**
- * Add a message listener that's tied to our listenerId.
- */
-function addMessageListenerId(messageName, handler) {
- addMessageListener(messageName + listenerId, handler);
-}
-
-/**
- * Remove a message listener that's tied to our listenerId.
- */
-function removeMessageListenerId(messageName, handler) {
- removeMessageListener(messageName + listenerId, handler);
-}
-
-var getTitleFn = dispatch(getTitle);
-var getPageSourceFn = dispatch(getPageSource);
-var getActiveElementFn = dispatch(getActiveElement);
-var clickElementFn = dispatch(clickElement);
-var getElementAttributeFn = dispatch(getElementAttribute);
-var getElementPropertyFn = dispatch(getElementProperty);
-var getElementTextFn = dispatch(getElementText);
-var getElementTagNameFn = dispatch(getElementTagName);
-var getElementRectFn = dispatch(getElementRect);
-var isElementEnabledFn = dispatch(isElementEnabled);
-var getCurrentUrlFn = dispatch(getCurrentUrl);
-var findElementContentFn = dispatch(findElementContent);
-var findElementsContentFn = dispatch(findElementsContent);
-var isElementSelectedFn = dispatch(isElementSelected);
-var clearElementFn = dispatch(clearElement);
-var isElementDisplayedFn = dispatch(isElementDisplayed);
-var getElementValueOfCssPropertyFn = dispatch(getElementValueOfCssProperty);
-var switchToShadowRootFn = dispatch(switchToShadowRoot);
-var getCookiesFn = dispatch(getCookies);
-var singleTapFn = dispatch(singleTap);
-var takeScreenshotFn = dispatch(takeScreenshot);
-var performActionsFn = dispatch(performActions);
-var releaseActionsFn = dispatch(releaseActions);
-var actionChainFn = dispatch(actionChain);
-var multiActionFn = dispatch(multiAction);
-var addCookieFn = dispatch(addCookie);
-var deleteCookieFn = dispatch(deleteCookie);
-var deleteAllCookiesFn = dispatch(deleteAllCookies);
-var executeFn = dispatch(execute);
-var executeInSandboxFn = dispatch(executeInSandbox);
-var executeSimpleTestFn = dispatch(executeSimpleTest);
-var sendKeysToElementFn = dispatch(sendKeysToElement);
-
-/**
- * Start all message listeners
- */
-function startListeners() {
- addMessageListenerId("Marionette:newSession", newSession);
- addMessageListenerId("Marionette:execute", executeFn);
- addMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
- addMessageListenerId("Marionette:executeSimpleTest", executeSimpleTestFn);
- addMessageListenerId("Marionette:singleTap", singleTapFn);
- addMessageListenerId("Marionette:performActions", performActionsFn);
- addMessageListenerId("Marionette:releaseActions", releaseActionsFn);
- addMessageListenerId("Marionette:actionChain", actionChainFn);
- addMessageListenerId("Marionette:multiAction", multiActionFn);
- addMessageListenerId("Marionette:get", get);
- addMessageListenerId("Marionette:pollForReadyState", pollForReadyState);
- addMessageListenerId("Marionette:cancelRequest", cancelRequest);
- addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrlFn);
- addMessageListenerId("Marionette:getTitle", getTitleFn);
- addMessageListenerId("Marionette:getPageSource", getPageSourceFn);
- addMessageListenerId("Marionette:goBack", goBack);
- addMessageListenerId("Marionette:goForward", goForward);
- addMessageListenerId("Marionette:refresh", refresh);
- addMessageListenerId("Marionette:findElementContent", findElementContentFn);
- addMessageListenerId("Marionette:findElementsContent", findElementsContentFn);
- addMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
- addMessageListenerId("Marionette:clickElement", clickElementFn);
- addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
- addMessageListenerId("Marionette:getElementProperty", getElementPropertyFn);
- addMessageListenerId("Marionette:getElementText", getElementTextFn);
- addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
- addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
- addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
- addMessageListenerId("Marionette:getElementRect", getElementRectFn);
- addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
- addMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
- addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElementFn);
- addMessageListenerId("Marionette:clearElement", clearElementFn);
- addMessageListenerId("Marionette:switchToFrame", switchToFrame);
- addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
- addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
- addMessageListenerId("Marionette:deleteSession", deleteSession);
- addMessageListenerId("Marionette:sleepSession", sleepSession);
- addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
- addMessageListenerId("Marionette:setTestName", setTestName);
- addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
- addMessageListenerId("Marionette:addCookie", addCookieFn);
- addMessageListenerId("Marionette:getCookies", getCookiesFn);
- addMessageListenerId("Marionette:deleteAllCookies", deleteAllCookiesFn);
- addMessageListenerId("Marionette:deleteCookie", deleteCookieFn);
-}
-
-/**
- * Used during newSession and restart, called to set up the modal dialog listener in b2g
- */
-function waitForReady() {
- if (content.document.readyState == 'complete') {
- readyStateTimer.cancel();
- content.addEventListener("mozbrowsershowmodalprompt", modalHandler, false);
- content.addEventListener("unload", waitForReady, false);
- }
- else {
- readyStateTimer.initWithCallback(waitForReady, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- }
-}
-
-/**
- * Called when we start a new session. It registers the
- * current environment, and resets all values
- */
-function newSession(msg) {
- capabilities = session.Capabilities.fromJSON(msg.json);
- isB2G = capabilities.get("platformName") === "B2G";
- resetValues();
- if (isB2G) {
- readyStateTimer.initWithCallback(waitForReady, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- // We have to set correct mouse event source to MOZ_SOURCE_TOUCH
- // to offer a way for event listeners to differentiate
- // events being the result of a physical mouse action.
- // This is especially important for the touch event shim,
- // in order to prevent creating touch event for these fake mouse events.
- legacyactions.inputSource = Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH;
- }
-}
-
-/**
- * Puts the current session to sleep, so all listeners are removed except
- * for the 'restart' listener. This is used to keep the content listener
- * alive for reuse in B2G instead of reloading it each time.
- */
-function sleepSession(msg) {
- deleteSession();
- addMessageListener("Marionette:restart", restart);
-}
-
-/**
- * Restarts all our listeners after this listener was put to sleep
- */
-function restart(msg) {
- removeMessageListener("Marionette:restart", restart);
- if (isB2G) {
- readyStateTimer.initWithCallback(waitForReady, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- }
- registerSelf();
-}
-
-/**
- * Removes all listeners
- */
-function deleteSession(msg) {
- removeMessageListenerId("Marionette:newSession", newSession);
- removeMessageListenerId("Marionette:execute", executeFn);
- removeMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
- removeMessageListenerId("Marionette:executeSimpleTest", executeSimpleTestFn);
- removeMessageListenerId("Marionette:singleTap", singleTapFn);
- removeMessageListenerId("Marionette:performActions", performActionsFn);
- removeMessageListenerId("Marionette:releaseActions", releaseActionsFn);
- removeMessageListenerId("Marionette:actionChain", actionChainFn);
- removeMessageListenerId("Marionette:multiAction", multiActionFn);
- removeMessageListenerId("Marionette:get", get);
- removeMessageListenerId("Marionette:pollForReadyState", pollForReadyState);
- removeMessageListenerId("Marionette:cancelRequest", cancelRequest);
- removeMessageListenerId("Marionette:getTitle", getTitleFn);
- removeMessageListenerId("Marionette:getPageSource", getPageSourceFn);
- removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrlFn);
- removeMessageListenerId("Marionette:goBack", goBack);
- removeMessageListenerId("Marionette:goForward", goForward);
- removeMessageListenerId("Marionette:refresh", refresh);
- removeMessageListenerId("Marionette:findElementContent", findElementContentFn);
- removeMessageListenerId("Marionette:findElementsContent", findElementsContentFn);
- removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
- removeMessageListenerId("Marionette:clickElement", clickElementFn);
- removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn);
- removeMessageListenerId("Marionette:getElementProperty", getElementPropertyFn);
- removeMessageListenerId("Marionette:getElementText", getElementTextFn);
- removeMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
- removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
- removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
- removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
- removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
- removeMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
- removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElementFn);
- removeMessageListenerId("Marionette:clearElement", clearElementFn);
- removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
- removeMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
- removeMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
- removeMessageListenerId("Marionette:deleteSession", deleteSession);
- removeMessageListenerId("Marionette:sleepSession", sleepSession);
- removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
- removeMessageListenerId("Marionette:setTestName", setTestName);
- removeMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
- removeMessageListenerId("Marionette:addCookie", addCookieFn);
- removeMessageListenerId("Marionette:getCookies", getCookiesFn);
- removeMessageListenerId("Marionette:deleteAllCookies", deleteAllCookiesFn);
- removeMessageListenerId("Marionette:deleteCookie", deleteCookieFn);
- if (isB2G) {
- content.removeEventListener("mozbrowsershowmodalprompt", modalHandler, false);
- }
- seenEls.clear();
- // reset container frame to the top-most frame
- curContainer = { frame: content, shadowRoot: null };
- curContainer.frame.focus();
- legacyactions.touchIds = {};
- if (action.inputStateMap !== undefined) {
- action.inputStateMap.clear();
- }
- if (action.inputsToCancel !== undefined) {
- action.inputsToCancel.length = 0;
- }
-}
-
-/**
- * Send asynchronous reply to chrome.
- *
- * @param {UUID} uuid
- * Unique identifier of the request.
- * @param {AsyncContentSender.ResponseType} type
- * Type of response.
- * @param {?=} data
- * JSON serialisable object to accompany the message. Defaults to
- * an empty dictionary.
- */
-function sendToServer(uuid, data = undefined) {
- let channel = new proxy.AsyncMessageChannel(
- () => this,
- sendAsyncMessage.bind(this));
- channel.reply(uuid, data);
-}
-
-/**
- * Send asynchronous reply with value to chrome.
- *
- * @param {?} obj
- * JSON serialisable object of arbitrary type and complexity.
- * @param {UUID} uuid
- * Unique identifier of the request.
- */
-function sendResponse(obj, id) {
- sendToServer(id, obj);
-}
-
-/**
- * Send asynchronous reply to chrome.
- *
- * @param {UUID} uuid
- * Unique identifier of the request.
- */
-function sendOk(uuid) {
- sendToServer(uuid);
-}
-
-/**
- * Send asynchronous error reply to chrome.
- *
- * @param {Error} err
- * Error to notify chrome of.
- * @param {UUID} uuid
- * Unique identifier of the request.
- */
-function sendError(err, uuid) {
- sendToServer(uuid, err);
-}
-
-/**
- * Send log message to server
- */
-function sendLog(msg) {
- sendToServer("Marionette:log", {message: msg});
-}
-
-/**
- * Clear test values after completion of test
- */
-function resetValues() {
- sandboxes.clear();
- curContainer = {frame: content, shadowRoot: null};
- legacyactions.mouseEventsOnly = false;
- action.inputStateMap = new Map();
- action.inputsToCancel = [];
-}
-
-/**
- * Dump a logline to stdout. Prepends logline with a timestamp.
- */
-function dumpLog(logline) {
- dump(Date.now() + " Marionette: " + logline);
-}
-
-/**
- * Check if our context was interrupted
- */
-function wasInterrupted() {
- if (previousContainer) {
- let element = content.document.elementFromPoint((content.innerWidth/2), (content.innerHeight/2));
- if (element.id.indexOf("modal-dialog") == -1) {
- return true;
- }
- else {
- return false;
- }
- }
- return sendSyncMessage("MarionetteFrame:getInterruptedState", {})[0].value;
-}
-
-function checkForInterrupted() {
- if (wasInterrupted()) {
- if (previousContainer) {
- // if previousContainer is set, then we're in a single process environment
- curContainer = legacyactions.container = previousContainer;
- previousContainer = null;
- }
- else {
- //else we're in OOP environment, so we'll switch to the original OOP frame
- sendSyncMessage("Marionette:switchToModalOrigin");
- }
- sendSyncMessage("Marionette:switchedToFrame", { restorePrevious: true });
- }
-}
-
-function* execute(script, args, timeout, opts) {
- opts.timeout = timeout;
- script = importedScripts.for("content").concat(script);
-
- let sb = sandbox.createMutable(curContainer.frame);
- let wargs = element.fromJson(
- args, seenEls, curContainer.frame, curContainer.shadowRoot);
- let res = yield evaluate.sandbox(sb, script, wargs, opts);
-
- return element.toJson(res, seenEls);
-}
-
-function* executeInSandbox(script, args, timeout, opts) {
- opts.timeout = timeout;
- script = importedScripts.for("content").concat(script);
-
- let sb = sandboxes.get(opts.sandboxName, opts.newSandbox);
- if (opts.sandboxName) {
- sb = sandbox.augment(sb, {global: sb});
- sb = sandbox.augment(sb, new logging.Adapter(contentLog));
- }
-
- let wargs = element.fromJson(
- args, seenEls, curContainer.frame, curContainer.shadowRoot);
- let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
-
- let res = yield evaluatePromise;
- sendSyncMessage(
- "Marionette:shareData",
- {log: element.toJson(contentLog.get(), seenEls)});
- return element.toJson(res, seenEls);
-}
-
-function* executeSimpleTest(script, args, timeout, opts) {
- opts.timeout = timeout;
- let win = curContainer.frame;
- script = importedScripts.for("content").concat(script);
-
- let harness = new simpletest.Harness(
- win,
- "content",
- contentLog,
- timeout,
- marionetteTestName);
- let sb = sandbox.createSimpleTest(curContainer.frame, harness);
- // TODO(ato): Not sure this is needed:
- sb = sandbox.augment(sb, new logging.Adapter(contentLog));
-
- let wargs = element.fromJson(
- args, seenEls, curContainer.frame, curContainer.shadowRoot);
- let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
-
- let res = yield evaluatePromise;
- sendSyncMessage(
- "Marionette:shareData",
- {log: element.toJson(contentLog.get(), seenEls)});
- return element.toJson(res, seenEls);
-}
-
-/**
- * Sets the test name, used in logging messages.
- */
-function setTestName(msg) {
- marionetteTestName = msg.json.value;
- sendOk(msg.json.command_id);
-}
-
-/**
- * This function creates a touch event given a touch type and a touch
- */
-function emitTouchEvent(type, touch) {
- if (!wasInterrupted()) {
- let loggingInfo = "emitting Touch event of type " + type + " to element with id: " + touch.target.id + " and tag name: " + touch.target.tagName + " at coordinates (" + touch.clientX + ", " + touch.clientY + ") relative to the viewport";
- dumpLog(loggingInfo);
- var docShell = curContainer.frame.document.defaultView.
- QueryInterface(Components.interfaces.nsIInterfaceRequestor).
- getInterface(Components.interfaces.nsIWebNavigation).
- QueryInterface(Components.interfaces.nsIDocShell);
- if (docShell.asyncPanZoomEnabled && legacyactions.scrolling) {
- // if we're in APZ and we're scrolling, we must use sendNativeTouchPoint to dispatch our touchmove events
- let index = sendSyncMessage("MarionetteFrame:getCurrentFrameId");
- // only call emitTouchEventForIFrame if we're inside an iframe.
- if (index != null) {
- sendSyncMessage("Marionette:emitTouchEvent",
- { index: index, type: type, id: touch.identifier,
- clientX: touch.clientX, clientY: touch.clientY,
- screenX: touch.screenX, screenY: touch.screenY,
- radiusX: touch.radiusX, radiusY: touch.radiusY,
- rotation: touch.rotationAngle, force: touch.force });
- return;
- }
- }
- // we get here if we're not in asyncPacZoomEnabled land, or if we're the main process
- /*
- Disabled per bug 888303
- contentLog.log(loggingInfo, "TRACE");
- sendSyncMessage(
- "Marionette:shareData",
- {log: element.toJson(contentLog.get(), seenEls)});
- contentLog.clear();
- */
- let domWindowUtils = curContainer.frame.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
- domWindowUtils.sendTouchEvent(type, [touch.identifier], [touch.clientX], [touch.clientY], [touch.radiusX], [touch.radiusY], [touch.rotationAngle], [touch.force], 1, 0);
- }
-}
-
-/**
- * Function that perform a single tap
- */
-function singleTap(id, corx, cory) {
- let el = seenEls.get(id, curContainer);
- // after this block, the element will be scrolled into view
- let visible = element.isVisible(el, corx, cory);
- if (!visible) {
- throw new ElementNotInteractableError("Element is not currently visible and may not be manipulated");
- }
-
- let a11y = accessibility.get(capabilities.get("moz:accessibilityChecks"));
- return a11y.getAccessible(el, true).then(acc => {
- a11y.assertVisible(acc, el, visible);
- a11y.assertActionable(acc, el);
- if (!curContainer.frame.document.createTouch) {
- legacyactions.mouseEventsOnly = true;
- }
- let c = element.coordinates(el, corx, cory);
- if (!legacyactions.mouseEventsOnly) {
- let touchId = legacyactions.nextTouchId++;
- let touch = createATouch(el, c.x, c.y, touchId);
- emitTouchEvent('touchstart', touch);
- emitTouchEvent('touchend', touch);
- }
- legacyactions.mouseTap(el.ownerDocument, c.x, c.y);
- });
-}
-
-/**
- * Function to create a touch based on the element
- * corx and cory are relative to the viewport, id is the touchId
- */
-function createATouch(el, corx, cory, touchId) {
- let doc = el.ownerDocument;
- let win = doc.defaultView;
- let [clientX, clientY, pageX, pageY, screenX, screenY] =
- legacyactions.getCoordinateInfo(el, corx, cory);
- let atouch = doc.createTouch(win, el, touchId, pageX, pageY, screenX, screenY, clientX, clientY);
- return atouch;
-}
-
-/**
- * Perform a series of grouped actions at the specified points in time.
- *
- * @param {obj} msg
- * Object with an |actions| attribute that is an Array of objects
- * each of which represents an action sequence.
- */
-function* performActions(msg) {
- let chain = action.Chain.fromJson(msg.actions);
- yield action.dispatch(chain, seenEls, curContainer);
-}
-
-/**
- * The Release Actions command is used to release all the keys and pointer
- * buttons that are currently depressed. This causes events to be fired as if
- * the state was released by an explicit series of actions. It also clears all
- * the internal state of the virtual devices.
- */
-function* releaseActions() {
- yield action.dispatchTickActions(action.inputsToCancel.reverse(), 0, seenEls, curContainer);
- action.inputsToCancel.length = 0;
- action.inputStateMap.clear();
-}
-
-/**
- * Start action chain on one finger.
- */
-function actionChain(chain, touchId) {
- let touchProvider = {};
- touchProvider.createATouch = createATouch;
- touchProvider.emitTouchEvent = emitTouchEvent;
-
- return legacyactions.dispatchActions(
- chain,
- touchId,
- curContainer,
- seenEls,
- touchProvider);
-}
-
-/**
- * Function to emit touch events which allow multi touch on the screen
- * @param type represents the type of event, touch represents the current touch,touches are all pending touches
- */
-function emitMultiEvents(type, touch, touches) {
- let target = touch.target;
- let doc = target.ownerDocument;
- let win = doc.defaultView;
- // touches that are in the same document
- let documentTouches = doc.createTouchList(touches.filter(function (t) {
- return ((t.target.ownerDocument === doc) && (type != 'touchcancel'));
- }));
- // touches on the same target
- let targetTouches = doc.createTouchList(touches.filter(function (t) {
- return ((t.target === target) && ((type != 'touchcancel') || (type != 'touchend')));
- }));
- // Create changed touches
- let changedTouches = doc.createTouchList(touch);
- // Create the event object
- let event = doc.createEvent('TouchEvent');
- event.initTouchEvent(type,
- true,
- true,
- win,
- 0,
- false, false, false, false,
- documentTouches,
- targetTouches,
- changedTouches);
- target.dispatchEvent(event);
-}
-
-/**
- * Function to dispatch one set of actions
- * @param touches represents all pending touches, batchIndex represents the batch we are dispatching right now
- */
-function setDispatch(batches, touches, batchIndex=0) {
- // check if all the sets have been fired
- if (batchIndex >= batches.length) {
- multiLast = {};
- return;
- }
-
- // a set of actions need to be done
- let batch = batches[batchIndex];
- // each action for some finger
- let pack;
- // the touch id for the finger (pack)
- let touchId;
- // command for the finger
- let command;
- // touch that will be created for the finger
- let el;
- let corx;
- let cory;
- let touch;
- let lastTouch;
- let touchIndex;
- let waitTime = 0;
- let maxTime = 0;
- let c;
-
- // loop through the batch
- batchIndex++;
- for (let i = 0; i < batch.length; i++) {
- pack = batch[i];
- touchId = pack[0];
- command = pack[1];
-
- switch (command) {
- case "press":
- el = seenEls.get(pack[2], curContainer);
- c = element.coordinates(el, pack[3], pack[4]);
- touch = createATouch(el, c.x, c.y, touchId);
- multiLast[touchId] = touch;
- touches.push(touch);
- emitMultiEvents("touchstart", touch, touches);
- break;
-
- case "release":
- touch = multiLast[touchId];
- // the index of the previous touch for the finger may change in the touches array
- touchIndex = touches.indexOf(touch);
- touches.splice(touchIndex, 1);
- emitMultiEvents("touchend", touch, touches);
- break;
-
- case "move":
- el = seenEls.get(pack[2], curContainer);
- c = element.coordinates(el);
- touch = createATouch(multiLast[touchId].target, c.x, c.y, touchId);
- touchIndex = touches.indexOf(lastTouch);
- touches[touchIndex] = touch;
- multiLast[touchId] = touch;
- emitMultiEvents("touchmove", touch, touches);
- break;
-
- case "moveByOffset":
- el = multiLast[touchId].target;
- lastTouch = multiLast[touchId];
- touchIndex = touches.indexOf(lastTouch);
- let doc = el.ownerDocument;
- let win = doc.defaultView;
- // since x and y are relative to the last touch, therefore, it's relative to the position of the last touch
- let clientX = lastTouch.clientX + pack[2],
- clientY = lastTouch.clientY + pack[3];
- let pageX = clientX + win.pageXOffset,
- pageY = clientY + win.pageYOffset;
- let screenX = clientX + win.mozInnerScreenX,
- screenY = clientY + win.mozInnerScreenY;
- touch = doc.createTouch(win, el, touchId, pageX, pageY, screenX, screenY, clientX, clientY);
- touches[touchIndex] = touch;
- multiLast[touchId] = touch;
- emitMultiEvents("touchmove", touch, touches);
- break;
-
- case "wait":
- if (typeof pack[2] != "undefined") {
- waitTime = pack[2] * 1000;
- if (waitTime > maxTime) {
- maxTime = waitTime;
- }
- }
- break;
- }
- }
-
- if (maxTime != 0) {
- checkTimer.initWithCallback(function() {
- setDispatch(batches, touches, batchIndex);
- }, maxTime, Ci.nsITimer.TYPE_ONE_SHOT);
- } else {
- setDispatch(batches, touches, batchIndex);
- }
-}
-
-/**
- * Start multi-action.
- *
- * @param {Number} maxLen
- * Longest action chain for one finger.
- */
-function multiAction(args, maxLen) {
- // unwrap the original nested array
- let commandArray = element.fromJson(
- args, seenEls, curContainer.frame, curContainer.shadowRoot);
- let concurrentEvent = [];
- let temp;
- for (let i = 0; i < maxLen; i++) {
- let row = [];
- for (let j = 0; j < commandArray.length; j++) {
- if (typeof commandArray[j][i] != "undefined") {
- // add finger id to the front of each action, i.e. [finger_id, action, element]
- temp = commandArray[j][i];
- temp.unshift(j);
- row.push(temp);
- }
- }
- concurrentEvent.push(row);
- }
-
- // now concurrent event is made of sets where each set contain a list of actions that need to be fired.
- // note: each action belongs to a different finger
- // pendingTouches keeps track of current touches that's on the screen
- let pendingTouches = [];
- setDispatch(concurrentEvent, pendingTouches);
-}
-
-/**
- * This implements the latter part of a get request (for the case we need to resume one
- * when a remoteness update happens in the middle of a navigate request). This is most of
- * of the work of a navigate request, but doesn't assume DOMContentLoaded is yet to fire.
- *
- * @param {function=} cleanupCallback
- * Callback to execute when registered event handlers or observer notifications
- * have to be cleaned-up.
- * @param {number} command_id
- * ID of the currently handled message between the driver and listener.
- * @param {string=} lastSeenURL
- * Last URL as seen before the navigation request got triggered.
- * @param {number} pageTimeout
- * Timeout in seconds the method has to wait for the page being finished loading.
- * @param {number} startTime
- * Unix timestap when the navitation request got triggred.
- */
-function pollForReadyState(msg) {
- let {cleanupCallback, command_id, lastSeenURL, pageTimeout, startTime} = msg.json;
-
- if (typeof startTime == "undefined") {
- startTime = new Date().getTime();
- }
-
- if (typeof cleanupCallback == "undefined") {
- cleanupCallback = () => {};
- }
-
- let endTime = startTime + pageTimeout;
-
- let checkLoad = function() {
- navTimer.cancel();
-
- let doc = curContainer.frame.document;
-
- if (pageTimeout === null || new Date().getTime() <= endTime) {
- // Under some conditions (eg. for error pages) the pagehide event is fired
- // even with a readyState complete for the formerly loaded page.
- // To prevent race conditition for goBack and goForward we have to wait
- // until the last seen page has been fully unloaded.
- // TODO: Bug 1333458 has to improve this.
- if (!doc.location || lastSeenURL && doc.location.href === lastSeenURL) {
- navTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
-
- // document fully loaded
- } else if (doc.readyState === "complete") {
- cleanupCallback();
- sendOk(command_id);
-
- // document with an insecure cert
- } else if (doc.readyState === "interactive" &&
- doc.baseURI.startsWith("about:certerror")) {
- cleanupCallback();
- sendError(new InsecureCertificateError(), command_id);
-
- // we have reached an error url without requesting it
- } else if (doc.readyState === "interactive" &&
- /about:.+(error)\?/.exec(doc.baseURI)) {
- cleanupCallback();
- sendError(new UnknownError("Reached error page: " + doc.baseURI), command_id);
-
- // return early for about: urls
- } else if (doc.readyState === "interactive" && doc.baseURI.startsWith("about:")) {
- cleanupCallback();
- sendOk(command_id);
-
- // document not fully loaded
- } else {
- navTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- }
-
- } else {
- cleanupCallback();
- sendError(new TimeoutError("Error loading page, timed out (checkLoad)"), command_id);
- }
- };
-
- checkLoad();
-}
-
-/**
- * Navigate to the given URL. The operation will be performed on the
- * current browsing context, which means it handles the case where we
- * navigate within an iframe. All other navigation is handled by the
- * driver (in chrome space).
- */
-function get(msg) {
- let {pageTimeout, url, command_id} = msg.json;
-
- let startTime = new Date().getTime();
-
- // We need to move to the top frame before navigating
- sendSyncMessage("Marionette:switchedToFrame", {frameValue: null});
- curContainer.frame = content;
-
- let docShell = curContainer.frame
- .document
- .defaultView
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell);
- let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebProgress);
- let sawLoad = false;
-
- let requestedURL;
- let loadEventExpected = false;
- try {
- requestedURL = new URL(url).toString();
- let curURL = curContainer.frame.location;
- loadEventExpected = navigate.isLoadEventExpected(curURL, requestedURL);
- } catch (e) {
- sendError(new InvalidArgumentError("Malformed URL: " + e.message), command_id);
- return;
- }
-
- // It's possible that a site we're being sent to will end up redirecting
- // us before we end up on a page that fires DOMContentLoaded. We can ensure
- // This loadListener ensures that we don't send a success signal back to
- // the caller until we've seen the load of the requested URL attempted
- // on this frame.
- let loadListener = {
- QueryInterface: XPCOMUtils.generateQI(
- [Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
-
- onStateChange(webProgress, request, state, status) {
- if (!(request instanceof Ci.nsIChannel)) {
- return;
- }
-
- const isDocument = state & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
- const loadedURL = request.URI.spec;
-
- // We have to look at the originalURL because of about: pages,
- // the loadedURL is what the about: page resolves to, and is
- // not the one that was requested.
- const originalURL = request.originalURI.spec;
- const isRequestedURL = loadedURL == requestedURL ||
- originalURL == requestedURL;
-
- if (!isDocument || !isRequestedURL) {
- return;
- }
-
- // We started loading the requested document. This document
- // might not be the one that ends up firing DOMContentLoaded
- // (if it, for example, redirects), but because we've started
- // loading this URL, we know that any future DOMContentLoaded's
- // are fair game to tell the Marionette client about.
- if (state & Ci.nsIWebProgressListener.STATE_START) {
- sawLoad = true;
- }
-
- // This indicates network stop or last request stop outside of
- // loading the document. We hit this when DOMContentLoaded is
- // not triggered, which is the case for image documents.
- else if (state & Ci.nsIWebProgressListener.STATE_STOP &&
- content.document instanceof content.ImageDocument) {
- pollForReadyState({json: {
- command_id: command_id,
- pageTimeout: pageTimeout,
- startTime: startTime,
- cleanupCallback: () => {
- webProgress.removeProgressListener(loadListener);
- removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- }
- }});
- }
- },
-
- onLocationChange() {},
- onProgressChange() {},
- onStatusChange() {},
- onSecurityChange() {},
- };
-
- webProgress.addProgressListener(
- loadListener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
-
- // Prevent DOMContentLoaded events from frames from invoking this
- // code, unless the event is coming from the frame associated with
- // the current window (i.e. someone has used switch_to_frame).
- onDOMContentLoaded = function onDOMContentLoaded(event) {
- let frameEl = event.originalTarget.defaultView.frameElement;
- let correctFrame = !frameEl || frameEl == curContainer.frame.frameElement;
-
- // If the page we're at fired DOMContentLoaded and appears
- // to be the one we asked to load, then we definitely
- // saw the load occur. We need this because for error
- // pages, like about:neterror for unsupported protocols,
- // we don't end up opening a channel that our
- // WebProgressListener can monitor.
- if (curContainer.frame.location == requestedURL) {
- sawLoad = true;
- }
-
- // We also need to make sure that if the requested URL is not about:blank
- // the DOMContentLoaded we saw isn't for the initial about:blank of a newly
- // created docShell.
- let loadedRequestedURI = (requestedURL == "about:blank") ||
- docShell.hasLoadedNonBlankURI;
-
- if (correctFrame && sawLoad && loadedRequestedURI) {
- pollForReadyState({json: {
- command_id: command_id,
- pageTimeout: pageTimeout,
- startTime: startTime,
- cleanupCallback: () => {
- webProgress.removeProgressListener(loadListener);
- removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- }
- }});
- }
- };
-
- if (typeof pageTimeout != "undefined") {
- let onTimeout = function() {
- if (loadEventExpected) {
- removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- }
- webProgress.removeProgressListener(loadListener);
- sendError(new TimeoutError("Error loading page, timed out (onDOMContentLoaded)"), command_id);
- }
- navTimer.initWithCallback(onTimeout, pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
- }
-
- if (loadEventExpected) {
- addEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- }
- curContainer.frame.location = requestedURL;
- if (!loadEventExpected) {
- sendOk(command_id);
- }
-}
-
-/**
- * Cancel the polling and remove the event listener associated with a
- * current navigation request in case we're interupted by an onbeforeunload
- * handler and navigation doesn't complete.
- */
-function cancelRequest() {
- navTimer.cancel();
- if (onDOMContentLoaded) {
- removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
- }
-}
-
-/**
- * Get URL of the top-level browsing context.
- */
-function getCurrentUrl() {
- return content.location.href;
-}
-
-/**
- * Get the title of the current browsing context.
- */
-function getTitle() {
- return curContainer.frame.top.document.title;
-}
-
-/**
- * Get source of the current browsing context's DOM.
- */
-function getPageSource() {
- return curContainer.frame.document.documentElement.outerHTML;
-}
-
-/**
- * Wait for the current page to be unloaded after a navigation got triggered.
- *
- * @param {function} trigger
- * Callback to execute which triggers a page navigation.
- * @param {function} doneCallback
- * Callback to execute when the current page has been unloaded.
- *
- * It receives a dictionary with the following items as argument:
- * loading - Flag if a page load will follow.
- * lastSeenURL - Last seen URL before the navigation request.
- * startTime - Time when the navigation request has been triggered.
- */
-function waitForPageUnloaded(trigger, doneCallback) {
- let currentURL = curContainer.frame.location.href;
- let start = new Date().getTime();
-
- function handleEvent(event) {
- // In case of a remoteness change it can happen that we are no longer able
- // to access the document's location. In those cases ignore the event,
- // but keep the code waiting, and assume in the driver that waiting for the
- // page load is necessary. Bug 1333458 should improve things.
- if (typeof event.originalTarget.location == "undefined") {
- return;
- }
-
- switch (event.type) {
- case "hashchange":
- removeEventListener("hashchange", handleEvent);
- removeEventListener("pagehide", handleEvent);
- removeEventListener("unload", handleEvent);
-
- doneCallback({loading: false, lastSeenURL: currentURL});
- break;
-
- case "pagehide":
- case "unload":
- if (event.originalTarget === curContainer.frame.document) {
- removeEventListener("hashchange", handleEvent);
- removeEventListener("pagehide", handleEvent);
- removeEventListener("unload", handleEvent);
-
- doneCallback({loading: true, lastSeenURL: currentURL, startTime: start});
- }
- break;
- }
- }
-
- addEventListener("hashchange", handleEvent, false);
- addEventListener("pagehide", handleEvent, false);
- addEventListener("unload", handleEvent, false);
-
- trigger();
-}
-
-/**
- * Cause the browser to traverse one step backward in the joint history
- * of the current browsing context.
- *
- * @param {number} command_id
- * ID of the currently handled message between the driver and listener.
- * @param {number} pageTimeout
- * Timeout in milliseconds the method has to wait for the page being finished loading.
- */
-function goBack(msg) {
- let {command_id, pageTimeout} = msg.json;
-
- waitForPageUnloaded(() => {
- curContainer.frame.history.back();
- }, pageLoadStatus => {
- if (pageLoadStatus.loading) {
- pollForReadyState({json: {
- command_id: command_id,
- lastSeenURL: pageLoadStatus.lastSeenURL,
- pageTimeout: pageTimeout,
- startTime: pageLoadStatus.startTime,
- }});
- } else {
- sendOk(command_id);
- }
- });
-}
-
-/**
- * Cause the browser to traverse one step forward in the joint history
- * of the current browsing context.
- *
- * @param {number} command_id
- * ID of the currently handled message between the driver and listener.
- * @param {number} pageTimeout
- * Timeout in milliseconds the method has to wait for the page being finished loading.
- */
-function goForward(msg) {
- let {command_id, pageTimeout} = msg.json;
-
- waitForPageUnloaded(() => {
- curContainer.frame.history.forward();
- }, pageLoadStatus => {
- if (pageLoadStatus.loading) {
- pollForReadyState({json: {
- command_id: command_id,
- lastSeenURL: pageLoadStatus.lastSeenURL,
- pageTimeout: pageTimeout,
- startTime: pageLoadStatus.startTime,
- }});
- } else {
- sendOk(command_id);
- }
- });
-}
-
-/**
- * Refresh the page
- */
-function refresh(msg) {
- let command_id = msg.json.command_id;
- curContainer.frame.location.reload(true);
- let listen = function() {
- removeEventListener("DOMContentLoaded", listen, false);
- sendOk(command_id);
- };
- addEventListener("DOMContentLoaded", listen, false);
-}
-
-/**
- * Find an element in the current browsing context's document using the
- * given search strategy.
- */
-function* findElementContent(strategy, selector, opts = {}) {
- if (!SUPPORTED_STRATEGIES.has(strategy)) {
- throw new InvalidSelectorError("Strategy not supported: " + strategy);
- }
-
- opts.all = false;
- if (opts.startNode) {
- opts.startNode = seenEls.get(opts.startNode, curContainer);
- }
-
- let el = yield element.find(curContainer, strategy, selector, opts);
- let elRef = seenEls.add(el);
- let webEl = element.makeWebElement(elRef);
- return webEl;
-}
-
-/**
- * Find elements in the current browsing context's document using the
- * given search strategy.
- */
-function* findElementsContent(strategy, selector, opts = {}) {
- if (!SUPPORTED_STRATEGIES.has(strategy)) {
- throw new InvalidSelectorError("Strategy not supported: " + strategy);
- }
-
- opts.all = true;
- if (opts.startNode) {
- opts.startNode = seenEls.get(opts.startNode, curContainer);
- }
-
- let els = yield element.find(curContainer, strategy, selector, opts);
- let elRefs = seenEls.addAll(els);
- let webEls = elRefs.map(element.makeWebElement);
- return webEls;
-}
-
-/** Find and return the active element on the page. */
-function getActiveElement() {
- let el = curContainer.frame.document.activeElement;
- return element.toJson(el, seenEls);
-}
-
-/**
- * Send click event to element.
- *
- * @param {WebElement} id
- * Reference to the web element to click.
- */
-function clickElement(id) {
- let el = seenEls.get(id, curContainer);
- return interaction.clickElement(
- el,
- capabilities.get("moz:accessibilityChecks"),
- capabilities.get("specificationLevel") >= 1);
-}
-
-function getElementAttribute(id, name) {
- let el = seenEls.get(id, curContainer);
- if (element.isBooleanAttribute(el, name)) {
- if (el.hasAttribute(name)) {
- return "true";
- } else {
- return null;
- }
- } else {
- return el.getAttribute(name);
- }
-}
-
-function getElementProperty(id, name) {
- let el = seenEls.get(id, curContainer);
- return typeof el[name] != "undefined" ? el[name] : null;
-}
-
-/**
- * Get the text of this element. This includes text from child elements.
- *
- * @param {WebElement} id
- * Reference to web element.
- *
- * @return {string}
- * Text of element.
- */
-function getElementText(id) {
- let el = seenEls.get(id, curContainer);
- return atom.getElementText(el, curContainer.frame);
-}
-
-/**
- * Get the tag name of an element.
- *
- * @param {WebElement} id
- * Reference to web element.
- *
- * @return {string}
- * Tag name of element.
- */
-function getElementTagName(id) {
- let el = seenEls.get(id, curContainer);
- return el.tagName.toLowerCase();
-}
-
-/**
- * Determine the element displayedness of the given web element.
- *
- * Also performs additional accessibility checks if enabled by session
- * capability.
- */
-function isElementDisplayed(id) {
- let el = seenEls.get(id, curContainer);
- return interaction.isElementDisplayed(
- el, capabilities.get("moz:accessibilityChecks"));
-}
-
-/**
- * Retrieves the computed value of the given CSS property of the given
- * web element.
- *
- * @param {String} id
- * Web element reference.
- * @param {String} prop
- * The CSS property to get.
- *
- * @return {String}
- * Effective value of the requested CSS property.
- */
-function getElementValueOfCssProperty(id, prop) {
- let el = seenEls.get(id, curContainer);
- let st = curContainer.frame.document.defaultView.getComputedStyle(el, null);
- return st.getPropertyValue(prop);
-}
-
-/**
- * Get the position and dimensions of the element.
- *
- * @param {WebElement} id
- * Reference to web element.
- *
- * @return {Object.<string, number>}
- * The x, y, width, and height properties of the element.
- */
-function getElementRect(id) {
- let el = seenEls.get(id, curContainer);
- let clientRect = el.getBoundingClientRect();
- return {
- x: clientRect.x + curContainer.frame.pageXOffset,
- y: clientRect.y + curContainer.frame.pageYOffset,
- width: clientRect.width,
- height: clientRect.height
- };
-}
-
-/**
- * Check if element is enabled.
- *
- * @param {WebElement} id
- * Reference to web element.
- *
- * @return {boolean}
- * True if enabled, false otherwise.
- */
-function isElementEnabled(id) {
- let el = seenEls.get(id, curContainer);
- return interaction.isElementEnabled(
- el, capabilities.get("moz:accessibilityChecks"));
-}
-
-/**
- * Determines if the referenced element is selected or not.
- *
- * This operation only makes sense on input elements of the Checkbox-
- * and Radio Button states, or option elements.
- */
-function isElementSelected(id) {
- let el = seenEls.get(id, curContainer);
- return interaction.isElementSelected(
- el, capabilities.get("moz:accessibilityChecks"));
-}
-
-function* sendKeysToElement(id, val) {
- let el = seenEls.get(id, curContainer);
- if (el.type == "file") {
- let path = val.join("");
- yield interaction.uploadFile(el, path);
- } else if ((el.type == "date" || el.type == "time") &&
- Preferences.get("dom.forms.datetime")) {
- yield interaction.setFormControlValue(el, val);
- } else {
- yield interaction.sendKeysToElement(
- el, val, false, capabilities.get("moz:accessibilityChecks"));
- }
-}
-
-/**
- * Clear the text of an element.
- */
-function clearElement(id) {
- try {
- let el = seenEls.get(id, curContainer);
- if (el.type == "file") {
- el.value = null;
- } else {
- atom.clearElement(el, curContainer.frame);
- }
- } catch (e) {
- // Bug 964738: Newer atoms contain status codes which makes wrapping
- // this in an error prototype that has a status property unnecessary
- if (e.name == "InvalidElementStateError") {
- throw new InvalidElementStateError(e.message);
- } else {
- throw e;
- }
- }
-}
-
-/**
- * Switch the current context to the specified host's Shadow DOM.
- * @param {WebElement} id
- * Reference to web element.
- */
-function switchToShadowRoot(id) {
- if (!id) {
- // If no host element is passed, attempt to find a parent shadow root or, if
- // none found, unset the current shadow root
- if (curContainer.shadowRoot) {
- let parent;
- try {
- parent = curContainer.shadowRoot.host;
- } catch (e) {
- // There is a chance that host element is dead and we are trying to
- // access a dead object.
- curContainer.shadowRoot = null;
- return;
- }
- while (parent && !(parent instanceof curContainer.frame.ShadowRoot)) {
- parent = parent.parentNode;
- }
- curContainer.shadowRoot = parent;
- }
- return;
- }
-
- let foundShadowRoot;
- let hostEl = seenEls.get(id, curContainer);
- foundShadowRoot = hostEl.shadowRoot;
- if (!foundShadowRoot) {
- throw new NoSuchElementError('Unable to locate shadow root: ' + id);
- }
- curContainer.shadowRoot = foundShadowRoot;
-}
-
-/**
- * Switch to the parent frame of the current Frame. If the frame is the top most
- * is the current frame then no action will happen.
- */
- function switchToParentFrame(msg) {
- let command_id = msg.json.command_id;
- curContainer.frame = curContainer.frame.parent;
- let parentElement = seenEls.add(curContainer.frame);
-
- sendSyncMessage(
- "Marionette:switchedToFrame", {frameValue: parentElement});
-
- sendOk(msg.json.command_id);
- }
-
-/**
- * Switch to frame given either the server-assigned element id,
- * its index in window.frames, or the iframe's name or id.
- */
-function switchToFrame(msg) {
- let command_id = msg.json.command_id;
- function checkLoad() {
- let errorRegex = /about:.+(error)|(blocked)\?/;
- if (curContainer.frame.document.readyState == "complete") {
- sendOk(command_id);
- return;
- } else if (curContainer.frame.document.readyState == "interactive" &&
- errorRegex.exec(curContainer.frame.document.baseURI)) {
- sendError(new UnknownError("Error loading page"), command_id);
- return;
- }
- checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- }
- let foundFrame = null;
- let frames = [];
- let parWindow = null;
- // Check of the curContainer.frame reference is dead
- try {
- frames = curContainer.frame.frames;
- //Until Bug 761935 lands, we won't have multiple nested OOP iframes. We will only have one.
- //parWindow will refer to the iframe above the nested OOP frame.
- parWindow = curContainer.frame.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
- } catch (e) {
- // We probably have a dead compartment so accessing it is going to make Firefox
- // very upset. Let's now try redirect everything to the top frame even if the
- // user has given us a frame since search doesnt look up.
- msg.json.id = null;
- msg.json.element = null;
- }
-
- if ((msg.json.id === null || msg.json.id === undefined) && (msg.json.element == null)) {
- // returning to root frame
- sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
-
- curContainer.frame = content;
- if(msg.json.focus == true) {
- curContainer.frame.focus();
- }
-
- checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
-
- let id = msg.json.element;
- if (seenEls.has(id)) {
- let wantedFrame;
- try {
- wantedFrame = seenEls.get(id, curContainer);
- } catch (e) {
- sendError(e, command_id);
- }
-
- if (frames.length > 0) {
- for (let i = 0; i < frames.length; i++) {
- // use XPCNativeWrapper to compare elements; see bug 834266
- if (XPCNativeWrapper(frames[i].frameElement) == XPCNativeWrapper(wantedFrame)) {
- curContainer.frame = frames[i].frameElement;
- foundFrame = i;
- }
- }
- }
-
- if (foundFrame === null) {
- // Either the frame has been removed or we have a OOP frame
- // so lets just get all the iframes and do a quick loop before
- // throwing in the towel
- let iframes = curContainer.frame.document.getElementsByTagName("iframe");
- for (var i = 0; i < iframes.length; i++) {
- if (XPCNativeWrapper(iframes[i]) == XPCNativeWrapper(wantedFrame)) {
- curContainer.frame = iframes[i];
- foundFrame = i;
- }
- }
- }
- }
-
- if (foundFrame === null) {
- if (typeof(msg.json.id) === 'number') {
- try {
- foundFrame = frames[msg.json.id].frameElement;
- if (foundFrame !== null) {
- curContainer.frame = foundFrame;
- foundFrame = seenEls.add(curContainer.frame);
- }
- else {
- // If foundFrame is null at this point then we have the top level browsing
- // context so should treat it accordingly.
- sendSyncMessage("Marionette:switchedToFrame", { frameValue: null});
- curContainer.frame = content;
- if(msg.json.focus == true) {
- curContainer.frame.focus();
- }
-
- checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- return;
- }
- } catch (e) {
- // Since window.frames does not return OOP frames it will throw
- // and we land up here. Let's not give up and check if there are
- // iframes and switch to the indexed frame there
- let iframes = curContainer.frame.document.getElementsByTagName("iframe");
- if (msg.json.id >= 0 && msg.json.id < iframes.length) {
- curContainer.frame = iframes[msg.json.id];
- foundFrame = msg.json.id;
- }
- }
- }
- }
-
- if (foundFrame === null) {
- sendError(new NoSuchFrameError("Unable to locate frame: " + (msg.json.id || msg.json.element)), command_id);
- return true;
- }
-
- // send a synchronous message to let the server update the currently active
- // frame element (for getActiveFrame)
- let frameValue = element.toJson(
- curContainer.frame.wrappedJSObject, seenEls)[element.Key];
- sendSyncMessage("Marionette:switchedToFrame", {frameValue: frameValue});
-
- let rv = null;
- if (curContainer.frame.contentWindow === null) {
- // The frame we want to switch to is a remote/OOP frame;
- // notify our parent to handle the switch
- curContainer.frame = content;
- rv = {win: parWindow, frame: foundFrame};
- } else {
- curContainer.frame = curContainer.frame.contentWindow;
- if (msg.json.focus) {
- curContainer.frame.focus();
- }
- checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
- }
-
- sendResponse(rv, command_id);
-}
-
-function addCookie(cookie) {
- cookies.add(cookie.name, cookie.value, cookie);
-}
-
-/**
- * Get all cookies for the current domain.
- */
-function getCookies() {
- let rv = [];
-
- for (let cookie of cookies) {
- let expires = cookie.expires;
- // session cookie, don't return an expiry
- if (expires == 0) {
- expires = null;
- // date before epoch time, cap to epoch
- } else if (expires == 1) {
- expires = 0;
- }
- rv.push({
- 'name': cookie.name,
- 'value': cookie.value,
- 'path': cookie.path,
- 'domain': cookie.host,
- 'secure': cookie.isSecure,
- 'httpOnly': cookie.httpOnly,
- 'expiry': expires
- });
- }
-
- return rv;
-}
-
-/**
- * Delete a cookie by name.
- */
-function deleteCookie(name) {
- cookies.delete(name);
-}
-
-/**
- * Delete all the visibile cookies on a page.
- */
-function deleteAllCookies() {
- for (let cookie of cookies) {
- cookies.delete(cookie);
- }
-}
-
-function getAppCacheStatus(msg) {
- sendResponse(
- curContainer.frame.applicationCache.status, msg.json.command_id);
-}
-
-/**
- * Perform a screen capture in content context.
- *
- * Accepted values for |opts|:
- *
- * @param {UUID=} id
- * Optional web element reference of an element to take a screenshot
- * of.
- * @param {boolean=} full
- * True to take a screenshot of the entire document element. Is not
- * considered if {@code id} is not defined. Defaults to true.
- * @param {Array.<UUID>=} highlights
- * Draw a border around the elements found by their web element
- * references.
- * @param {boolean=} scroll
- * When |id| is given, scroll it into view before taking the
- * screenshot. Defaults to true.
- *
- * @param {capture.Format} format
- * Format to return the screenshot in.
- * @param {Object.<string, ?>} opts
- * Options.
- *
- * @return {string}
- * Base64 encoded string or a SHA-256 hash of the screenshot.
- */
-function takeScreenshot(format, opts = {}) {
- let id = opts.id;
- let full = !!opts.full;
- let highlights = opts.highlights || [];
- let scroll = !!opts.scroll;
-
- let highlightEls = highlights.map(ref => seenEls.get(ref, curContainer));
-
- let canvas;
-
- // viewport
- if (!id && !full) {
- canvas = capture.viewport(curContainer.frame, highlightEls);
-
- // element or full document element
- } else {
- let el;
- if (id) {
- el = seenEls.get(id, curContainer);
- if (scroll) {
- element.scrollIntoView(el);
- }
- } else {
- el = curContainer.frame.document.documentElement;
- }
-
- canvas = capture.element(el, highlightEls);
- }
-
- switch (format) {
- case capture.Format.Base64:
- return capture.toBase64(canvas);
-
- case capture.Format.Hash:
- return capture.toHash(canvas);
-
- default:
- throw new TypeError("Unknown screenshot format: " + format);
- }
-}
-
-// Call register self when we get loaded
-registerSelf();
diff --git a/testing/marionette/logging.js b/testing/marionette/logging.js
deleted file mode 100644
index d77adfb0cb..0000000000
--- a/testing/marionette/logging.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["logging"];
-
-this.logging = {};
-
-/** Simple logger that is used in Simple Test harness tests. */
-logging.ContentLogger = class {
- constructor() {
- this.logs_ = [];
- }
-
- /**
- * Append a log entry.
- *
- * @param {string} message
- * Log entry message.
- * @param {string=} level
- * Severity of entry. Defaults to "INFO".
- */
- log(message, level = "INFO") {
- let now = (new Date()).toString();
- this.logs_.push([level, message, now]);
- }
-
- /**
- * Append array of log entries.
- *
- * @param {Array.<Array<string, string, string>>} messages
- * List of log entries, that are of the form severity, message,
- * and date.
- */
- addAll(messages) {
- for (let message of messages) {
- this.logs_.push(message);
- }
- }
-
- /**
- * Gets current log entries and clears the cache.
- *
- * @return {Array.<Array<string, string, string>>}
- * Log entries of the form severity, message, and date.
- */
- get() {
- let logs = this.logs_;
- this.logs_ = [];
- return logs;
- }
-};
-
-/**
- * Adapts an instance of ContentLogger for use in a sandbox. Is consumed
- * by sandbox.augment.
- */
-logging.Adapter = class {
- constructor(logger = null) {
- this.logger = logger;
- }
-
- get exports() {
- return new Map([["log", this.log.bind(this)]]);
- }
-
- log(message, level = "INFO") {
- dump(`MARIONETTE LOG: ${level}: ${message}\n`);
- if (this.logger) {
- this.logger.log(message, level);
- }
- }
-};
diff --git a/testing/marionette/mach_commands.py b/testing/marionette/mach_commands.py
deleted file mode 100644
index 6461bc16d1..0000000000
--- a/testing/marionette/mach_commands.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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 __future__ import absolute_import, unicode_literals
-
-import os
-import sys
-import argparse
-
-from mozbuild.base import (
- MachCommandBase,
- MachCommandConditions as conditions,
-)
-
-from mach.decorators import (
- CommandArgument,
- CommandProvider,
- Command,
-)
-
-def is_firefox_or_android(cls):
- """Must have Firefox build or Android build."""
- return conditions.is_firefox(cls) or conditions.is_android(cls)
-
-def setup_marionette_argument_parser():
- from marionette_harness.runtests import MarionetteArguments
- from mozlog.structured import commandline
- parser = MarionetteArguments()
- commandline.add_logging_group(parser)
- return parser
-
-def run_marionette(tests, binary=None, topsrcdir=None, **kwargs):
- from mozlog.structured import commandline
-
- from marionette_harness.runtests import (
- MarionetteTestRunner,
- MarionetteHarness
- )
-
- parser = setup_marionette_argument_parser()
-
- if not tests:
- tests = [os.path.join(topsrcdir,
- 'testing/marionette/harness/marionette_harness/tests/unit-tests.ini')]
-
- args = argparse.Namespace(tests=tests)
-
- args.binary = binary
-
- for k, v in kwargs.iteritems():
- setattr(args, k, v)
-
- parser.verify_usage(args)
-
- args.logger = commandline.setup_logging("Marionette Unit Tests",
- args,
- {"mach": sys.stdout})
- failed = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run()
- if failed > 0:
- return 1
- else:
- return 0
-
-@CommandProvider
-class MachCommands(MachCommandBase):
- @Command('marionette-test', category='testing',
- description='Run a Marionette test (Check UI or the internal JavaScript using marionette).',
- conditions=[is_firefox_or_android],
- parser=setup_marionette_argument_parser,
- )
- def run_marionette_test(self, tests, **kwargs):
- if 'test_objects' in kwargs:
- tests = []
- for obj in kwargs['test_objects']:
- tests.append(obj['file_relpath'])
- del kwargs['test_objects']
-
- if not kwargs.get('binary') and conditions.is_firefox(self):
- kwargs['binary'] = self.get_binary_path('app')
- return run_marionette(tests, topsrcdir=self.topsrcdir, **kwargs)
diff --git a/testing/marionette/mach_test_package_commands.py b/testing/marionette/mach_test_package_commands.py
deleted file mode 100644
index 66d99d2a44..0000000000
--- a/testing/marionette/mach_test_package_commands.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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 argparse
-import os
-import sys
-from functools import partial
-
-from mach.decorators import (
- CommandProvider,
- Command,
-)
-
-parser = None
-
-
-def run_marionette(context, **kwargs):
- from marionette.runtests import (
- MarionetteTestRunner,
- MarionetteHarness
- )
- from mozlog.structured import commandline
-
-
- args = argparse.Namespace(**kwargs)
- args.binary = args.binary or context.firefox_bin
- args.e10s = context.mozharness_config.get('e10s', args.e10s)
-
- test_root = os.path.join(context.package_root, 'marionette', 'tests')
- if not args.tests:
- args.tests = [os.path.join(test_root, 'testing', 'marionette', 'harness',
- 'marionette_harness', 'tests', 'unit-tests.ini')]
-
- normalize = partial(context.normalize_test_path, test_root)
- args.tests = map(normalize, args.tests)
-
- commandline.add_logging_group(parser)
- parser.verify_usage(args)
-
- args.logger = commandline.setup_logging("Marionette Unit Tests",
- args,
- {"mach": sys.stdout})
- status = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run()
- return 1 if status else 0
-
-
-def setup_marionette_argument_parser():
- from marionette.runner.base import BaseMarionetteArguments
- global parser
- parser = BaseMarionetteArguments()
- return parser
-
-
-@CommandProvider
-class MachCommands(object):
-
- def __init__(self, context):
- self.context = context
-
- @Command(
- 'marionette-test', category='testing',
- description='Run a Marionette test (Check UI or the internal JavaScript '
- 'using marionette).',
- parser=setup_marionette_argument_parser)
- def run_marionette_test(self, **kwargs):
- return run_marionette(self.context, **kwargs)
diff --git a/testing/marionette/marionette.eslintrc.js b/testing/marionette/marionette.eslintrc.js
deleted file mode 100644
index 8e54bd5ff3..0000000000
--- a/testing/marionette/marionette.eslintrc.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Parent config file for all marionette files.
-module.exports = {
- // All globals made available in the test environment.
- "globals": {
- "ok": false,
- "is": false,
- }
-};
diff --git a/testing/marionette/message.js b/testing/marionette/message.js
deleted file mode 100644
index fd8ac4861c..0000000000
--- a/testing/marionette/message.js
+++ /dev/null
@@ -1,285 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-var {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = [
- "Command",
- "Message",
- "MessageOrigin",
- "Response",
-];
-
-const logger = Log.repository.getLogger("Marionette");
-
-this.MessageOrigin = {
- Client: 0,
- Server: 1,
-};
-
-this.Message = {};
-
-/**
- * Converts a data packet into a Command or Response type.
- *
- * @param {Array.<number, number, ?, ?>} data
- * A four element array where the elements, in sequence, signifies
- * message type, message ID, method name or error, and parameters
- * or result.
- *
- * @return {(Command,Response)}
- * Based on the message type, a Command or Response instance.
- *
- * @throws {TypeError}
- * If the message type is not recognised.
- */
-Message.fromMsg = function (data) {
- switch (data[0]) {
- case Command.TYPE:
- return Command.fromMsg(data);
-
- case Response.TYPE:
- return Response.fromMsg(data);
-
- default:
- throw new TypeError(
- "Unrecognised message type in packet: " + JSON.stringify(data));
- }
-};
-
-/**
- * A command is a request from the client to run a series of remote end
- * steps and return a fitting response.
- *
- * The command can be synthesised from the message passed over the
- * Marionette socket using the {@code fromMsg} function. The format of
- * a message is:
- *
- * [type, id, name, params]
- *
- * where
- *
- * type:
- * Must be zero (integer). Zero means that this message is a command.
- *
- * id:
- * Number used as a sequence number. The server replies with a
- * requested id.
- *
- * name:
- * String representing the command name with an associated set of
- * remote end steps.
- *
- * params:
- * Object of command function arguments. The keys of this object
- * must be strings, but the values can be arbitrary values.
- *
- * A command has an associated message {@code id} that prevents the
- * dispatcher from sending responses in the wrong order.
- *
- * The command may also have optional error- and result handlers that
- * are called when the client returns with a response. These are
- * {@code function onerror({Object})}, {@code function onresult({Object})},
- * and {@code function onresult({Response})}.
- *
- * @param {number} msgId
- * Message ID unique identifying this message.
- * @param {string} name
- * Command name.
- * @param {Object<string, ?>} params
- * Command parameters.
- */
-this.Command = class {
- constructor(msgId, name, params={}) {
- this.id = msgId;
- this.name = name;
- this.parameters = params;
-
- this.onerror = null;
- this.onresult = null;
-
- this.origin = MessageOrigin.Client;
- this.sent = false;
- }
-
- /**
- * Calls the error- or result handler associated with this command.
- * This function can be replaced with a custom response handler.
- *
- * @param {Response} resp
- * The response to pass on to the result or error to the
- * {@code onerror} or {@code onresult} handlers to.
- */
- onresponse(resp) {
- if (resp.error && this.onerror) {
- this.onerror(resp.error);
- } else if (resp.body && this.onresult) {
- this.onresult(resp.body);
- }
- }
-
- toMsg() {
- return [Command.TYPE, this.id, this.name, this.parameters];
- }
-
- toString() {
- return "Command {id: " + this.id + ", " +
- "name: " + JSON.stringify(this.name) + ", " +
- "parameters: " + JSON.stringify(this.parameters) + "}"
- }
-
- static fromMsg(msg) {
- return new Command(msg[1], msg[2], msg[3]);
- }
-};
-
-Command.TYPE = 0;
-
-
-const validator = {
- exclusionary: {
- "capabilities": ["error", "value"],
- "error": ["value", "sessionId", "capabilities"],
- "sessionId": ["error", "value"],
- "value": ["error", "sessionId", "capabilities"],
- },
-
- set: function (obj, prop, val) {
- let tests = this.exclusionary[prop];
- if (tests) {
- for (let t of tests) {
- if (obj.hasOwnProperty(t)) {
- throw new TypeError(`${t} set, cannot set ${prop}`);
- }
- }
- }
-
- obj[prop] = val;
- return true;
- },
-};
-
-/**
- * The response body is exposed as an argument to commands.
- * Commands can set fields on the body through defining properties.
- *
- * Setting properties invokes a validator that performs tests for
- * mutually exclusionary fields on the input against the existing data
- * in the body.
- *
- * For example setting the {@code error} property on the body when
- * {@code value}, {@code sessionId}, or {@code capabilities} have been
- * set previously will cause an error.
- */
-this.ResponseBody = () => new Proxy({}, validator);
-
-/**
- * Represents the response returned from the remote end after execution
- * of its corresponding command.
- *
- * The response is a mutable object passed to each command for
- * modification through the available setters. To send data in a response,
- * you modify the body property on the response. The body property can
- * also be replaced completely.
- *
- * The response is sent implicitly by CommandProcessor when a command
- * has finished executing, and any modifications made subsequent to that
- * will have no effect.
- *
- * @param {number} msgId
- * Message ID tied to the corresponding command request this is a
- * response for.
- * @param {function(Response|Message)} respHandler
- * Function callback called on sending the response.
- */
-this.Response = class {
- constructor(msgId, respHandler) {
- this.id = msgId;
-
- this.error = null;
- this.body = ResponseBody();
-
- this.origin = MessageOrigin.Server;
- this.sent = false;
-
- this.respHandler_ = respHandler;
- }
-
- /**
- * Sends response conditionally, given a predicate.
- *
- * @param {function(Response): boolean} predicate
- * A predicate taking a Response object and returning a boolean.
- */
- sendConditionally(predicate) {
- if (predicate(this)) {
- this.send();
- }
- }
-
- /**
- * Sends response using the response handler provided on construction.
- *
- * @throws {RangeError}
- * If the response has already been sent.
- */
- send() {
- if (this.sent) {
- throw new RangeError("Response has already been sent: " + this);
- }
- this.respHandler_(this);
- this.sent = true;
- }
-
- /**
- * Send given Error to client.
- *
- * Turns the response into an error response, clears any previously
- * set body data, and sends it using the response handler provided
- * on construction.
- *
- * @param {Error} err
- * The Error instance to send.
- *
- * @throws {Error}
- * If the {@code error} is not a WebDriverError, the error is
- * propagated.
- */
- sendError(err) {
- this.error = error.wrap(err).toJSON();
- this.body = null;
- this.send();
-
- // propagate errors which are implementation problems
- if (!error.isWebDriverError(err)) {
- throw err;
- }
- }
-
- toMsg() {
- return [Response.TYPE, this.id, this.error, this.body];
- }
-
- toString() {
- return "Response {id: " + this.id + ", " +
- "error: " + JSON.stringify(this.error) + ", " +
- "body: " + JSON.stringify(this.body) + "}";
- }
-
- static fromMsg(msg) {
- let resp = new Response(msg[1], null);
- resp.error = msg[2];
- resp.body = msg[3];
- return resp;
- }
-};
-
-Response.TYPE = 1;
diff --git a/testing/marionette/modal.js b/testing/marionette/modal.js
deleted file mode 100644
index 3c1b464375..0000000000
--- a/testing/marionette/modal.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-this.EXPORTED_SYMBOLS = ["modal"];
-
-const isFirefox = () => Services.appinfo.name == "Firefox";
-
-this.modal = {};
-modal = {
- COMMON_DIALOG_LOADED: "common-dialog-loaded",
- TABMODAL_DIALOG_LOADED: "tabmodal-dialog-loaded",
- handlers: {
- "common-dialog-loaded": new Set(),
- "tabmodal-dialog-loaded": new Set()
- }
-};
-
-/**
- * Add handler that will be called when a global- or tab modal dialogue
- * appears.
- *
- * This is achieved by installing observers for common-
- * and tab modal loaded events.
- *
- * This function is a no-op if called on any other product than Firefox.
- *
- * @param {function(Object, string)} handler
- * The handler to be called, which is passed the
- * subject (e.g. ChromeWindow) and the topic (one of
- * {@code modal.COMMON_DIALOG_LOADED} or
- * {@code modal.TABMODAL_DIALOG_LOADED}.
- */
-modal.addHandler = function (handler) {
- if (!isFirefox()) {
- return;
- }
-
- Object.keys(this.handlers).map(topic => {
- this.handlers[topic].add(handler);
- Services.obs.addObserver(handler, topic, false);
- });
-};
-
-/**
- * Remove modal dialogue handler by function reference.
- *
- * This function is a no-op if called on any other product than Firefox.
- *
- * @param {function} toRemove
- * The handler previously passed to modal.addHandler which will now
- * be removed.
- */
-modal.removeHandler = function (toRemove) {
- if (!isFirefox()) {
- return;
- }
-
- for (let topic of Object.keys(this.handlers)) {
- let handlers = this.handlers[topic];
- for (let handler of handlers) {
- if (handler == toRemove) {
- Services.obs.removeObserver(handler, topic);
- handlers.delete(handler);
- }
- }
- }
-};
-
-/**
- * Represents the current modal dialogue.
- *
- * @param {function(): browser.Context} curBrowserFn
- * Function that returns the current |browser.Context|.
- * @param {nsIWeakReference=} winRef
- * A weak reference to the current |ChromeWindow|.
- */
-modal.Dialog = class {
- constructor(curBrowserFn, winRef = undefined) {
- this.curBrowserFn_ = curBrowserFn;
- this.win_ = winRef;
- }
-
- get curBrowser_() { return this.curBrowserFn_(); }
-
- /**
- * Returns the ChromeWindow associated with an open dialog window if
- * it is currently attached to the DOM.
- */
- get window() {
- if (this.win_) {
- let win = this.win_.get();
- if (win && win.parent) {
- return win;
- }
- }
- return null;
- }
-
- get ui() {
- let win = this.window;
- if (win) {
- return win.Dialog.ui;
- }
- return this.curBrowser_.getTabModalUI();
- }
-};
diff --git a/testing/marionette/moz.build b/testing/marionette/moz.build
deleted file mode 100644
index 7dbfcca379..0000000000
--- a/testing/marionette/moz.build
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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/.
-
-DIRS += ["components"]
-
-JAR_MANIFESTS += ["jar.mn"]
-MARIONETTE_UNIT_MANIFESTS += ["harness/marionette_harness/tests/unit/unit-tests.ini"]
-MARIONETTE_WEBAPI_MANIFESTS += ["harness/marionette_harness/tests/webapi-tests.ini"]
-XPCSHELL_TESTS_MANIFESTS += ["unit.ini"]
-
-with Files("**"):
- BUG_COMPONENT = ("Testing", "Marionette")
diff --git a/testing/marionette/navigate.js b/testing/marionette/navigate.js
deleted file mode 100644
index edbfa552a2..0000000000
--- a/testing/marionette/navigate.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.importGlobalProperties(["URL"]);
-
-this.EXPORTED_SYMBOLS = ["navigate"];
-
-this.navigate = {};
-
-/**
- * Determines if we expect to get a DOM load event (DOMContentLoaded)
- * on navigating to the |future| URL.
- *
- * @param {string} current
- * URL the browser is currently visiting.
- * @param {string=} future
- * Destination URL, if known.
- *
- * @return {boolean}
- * Full page load would be expected if future is followed.
- *
- * @throws TypeError
- * If |current| is not defined, or any of |current| or |future|
- * are invalid URLs.
- */
-navigate.isLoadEventExpected = function (current, future = undefined) {
- if (typeof current == "undefined") {
- throw TypeError("Expected at least one URL");
- }
-
- // assume we will go somewhere exciting
- if (typeof future == "undefined") {
- return true;
- }
-
- let cur = new navigate.IdempotentURL(current);
- let fut = new navigate.IdempotentURL(future);
-
- // assume javascript:<whatever> will modify current document
- // but this is not an entirely safe assumption to make,
- // considering it could be used to set window.location
- if (fut.protocol == "javascript:") {
- return false;
- }
-
- // navigating to same url, but with any hash
- if (cur.origin == fut.origin &&
- cur.pathname == fut.pathname &&
- fut.hash != "") {
- return false;
- }
-
- return true;
-};
-
-/**
- * Sane URL implementation that normalises URL fragments (hashes) and
- * path names for "data:" URLs, and makes them idempotent.
- *
- * At the time of writing this, the web is approximately 10 000 days (or
- * ~27.39 years) old. One should think that by this point we would have
- * solved URLs. The following code is prudent example that we have not.
- *
- * When a URL with a fragment identifier but no explicit name for the
- * fragment is given, i.e. "#", the {@code hash} property a {@code URL}
- * object computes is an empty string. This is incidentally the same as
- * the default value of URLs without fragments, causing a lot of confusion.
- *
- * This means that the URL "http://a/#b" produces a hash of "#b", but that
- * "http://a/#" produces "". This implementation rectifies this behaviour
- * by returning the actual full fragment, which is "#".
- *
- * "data:" URLs that contain fragments, which if they have the same origin
- * and path name are not meant to cause a page reload on navigation,
- * confusingly adds the fragment to the {@code pathname} property.
- * This implementation remedies this behaviour by trimming it off.
- *
- * The practical result of this is that while {@code URL} objects are
- * not idempotent, the returned URL elements from this implementation
- * guarantees that |url.hash == url.hash|.
- *
- * @param {string|URL} o
- * Object to make an URL of.
- *
- * @return {navigate.IdempotentURL}
- * Considered by some to be a somewhat saner URL.
- *
- * @throws TypeError
- * If |o| is not a valid type or if is a string that cannot be parsed
- * as a URL.
- */
-navigate.IdempotentURL = function (o) {
- let url = new URL(o);
-
- let hash = url.hash;
- if (hash == "" && url.href[url.href.length - 1] == "#") {
- hash = "#";
- }
-
- return {
- hash: hash,
- host: url.host,
- hostname: url.hostname,
- href: url.href,
- origin: url.origin,
- password: url.password,
- pathname: url.pathname,
- port: url.port,
- protocol: url.protocol,
- search: url.search,
- searchParams: url.searchParams,
- username: url.username,
- };
-};
diff --git a/testing/marionette/proxy.js b/testing/marionette/proxy.js
deleted file mode 100644
index 9d338d44a2..0000000000
--- a/testing/marionette/proxy.js
+++ /dev/null
@@ -1,376 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/modal.js");
-
-this.EXPORTED_SYMBOLS = ["proxy"];
-
-const uuidgen = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
-
-// Proxy handler that traps requests to get a property. Will prioritise
-// properties that exist on the object's own prototype.
-var ownPriorityGetterTrap = {
- get: (obj, prop) => {
- if (obj.hasOwnProperty(prop)) {
- return obj[prop];
- }
- return (...args) => obj.send(prop, args);
- }
-};
-
-this.proxy = {};
-
-/**
- * Creates a transparent interface between the chrome- and content
- * contexts.
- *
- * Calls to this object will be proxied via the message manager to a
- * content frame script, and responses are returend as promises.
- *
- * The argument sequence is serialised and passed as an array, unless it
- * consists of a single object type that isn't null, in which case it's
- * passed literally. The latter specialisation is temporary to achieve
- * backwards compatibility with listener.js.
- *
- * @param {function(): (nsIMessageSender|nsIMessageBroadcaster)} mmFn
- * Closure function returning the current message manager.
- * @param {function(string, Object, number)} sendAsyncFn
- * Callback for sending async messages.
- */
-proxy.toListener = function (mmFn, sendAsyncFn) {
- let sender = new proxy.AsyncMessageChannel(mmFn, sendAsyncFn);
- return new Proxy(sender, ownPriorityGetterTrap);
-};
-
-/**
- * Provides a transparent interface between chrome- and content space.
- *
- * The AsyncMessageChannel is an abstraction of the message manager
- * IPC architecture allowing calls to be made to any registered message
- * listener in Marionette. The {@code #send(...)} method returns a promise
- * that gets resolved when the message handler calls {@code .reply(...)}.
- */
-proxy.AsyncMessageChannel = class {
- constructor(mmFn, sendAsyncFn) {
- this.sendAsync = sendAsyncFn;
- // TODO(ato): Bug 1242595
- this.activeMessageId = null;
-
- this.mmFn_ = mmFn;
- this.listeners_ = new Map();
- this.dialogueObserver_ = null;
- }
-
- get mm() {
- return this.mmFn_();
- }
-
- /**
- * Send a message across the channel. The name of the function to
- * call must be registered as a message listener.
- *
- * Usage:
- *
- * let channel = new AsyncMessageChannel(
- * messageManager, sendAsyncMessage.bind(this));
- * let rv = yield channel.send("remoteFunction", ["argument"]);
- *
- * @param {string} name
- * Function to call in the listener, e.g. for the message listener
- * "Marionette:foo8", use "foo".
- * @param {Array.<?>=} args
- * Argument list to pass the function. If args has a single entry
- * that is an object, we assume it's an old style dispatch, and
- * the object will passed literally.
- *
- * @return {Promise}
- * A promise that resolves to the result of the command.
- * @throws {TypeError}
- * If an unsupported reply type is received.
- * @throws {WebDriverError}
- * If an error is returned over the channel.
- */
- send(name, args = []) {
- let uuid = uuidgen.generateUUID().toString();
- // TODO(ato): Bug 1242595
- this.activeMessageId = uuid;
-
- return new Promise((resolve, reject) => {
- let path = proxy.AsyncMessageChannel.makePath(uuid);
- let cb = msg => {
- this.activeMessageId = null;
-
- switch (msg.json.type) {
- case proxy.AsyncMessageChannel.ReplyType.Ok:
- case proxy.AsyncMessageChannel.ReplyType.Value:
- resolve(msg.json.data);
- break;
-
- case proxy.AsyncMessageChannel.ReplyType.Error:
- let err = WebDriverError.fromJSON(msg.json.data);
- reject(err);
- break;
-
- default:
- throw new TypeError(
- `Unknown async response type: ${msg.json.type}`);
- }
- };
-
- this.dialogueObserver_ = (subject, topic) => {
- this.cancelAll();
- resolve();
- };
-
- // start content message listener
- // and install observers for global- and tab modal dialogues
- this.addListener_(path, cb);
- modal.addHandler(this.dialogueObserver_);
-
- // sendAsync is GeckoDriver#sendAsync
- this.sendAsync(name, marshal(args), uuid);
- });
- }
-
- /**
- * Reply to an asynchronous request.
- *
- * Passing an WebDriverError prototype will cause the receiving channel
- * to throw this error.
- *
- * Usage:
- *
- * let channel = proxy.AsyncMessageChannel(
- * messageManager, sendAsyncMessage.bind(this));
- *
- * // throws in requester:
- * channel.reply(uuid, new WebDriverError());
- *
- * // returns with value:
- * channel.reply(uuid, "hello world!");
- *
- * // returns with undefined:
- * channel.reply(uuid);
- *
- * @param {UUID} uuid
- * Unique identifier of the request.
- * @param {?=} obj
- * Message data to reply with.
- */
- reply(uuid, obj = undefined) {
- // TODO(ato): Eventually the uuid will be hidden in the dispatcher
- // in listener, and passing it explicitly to this function will be
- // unnecessary.
- if (typeof obj == "undefined") {
- this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Ok);
- } else if (error.isError(obj)) {
- let err = error.wrap(obj);
- this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Error, err);
- } else {
- this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Value, obj);
- }
- }
-
- sendReply_(uuid, type, data = undefined) {
- const path = proxy.AsyncMessageChannel.makePath(uuid);
-
- let payload;
- if (data && typeof data.toJSON == "function") {
- payload = data.toJSON();
- } else {
- payload = data;
- }
-
- const msg = {type: type, data: payload};
-
- // here sendAsync is actually the content frame's
- // sendAsyncMessage(path, message) global
- this.sendAsync(path, msg);
- }
-
- /**
- * Produces a path, or a name, for the message listener handler that
- * listens for a reply.
- *
- * @param {UUID} uuid
- * Unique identifier of the channel request.
- *
- * @return {string}
- * Path to be used for nsIMessageListener.addMessageListener.
- */
- static makePath(uuid) {
- return "Marionette:asyncReply:" + uuid;
- }
-
- /**
- * Abort listening for responses, remove all modal dialogue handlers,
- * and cancel any ongoing requests in the listener.
- */
- cancelAll() {
- this.removeAllListeners_();
- modal.removeHandler(this.dialogueObserver_);
- // TODO(ato): It's not ideal to have listener specific behaviour here:
- this.sendAsync("cancelRequest");
- }
-
- addListener_(path, callback) {
- let autoRemover = msg => {
- this.removeListener_(path);
- modal.removeHandler(this.dialogueObserver_);
- callback(msg);
- };
-
- this.mm.addMessageListener(path, autoRemover);
- this.listeners_.set(path, autoRemover);
- }
-
- removeListener_(path) {
- if (!this.listeners_.has(path)) {
- return true;
- }
-
- let l = this.listeners_.get(path);
- this.mm.removeMessageListener(path, l[1]);
- return this.listeners_.delete(path);
- }
-
- removeAllListeners_() {
- let ok = true;
- for (let [p, cb] of this.listeners_) {
- ok |= this.removeListener_(p);
- }
- return ok;
- }
-};
-proxy.AsyncMessageChannel.ReplyType = {
- Ok: 0,
- Value: 1,
- Error: 2,
-};
-
-/**
- * A transparent content-to-chrome RPC interface where responses are
- * presented as promises.
- *
- * @param {nsIFrameMessageManager} frameMessageManager
- * The content frame's message manager, which itself is usually an
- * implementor of.
- */
-proxy.toChromeAsync = function (frameMessageManager) {
- let sender = new AsyncChromeSender(frameMessageManager);
- return new Proxy(sender, ownPriorityGetterTrap);
-};
-
-/**
- * Sends asynchronous RPC messages to chrome space using a frame's
- * sendAsyncMessage (nsIAsyncMessageSender) function.
- *
- * Example on how to use from a frame content script:
- *
- * let sender = new AsyncChromeSender(messageManager);
- * let promise = sender.send("runEmulatorCmd", "my command");
- * let rv = yield promise;
- */
-this.AsyncChromeSender = class {
- constructor(frameMessageManager) {
- this.mm = frameMessageManager;
- }
-
- /**
- * Call registered function in chrome context.
- *
- * @param {string} name
- * Function to call in the chrome, e.g. for "Marionette:foo", use
- * "foo".
- * @param {?} args
- * Argument list to pass the function. Must be JSON serialisable.
- *
- * @return {Promise}
- * A promise that resolves to the value sent back.
- */
- send(name, args) {
- let uuid = uuidgen.generateUUID().toString();
-
- let proxy = new Promise((resolve, reject) => {
- let responseListener = msg => {
- if (msg.json.id != uuid) {
- return;
- }
-
- this.mm.removeMessageListener(
- "Marionette:listenerResponse", responseListener);
-
- if ("value" in msg.json) {
- resolve(msg.json.value);
- } else if ("error" in msg.json) {
- reject(msg.json.error);
- } else {
- throw new TypeError(
- `Unexpected response: ${msg.name} ${JSON.stringify(msg.json)}`);
- }
- };
-
- let msg = {arguments: marshal(args), id: uuid};
- this.mm.addMessageListener(
- "Marionette:listenerResponse", responseListener);
- this.mm.sendAsyncMessage("Marionette:" + name, msg);
- });
-
- return proxy;
- }
-};
-
-/**
- * Creates a transparent interface from the content- to the chrome context.
- *
- * Calls to this object will be proxied via the frame's sendSyncMessage
- * (nsISyncMessageSender) function. Since the message is synchronous,
- * the return value is presented as a return value.
- *
- * Example on how to use from a frame content script:
- *
- * let chrome = proxy.toChrome(sendSyncMessage.bind(this));
- * let cookie = chrome.getCookie("foo");
- *
- * @param {nsISyncMessageSender} sendSyncMessageFn
- * The frame message manager's sendSyncMessage function.
- */
-proxy.toChrome = function (sendSyncMessageFn) {
- let sender = new proxy.SyncChromeSender(sendSyncMessageFn);
- return new Proxy(sender, ownPriorityGetterTrap);
-};
-
-/**
- * The SyncChromeSender sends synchronous RPC messages to the chrome
- * context, using a frame's sendSyncMessage (nsISyncMessageSender)
- * function.
- *
- * Example on how to use from a frame content script:
- *
- * let sender = new SyncChromeSender(sendSyncMessage.bind(this));
- * let res = sender.send("addCookie", cookie);
- */
-proxy.SyncChromeSender = class {
- constructor(sendSyncMessage) {
- this.sendSyncMessage_ = sendSyncMessage;
- }
-
- send(func, args) {
- let name = "Marionette:" + func.toString();
- return this.sendSyncMessage_(name, marshal(args));
- }
-};
-
-var marshal = function (args) {
- if (args.length == 1 && typeof args[0] == "object") {
- return args[0];
- }
- return args;
-};
diff --git a/testing/marionette/puppeteer/.flake8 b/testing/marionette/puppeteer/.flake8
deleted file mode 100644
index ad0819adf8..0000000000
--- a/testing/marionette/puppeteer/.flake8
+++ /dev/null
@@ -1,3 +0,0 @@
-[flake8]
-max-line-length = 99
-exclude = __init__.py,
diff --git a/testing/marionette/puppeteer/firefox/MANIFEST.in b/testing/marionette/puppeteer/firefox/MANIFEST.in
deleted file mode 100644
index cf628b039c..0000000000
--- a/testing/marionette/puppeteer/firefox/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-exclude MANIFEST.in
-include requirements.txt
diff --git a/testing/marionette/puppeteer/firefox/docs/Makefile b/testing/marionette/puppeteer/firefox/docs/Makefile
deleted file mode 100644
index 86ab047dbf..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/Makefile
+++ /dev/null
@@ -1,177 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-
-# User-friendly check for sphinx-build
-ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
-$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
-endif
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " xml to make Docutils-native XML files"
- @echo " pseudoxml to make pseudoxml-XML files for display purposes"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FirefoxPuppeteer.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FirefoxPuppeteer.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/FirefoxPuppeteer"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FirefoxPuppeteer"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-latexpdfja:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through platex and dvipdfmx..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
-
-xml:
- $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
- @echo
- @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-pseudoxml:
- $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
- @echo
- @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/testing/marionette/puppeteer/firefox/docs/api/appinfo.rst b/testing/marionette/puppeteer/firefox/docs/api/appinfo.rst
deleted file mode 100644
index e3e9842bf4..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/appinfo.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.appinfo
-
-AppInfo
-=======
-
-The appinfo class is a wrapper around the nsIXULAppInfo_ interface in
-Firefox and provides access to a subset of its members.
-
-.. _nsIXULAppInfo: https://developer.mozilla.org/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIXULAppInfo
-
-AppInfo
--------
-
-.. autoclass:: AppInfo
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/keys.rst b/testing/marionette/puppeteer/firefox/docs/api/keys.rst
deleted file mode 100644
index 104b84e063..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/keys.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.keys
-
-Keys
-====
-
-Keys
-----
-
-.. autoclass:: Keys
- :members:
- :inherited-members:
- :undoc-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/l10n.rst b/testing/marionette/puppeteer/firefox/docs/api/l10n.rst
deleted file mode 100644
index dd332a63c4..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/l10n.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.l10n
-
-Localization
-============
-
-Localization
-------------
-
-.. autoclass:: L10n
- :members:
- :undoc-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/places.rst b/testing/marionette/puppeteer/firefox/docs/api/places.rst
deleted file mode 100644
index a469c1c6cc..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/places.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.places
-
-Places
-======
-
-The Places class provides low-level access for several bookmark and history
-related methods.
-
-Places
-------
-
-.. autoclass:: Places
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/security.rst b/testing/marionette/puppeteer/firefox/docs/api/security.rst
deleted file mode 100644
index eb9799fe04..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/security.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.security
-
-Security
-===========
-
-The Security class gives access to various helper methods, which assist in working with
-certificates or accessing specific security related information.
-
-Security
---------
-
-.. autoclass:: Security
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/software_update.rst b/testing/marionette/puppeteer/firefox/docs/api/software_update.rst
deleted file mode 100644
index ce9f410164..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/software_update.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.software_update
-
-SoftwareUpdate
-==============
-
-The SoftwareUpdate class provides helpers for update tests.
-
-SoftwareUpdate
---------------
-
-.. autoclass:: SoftwareUpdate
- :members:
-
-ActiveUpdate
-------------
-
-.. autoclass:: ActiveUpdate
- :members:
-
-MARChannels
------------
-
-.. autoclass:: MARChannels
- :members:
-
-UpdateChannel
--------------
-
-.. autoclass:: UpdateChannel
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/api/utils.rst b/testing/marionette/puppeteer/firefox/docs/api/utils.rst
deleted file mode 100644
index b654d24ece..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/api/utils.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.api.utils
-
-Utils
-===========
-
-The Utils class gives access to various helper methods.
-
-Utils
------
-
-.. autoclass:: Utils
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/conf.py b/testing/marionette/puppeteer/firefox/docs/conf.py
deleted file mode 100644
index 9af1338556..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/conf.py
+++ /dev/null
@@ -1,270 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Firefox Puppeteer documentation build configuration file, created by
-# sphinx-quickstart on Thu Nov 20 10:35:33 2014.
-#
-# This file is execfile()d with the current directory set to its
-# containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration ------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.todo',
-]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'Firefox Puppeteer'
-copyright = u'2014-2015, Mozilla'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.1'
-# The full version, including alpha/beta/rc tags.
-release = '0.1'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-# keep_warnings = False
-
-
-# -- Options for HTML output ----------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
-
-if not on_rtd:
- try:
- import sphinx_rtd_theme
- html_theme = 'sphinx_rtd_theme'
- html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
- except ImportError:
- pass
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-# html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# Add any extra paths that contain custom files (such as robots.txt or
-# .htaccess) here, relative to this directory. These files are copied
-# directly to the root of the documentation.
-# html_extra_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'FirefoxPuppeteerdoc'
-
-
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- # 'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- # 'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- # 'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title,
-# author, documentclass [howto, manual, or own class]).
-latex_documents = [
- ('index', 'FirefoxPuppeteer.tex', u'Firefox Puppeteer Documentation',
- u'Mozilla', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'firefoxpuppeteer', u'Firefox Puppeteer Documentation',
- [u'Mozilla'], 1)
-]
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'FirefoxPuppeteer', u'Firefox Puppeteer Documentation',
- u'Mozilla', 'FirefoxPuppeteer', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-# texinfo_no_detailmenu = False
diff --git a/testing/marionette/puppeteer/firefox/docs/index.rst b/testing/marionette/puppeteer/firefox/docs/index.rst
deleted file mode 100644
index d77ac59688..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/index.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer
-
-Firefox Puppeteer
-=================
-
-`Firefox Puppeteer`_ is a library built on top of the `Marionette Python client`_.
-It aims to make automation of Firefox's browser UI simpler. It does **not**
-make sense to use Firefox Puppeteer if:
-
-* You are manipulating something other than Firefox (like Firefox OS)
-* You are only manipulating elements in content scope (like a webpage)
-
-Roughly speaking, Firefox Puppeteer provides a library to manipulate each
-visual section of Firefox's browser UI. For example, there are different
-libraries for the tab bar, the navigation bar, etc.
-
-.. _Firefox Puppeteer: http://firefox-puppeteer.readthedocs.io/
-.. _Marionette Python client: http://marionette-client.readthedocs.org/
-
-Installation
-------------
-
-For end-users Firefox Puppeteer can be easily installed as a `Python package`_
-from PyPI. If you want to contribute to the project we propose that you clone
-the `mozilla-central`_ repository and run the following commands::
-
-$ cd testing/puppeteer/firefox
-$ python setup.py develop
-
-In both cases all necessary files including all dependencies will be installed.
-
-.. _Python package: https://pypi.python.org/pypi/firefox-puppeteer
-.. _mozilla-central: https://hg.mozilla.org/mozilla-central
-
-Versioning
-----------
-
-Puppeteer versions as regularly released from the Python source code, will follow
-a specific versioning schema. It means the major version number will always
-be identical with the supported Firefox version. Minor releases - the second part
-of the version number - are done throughout the life-cycle of a Firefox version
-when Puppeteer itself needs API changes for back-end and front-end modules. The
-last part of the version number is the patch level, and is only used for bugfix
-releases without any API changes.
-
-Examples:
-
- firefox_puppeteer_45.0.0 - First release for Firefox 45.0 and Firefox 45.xESR
- firefox_puppeteer_46.2.0 - Second release for Firefox 46.0 caused by API changes
- firefox_puppeteer_47.0.1 - First bugfix release for the new Firefox 47.0 support
-
-
-Libraries
----------
-
-The following libraries are currently implemented. More will be added in the
-future. Each library is available from an instance of the FirefoxTestCase class.
-
-.. toctree::
-
- ui/about_window/window
- ui/deck
- ui/menu
- ui/pageinfo/window
- ui/browser/notifications
- ui/browser/tabbar
- ui/browser/toolbars
- ui/browser/window
- ui/update_wizard/dialog
- ui/windows
- api/appinfo
- api/keys
- api/l10n
- api/places
- api/security
- api/software_update
- api/utils
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/testing/marionette/puppeteer/firefox/docs/make.bat b/testing/marionette/puppeteer/firefox/docs/make.bat
deleted file mode 100644
index 12a7390169..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/make.bat
+++ /dev/null
@@ -1,242 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. xml to make Docutils-native XML files
- echo. pseudoxml to make pseudoxml-XML files for display purposes
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-
-%SPHINXBUILD% 2> nul
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.http://sphinx-doc.org/
- exit /b 1
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\FirefoxPuppeteer.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\FirefoxPuppeteer.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdf" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdfja" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf-ja
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-if "%1" == "xml" (
- %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The XML files are in %BUILDDIR%/xml.
- goto end
-)
-
-if "%1" == "pseudoxml" (
- %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
- goto end
-)
-
-:end
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/about_window/window.rst b/testing/marionette/puppeteer/firefox/docs/ui/about_window/window.rst
deleted file mode 100644
index 43f9132f18..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/about_window/window.rst
+++ /dev/null
@@ -1,59 +0,0 @@
-About Window
-============
-
-AboutWindow
---------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.window.AboutWindow
- :members:
- :inherited-members:
-
-Deck
-----
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.Deck
- :members:
- :inherited-members:
-
-ApplyPanel
-----------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.ApplyPanel
- :members:
- :inherited-members:
-
-CheckForUpdatesPanel
---------------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.CheckForUpdatesPanel
- :members:
- :inherited-members:
-
-CheckingForUpdatesPanel
------------------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.CheckingForUpdatesPanel
- :members:
- :inherited-members:
-
-DownloadAndInstallPanel
------------------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.DownloadAndInstallPanel
- :members:
- :inherited-members:
-
-DownloadFailedPanel
--------------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.DownloadFailedPanel
- :members:
- :inherited-members:
-
-DownloadingPanel
-----------------
-
-.. autoclass:: firefox_puppeteer.ui.about_window.deck.DownloadingPanel
- :members:
- :inherited-members:
-
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/browser/notifications.rst b/testing/marionette/puppeteer/firefox/docs/ui/browser/notifications.rst
deleted file mode 100644
index 9ef44502c6..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/browser/notifications.rst
+++ /dev/null
@@ -1,44 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.browser.notifications
-
-Notifications
-=============
-
-AddOnInstallBlockedNotification
--------------------------------
-
-.. autoclass:: AddOnInstallBlockedNotification
- :members:
- :inherited-members:
- :show-inheritance:
-
-AddOnInstallConfirmationNotification
-------------------------------------
-
-.. autoclass:: AddOnInstallConfirmationNotification
- :members:
- :inherited-members:
- :show-inheritance:
-
-AddOnInstallCompleteNotification
---------------------------------
-
-.. autoclass:: AddOnInstallCompleteNotification
- :members:
- :inherited-members:
- :show-inheritance:
-
-AddOnInstallFailedNotification
-------------------------------
-
-.. autoclass:: AddOnInstallFailedNotification
- :members:
- :inherited-members:
- :show-inheritance:
-
-AddOnProgressNotification
--------------------------
-
-.. autoclass:: AddOnProgressNotification
- :members:
- :inherited-members:
- :show-inheritance:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/browser/tabbar.rst b/testing/marionette/puppeteer/firefox/docs/ui/browser/tabbar.rst
deleted file mode 100644
index 1ac431a991..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/browser/tabbar.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.browser.tabbar
-
-Tabbar
-======
-
-TabBar
-------
-
-.. autoclass:: TabBar
- :members:
-
-Tab
----
-
-.. autoclass:: Tab
- :members:
-
-MenuPanel
-----------
-
-.. autoclass:: MenuPanel
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/browser/toolbars.rst b/testing/marionette/puppeteer/firefox/docs/ui/browser/toolbars.rst
deleted file mode 100644
index ade4c799f6..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/browser/toolbars.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.browser.toolbars
-
-Toolbars
-========
-
-NavBar
-------
-
-.. autoclass:: NavBar
- :members:
-
-LocationBar
------------
-
-.. autoclass:: LocationBar
- :members:
-
-AutocompleteResults
--------------------
-
-.. autoclass:: AutocompleteResults
- :members:
-
-IdentityPopup
--------------
-
-.. autoclass:: IdentityPopup
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/browser/window.rst b/testing/marionette/puppeteer/firefox/docs/ui/browser/window.rst
deleted file mode 100644
index c12405f4d8..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/browser/window.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.browser.window
-
-BrowserWindow
-=============
-
-BrowserWindow
--------------
-
-.. autoclass:: BrowserWindow
- :members:
- :inherited-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/deck.rst b/testing/marionette/puppeteer/firefox/docs/ui/deck.rst
deleted file mode 100644
index 7f8bdef61b..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/deck.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Deck
-=====
-
-Panel
-------
-
-.. autoclass:: firefox_puppeteer.ui.deck.Panel
- :members:
- :inherited-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/menu.rst b/testing/marionette/puppeteer/firefox/docs/ui/menu.rst
deleted file mode 100644
index f6ecf0f424..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/menu.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.menu
-
-Menu
-====
-
-Menu Bar
---------
-
-.. autoclass:: MenuBar
- :members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/pageinfo/window.rst b/testing/marionette/puppeteer/firefox/docs/ui/pageinfo/window.rst
deleted file mode 100644
index 0725db0454..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/pageinfo/window.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-Page Info Window
-================
-
-PageInfoWindow
---------------
-
-.. autoclass:: firefox_puppeteer.ui.pageinfo.window.PageInfoWindow
- :members:
- :inherited-members:
-
-Deck
-----
-
-.. autoclass:: firefox_puppeteer.ui.pageinfo.deck.Deck
- :members:
- :inherited-members:
-
-PageInfoPanel
--------------
-
-.. autoclass:: firefox_puppeteer.ui.pageinfo.deck.PageInfoPanel
- :members:
- :inherited-members:
-
-SecurityPanel
--------------
-
-.. autoclass:: firefox_puppeteer.ui.pageinfo.deck.SecurityPanel
- :members:
- :inherited-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/update_wizard/dialog.rst b/testing/marionette/puppeteer/firefox/docs/ui/update_wizard/dialog.rst
deleted file mode 100644
index 8b70101e4f..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/update_wizard/dialog.rst
+++ /dev/null
@@ -1,128 +0,0 @@
-Update Wizard Dialog
-====================
-
-UpdateWizardDialog
-------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.dialog.UpdateWizardDialog
- :members:
- :inherited-members:
-
-Wizard
-------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.Wizard
- :members:
- :inherited-members:
-
-CheckingPanel
--------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.CheckingPanel
- :members:
- :inherited-members:
-
-DownloadingPanel
-----------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.DownloadingPanel
- :members:
- :inherited-members:
-
-DummyPanel
-----------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.DummyPanel
- :members:
- :inherited-members:
-
-ErrorPatchingPanel
-------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.ErrorPatchingPanel
- :members:
- :inherited-members:
-
-ErrorPanel
-----------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.ErrorPanel
- :members:
- :inherited-members:
-
-ErrorExtraPanel
----------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.ErrorExtraPanel
- :members:
- :inherited-members:
-
-FinishedPanel
--------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.FinishedPanel
- :members:
- :inherited-members:
-
-FinishedBackgroundPanel
------------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.FinishedBackgroundPanel
- :members:
- :inherited-members:
-
-IncompatibleCheckPanel
-----------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.IncompatibleCheckPanel
- :members:
- :inherited-members:
-
-IncompatibleListPanel
----------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.IncompatibleListPanel
- :members:
- :inherited-members:
-
-InstalledPanel
---------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.InstalledPanel
- :members:
- :inherited-members:
-
-LicensePanel
-------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.LicensePanel
- :members:
- :inherited-members:
-
-ManualUpdatePanel
------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.ManualUpdatePanel
- :members:
- :inherited-members:
-
-NoUpdatesFoundPanel
--------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.NoUpdatesFoundPanel
- :members:
- :inherited-members:
-
-PluginUpdatesFoundPanel
------------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.PluginUpdatesFoundPanel
- :members:
- :inherited-members:
-
-UpdatesFoundBasicPanel
-----------------------
-
-.. autoclass:: firefox_puppeteer.ui.update_wizard.wizard.UpdatesFoundBasicPanel
- :members:
- :inherited-members:
diff --git a/testing/marionette/puppeteer/firefox/docs/ui/windows.rst b/testing/marionette/puppeteer/firefox/docs/ui/windows.rst
deleted file mode 100644
index 258a743c9f..0000000000
--- a/testing/marionette/puppeteer/firefox/docs/ui/windows.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-.. py:currentmodule:: firefox_puppeteer.ui.windows
-
-Windows
-=======
-
-Windows
--------
-
-.. autoclass:: Windows
- :members:
-
-BaseWindow
-----------
-
-.. autoclass:: BaseWindow
- :members:
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/__init__.py
deleted file mode 100644
index bc66051020..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# 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.mixins import PuppeteerMixin
-from firefox_puppeteer.puppeteer import Puppeteer
-
-
-__version__ = '52.1.0'
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/__init__.py
+++ /dev/null
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/appinfo.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/appinfo.py
deleted file mode 100644
index 13d32c15b1..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/appinfo.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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.base import BaseLib
-
-
-class AppInfo(BaseLib):
- """This class provides access to various attributes of AppInfo.
-
- For more details on AppInfo, visit:
- https://developer.mozilla.org/en-US/docs/Mozilla/QA/Mozmill_tests/Shared_Modules/UtilsAPI/appInfo
- """
-
- def __getattr__(self, attr):
- with self.marionette.using_context('chrome'):
- value = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- return Services.appinfo[arguments[0]];
- """, script_args=[attr])
-
- if value is not None:
- return value
- else:
- raise AttributeError('{} has no attribute {}'.format(self.__class__.__name__,
- attr))
-
- @property
- def locale(self):
- with self.marionette.using_context('chrome'):
- return self.marionette.execute_script("""
- return Components.classes["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Components.interfaces.nsIXULChromeRegistry)
- .getSelectedLocale("global");
- """)
-
- @property
- def user_agent(self):
- with self.marionette.using_context('chrome'):
- return self.marionette.execute_script("""
- return Components.classes["@mozilla.org/network/protocol;1?name=http"]
- .getService(Components.interfaces.nsIHttpProtocolHandler)
- .userAgent;
- """)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/keys.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/keys.py
deleted file mode 100644
index 2c5a1e523d..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/keys.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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 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):
- self.isDarwin = marionette.session_capabilities['platformName'] == 'darwin'
-
- @property
- def ACCEL(self):
- return self.META if self.isDarwin else self.CONTROL
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/l10n.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/l10n.py
deleted file mode 100644
index f7f52918c3..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/l10n.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# 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/.
-
-# -----------------
-# DEPRECATED module
-# -----------------
-# Replace its use in tests when Firefox 45 ESR support ends with
-# marionette_driver.localization.L10n
-
-import copy
-
-from marionette_driver.errors import (
- NoSuchElementException,
- UnknownCommandException,
-)
-from marionette_driver.localization import L10n as L10nMarionette
-
-from firefox_puppeteer.base import BaseLib
-
-
-class L10n(BaseLib):
- """An API which allows Marionette to handle localized content.
-
- .. deprecated:: 52.2.0
- Use the localization module from :py:mod:`marionette_driver` instead.
-
- The `localization`_ of UI elements in Gecko based applications is done via
- entities and properties. For static values entities are used, which are located
- in .dtd files. Whereby for dynamically updated content the values come from
- .property files. Both types of elements can be identifed via a unique id,
- and the translated content retrieved.
-
- .. _localization: https://mzl.la/2eUMjyF
- """
-
- def __init__(self, marionette):
- super(L10n, self).__init__(marionette)
-
- self._l10nMarionette = L10nMarionette(self.marionette)
-
- def localize_entity(self, dtd_urls, entity_id):
- """Returns the localized string for the specified DTD entity id.
-
- To find the entity all given DTD files will be searched for the id.
-
- :param dtd_urls: A list of dtd files to search.
- :param entity_id: The id to retrieve the value from.
-
- :returns: The localized string for the requested entity.
-
- :raises NoSuchElementException: When entity id is not found in dtd_urls.
- """
- # Add xhtml11.dtd to prevent missing entity errors with XHTML files
- try:
- return self._l10nMarionette.localize_entity(dtd_urls, entity_id)
- except UnknownCommandException:
- dtds = copy.copy(dtd_urls)
- dtds.append("resource:///res/dtd/xhtml11.dtd")
-
- dtd_refs = ''
- for index, item in enumerate(dtds):
- dtd_id = 'dtd_%s' % index
- dtd_refs += '<!ENTITY %% %s SYSTEM "%s">%%%s;' % \
- (dtd_id, item, dtd_id)
-
- contents = """<?xml version="1.0"?>
- <!DOCTYPE elem [%s]>
-
- <elem id="entity">&%s;</elem>""" % (dtd_refs, entity_id)
-
- with self.marionette.using_context('chrome'):
- value = self.marionette.execute_script("""
- var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
- .createInstance(Components.interfaces.nsIDOMParser);
- var doc = parser.parseFromString(arguments[0], "text/xml");
- var node = doc.querySelector("elem[id='entity']");
-
- return node ? node.textContent : null;
- """, script_args=[contents])
-
- if not value:
- raise NoSuchElementException('DTD Entity not found: %s' % entity_id)
-
- return value
-
- def localize_property(self, property_urls, property_id):
- """Returns the localized string for the specified property id.
-
- To find the property all given property files will be searched for
- the id.
-
- :param property_urls: A list of property files to search.
- :param property_id: The id to retrieve the value from.
-
- :returns: The localized string for the requested entity.
-
- :raises NoSuchElementException: When property id is not found in
- property_urls.
- """
- try:
- return self._l10nMarionette.localize_property(property_urls, property_id)
- except UnknownCommandException:
- with self.marionette.using_context('chrome'):
- value = self.marionette.execute_script("""
- let property = null;
- let property_id = arguments[1];
-
- arguments[0].some(aUrl => {
- let bundle = Services.strings.createBundle(aUrl);
-
- try {
- property = bundle.GetStringFromName(property_id);
- return true;
- }
- catch (ex) { }
- });
-
- return property;
- """, script_args=[property_urls, property_id])
-
- if not value:
- raise NoSuchElementException('Property not found: %s' % property_id)
-
- return value
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/places.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/places.py
deleted file mode 100644
index fadc2c19b6..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/places.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# 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 collections import namedtuple
-from time import sleep
-
-from marionette_driver.errors import MarionetteException
-
-from firefox_puppeteer.base import BaseLib
-
-
-class Places(BaseLib):
- """Low-level access to several bookmark and history related actions."""
-
- BookmarkFolders = namedtuple('bookmark_folders',
- ['root', 'menu', 'toolbar', 'unfiled'])
- bookmark_folders = BookmarkFolders('root________', 'menu________',
- 'toolbar_____', 'unfiled_____')
-
- # Bookmark related helpers #
-
- def is_bookmarked(self, url):
- """Check if the given URL is bookmarked.
-
- :param url: The URL to Check
-
- :returns: True, if the URL is a bookmark
- """
- return self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
-
- PlacesUtils.bookmarks.fetch({url: arguments[0]}).then(bm => {
- marionetteScriptFinished(bm != null);
- });
- """, script_args=[url])
-
- def get_folder_ids_for_url(self, url):
- """Retrieve the folder ids where the given URL has been bookmarked in.
-
- :param url: URL of the bookmark
-
- :returns: List of folder ids
- """
- return self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
-
- let folderGuids = []
-
- function onResult(bm) {
- folderGuids.push(bm.parentGuid);
- }
-
- PlacesUtils.bookmarks.fetch({url: arguments[0]}, onResult).then(() => {
- marionetteScriptFinished(folderGuids);
- });
- """, script_args=[url])
-
- def is_bookmark_star_button_ready(self):
- """Check if the status of the star-button is not updating.
-
- :returns: True, if the button is ready
- """
- return self.marionette.execute_script("""
- let button = window.BookmarkingUI;
-
- return button.status !== button.STATUS_UPDATING;
- """)
-
- def restore_default_bookmarks(self):
- """Restore the default bookmarks for the current profile."""
- retval = self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
-
- // Default bookmarks.html file is stored inside omni.jar,
- // so get it via a resource URI
- let defaultBookmarks = 'chrome://browser/locale/bookmarks.html';
-
- // Trigger the import of the default bookmarks
- BookmarkHTMLUtils.importFromURL(defaultBookmarks, true)
- .then(() => marionetteScriptFinished(true))
- .catch(() => marionetteScriptFinished(false));
- """, script_timeout=10000)
-
- if not retval:
- raise MarionetteException("Restore Default Bookmarks failed")
-
- # Browser history related helpers #
-
- def get_all_urls_in_history(self):
- """Retrieve any URLs which have been stored in the history."""
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
-
- let options = PlacesUtils.history.getNewQueryOptions();
- let root = PlacesUtils.history.executeQuery(
- PlacesUtils.history.getNewQuery(), options).root;
- let urls = [];
-
- root.containerOpen = true;
- for (let i = 0; i < root.childCount; i++) {
- urls.push(root.getChild(i).uri)
- }
- root.containerOpen = false;
-
- return urls;
- """)
-
- def remove_all_history(self):
- """Remove all history items."""
- retval = self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
-
- PlacesUtils.history.clear()
- .then(() => marionetteScriptFinished(true))
- .catch(() => marionetteScriptFinished(false));
- """, script_timeout=10000)
-
- if not retval:
- raise MarionetteException("Removing all history failed")
-
- def wait_for_visited(self, urls, callback):
- """Wait until all passed-in urls have been visited.
-
- :param urls: List of URLs which need to be visited and indexed
-
- :param callback: Method to execute which triggers loading of the URLs
- """
- # Bug 1121691: Needs observer handling support with callback first
- # Until then we have to wait about 4s to ensure the page has been indexed
- callback()
- sleep(4)
-
- # Plugin related helpers #
-
- def clear_plugin_data(self):
- """Clear any kind of locally stored data from plugins."""
- self.marionette.execute_script("""
- let host = Components.classes["@mozilla.org/plugin/host;1"]
- .getService(Components.interfaces.nsIPluginHost);
- let tags = host.getPluginTags();
-
- tags.forEach(aTag => {
- try {
- host.clearSiteData(aTag, null, Components.interfaces.nsIPluginHost
- .FLAG_CLEAR_ALL, -1);
- } catch (ex) {
- }
- });
- """)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/security.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/security.py
deleted file mode 100644
index 7f6532a08c..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/security.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# 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 re
-
-from firefox_puppeteer.base import BaseLib
-from firefox_puppeteer.errors import NoCertificateError
-
-
-class Security(BaseLib):
- """Low-level access to security (SSL, TLS) related information."""
-
- # Security related helpers #
-
- def get_address_from_certificate(self, certificate):
- """Retrieves the address of the organization from the certificate information.
-
- The returned address may be `None` in case of no address found, or a dictionary
- with the following entries: `city`, `country`, `postal_code`, `state`, `street`.
-
- :param certificate: A JSON object representing the certificate, which can usually be
- retrieved via the current tab: `self.browser.tabbar.selected_tab.certificate`.
-
- :returns: Address details as dictionary
- """
- regex = re.compile('.*?L=(?P<city>.+?),ST=(?P<state>.+?),C=(?P<country>.+?)'
- ',postalCode=(?P<postal_code>.+?),STREET=(?P<street>.+?)'
- ',serial')
- results = regex.search(certificate['subjectName'])
-
- return results.groupdict() if results else results
-
- def get_certificate_for_page(self, tab_element):
- """The SSL certificate assiciated with the loaded web page in the given tab.
-
- :param tab_element: The inner tab DOM element.
-
- :returns: Certificate details as JSON object.
- """
- cert = self.marionette.execute_script("""
- var securityUI = arguments[0].linkedBrowser.securityUI;
- var status = securityUI.QueryInterface(Components.interfaces.nsISSLStatusProvider)
- .SSLStatus;
-
- return status ? status.serverCert : null;
- """, script_args=[tab_element])
-
- uri = self.marionette.execute_script("""
- return arguments[0].linkedBrowser.currentURI.spec;
- """, script_args=[tab_element])
-
- if cert is None:
- raise NoCertificateError('No certificate found for "{}"'.format(uri))
-
- return cert
-
- def get_domain_from_common_name(self, common_name):
- """Retrieves the domain associated with a page's security certificate from the common name.
-
- :param certificate: A string containing the certificate's common name, which can usually
- be retrieved like so: `certificate['commonName']`.
-
- :returns: Domain as string
- """
- return self.marionette.execute_script("""
- return Services.eTLD.getBaseDomainFromHost(arguments[0]);
- """, script_args=[common_name])
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py
deleted file mode 100644
index 0b90af0d85..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# 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 ConfigParser
-import os
-import re
-
-import mozinfo
-
-from firefox_puppeteer.base import BaseLib
-from firefox_puppeteer.api.appinfo import AppInfo
-
-
-class ActiveUpdate(BaseLib):
-
- def __getattr__(self, attr):
- value = self.marionette.execute_script("""
- let ums = Components.classes['@mozilla.org/updates/update-manager;1']
- .getService(Components.interfaces.nsIUpdateManager);
- return ums.activeUpdate[arguments[0]];
- """, script_args=[attr])
-
- if value:
- return value
- else:
- raise AttributeError('{} has no attribute {}'.format(self.__class__.__name__,
- attr))
-
- @property
- def exists(self):
- """Checks if there is an active update.
-
- :returns: True if there is an active update
- """
- active_update = self.marionette.execute_script("""
- let ums = Components.classes['@mozilla.org/updates/update-manager;1']
- .getService(Components.interfaces.nsIUpdateManager);
- return ums.activeUpdate;
- """)
-
- return bool(active_update)
-
- def get_patch_at(self, patch_index):
- """Use nsIUpdate.getPatchAt to return a patch from an update.
-
- :returns: JSON data for an nsIUpdatePatch object
- """
- return self.marionette.execute_script("""
- let ums = Components.classes['@mozilla.org/updates/update-manager;1']
- .getService(Components.interfaces.nsIUpdateManager);
- return ums.activeUpdate.getPatchAt(arguments[0]);
- """, script_args=[patch_index])
-
- @property
- def patch_count(self):
- """Get the patchCount from the active update.
-
- :returns: The patch count
- """
- return self.marionette.execute_script("""
- let ums = Components.classes['@mozilla.org/updates/update-manager;1']
- .getService(Components.interfaces.nsIUpdateManager);
- return ums.activeUpdate.patchCount;
- """)
-
- @property
- def selected_patch(self):
- """Get the selected patch for the active update.
-
- :returns: JSON data for the selected patch
- """
- return self.marionette.execute_script("""
- let ums = Components.classes['@mozilla.org/updates/update-manager;1']
- .getService(Components.interfaces.nsIUpdateManager);
- return ums.activeUpdate.selectedPatch;
- """)
-
-
-class MARChannels(BaseLib):
- """Class to handle the allowed MAR channels as listed in update-settings.ini."""
- INI_SECTION = 'Settings'
- INI_OPTION = 'ACCEPTED_MAR_CHANNEL_IDS'
-
- class MARConfigParser(ConfigParser.ConfigParser):
- """INI parser which allows to read and write MAR config files.
-
- Virtually identical to the original method, but delimit keys and values
- with '=' instead of ' = '
- """
-
- def write(self, fp):
- """Write an .ini-format representation of the configuration state."""
- if self._defaults:
- fp.write("[%s]\n" % ConfigParser.DEFAULTSECT)
- for (key, value) in self._defaults.items():
- fp.write("%s=%s\n" % (key, str(value).replace('\n', '\n\t')))
- fp.write("\n")
- for section in self._sections:
- fp.write("[%s]\n" % section)
- for (key, value) in self._sections[section].items():
- if key == "__name__":
- continue
- if (value is not None) or (self._optcre == self.OPTCRE):
- key = "=".join((key, str(value).replace('\n', '\n\t')))
- fp.write("%s\n" % (key))
- fp.write("\n")
-
- def __init__(self, marionette):
- BaseLib.__init__(self, marionette)
-
- self.config_file_path = self.marionette.execute_script("""
- Components.utils.import('resource://gre/modules/Services.jsm');
-
- let file = Services.dirsvc.get('GreD', Components.interfaces.nsIFile);
- file.append('update-settings.ini');
-
- return file.path;
- """)
-
- self.config = self.MARConfigParser()
- self.config.optionxform = str
-
- @property
- def channels(self):
- """The currently accepted MAR channels.
-
- :returns: A set of channel names
- """
- # Make sure to always read the current file contents
- self.config.read(self.config_file_path)
-
- return set(self.config.get(self.INI_SECTION, self.INI_OPTION).split(','))
-
- @channels.setter
- def channels(self, channels):
- """Set the accepted MAR channels.
-
- :param channels: A set of channel names
- """
- self.config.set(self.INI_SECTION, self.INI_OPTION, ','.join(channels))
- with open(self.config_file_path, 'wb') as configfile:
- self.config.write(configfile)
-
- def add_channels(self, channels):
- """Add additional MAR channels.
-
- :param channels: A set of channel names to add
- """
- self.channels = self.channels | set(channels)
-
- def remove_channels(self, channels):
- """Remove MAR channels.
-
- :param channels: A set of channel names to remove
- """
- self.channels = self.channels - set(channels)
-
-
-class SoftwareUpdate(BaseLib):
- """The SoftwareUpdate API adds support for an easy access to the update process."""
- PREF_APP_DISTRIBUTION = 'distribution.id'
- PREF_APP_DISTRIBUTION_VERSION = 'distribution.version'
- PREF_APP_UPDATE_CHANNEL = 'app.update.channel'
- PREF_APP_UPDATE_URL = 'app.update.url'
- PREF_APP_UPDATE_URL_OVERRIDE = 'app.update.url.override'
- PREF_DISABLED_ADDONS = 'extensions.disabledAddons'
-
- def __init__(self, marionette):
- BaseLib.__init__(self, marionette)
-
- self.app_info = AppInfo(marionette)
-
- self._mar_channels = MARChannels(marionette)
- self._active_update = ActiveUpdate(marionette)
-
- @property
- def ABI(self):
- """Get the customized ABI for the update service.
-
- :returns: ABI version
- """
- abi = self.app_info.XPCOMABI
- if mozinfo.isMac:
- abi += self.marionette.execute_script("""
- let macutils = Components.classes['@mozilla.org/xpcom/mac-utils;1']
- .getService(Components.interfaces.nsIMacUtils);
- if (macutils.isUniversalBinary) {
- return '-u-' + macutils.architecturesInBinary;
- }
- return '';
- """)
-
- return abi
-
- @property
- def active_update(self):
- """ Holds a reference to an :class:`ActiveUpdate` object."""
- return self._active_update
-
- @property
- def allowed(self):
- """Check if the user has permissions to run the software update
-
- :returns: Status if the user has the permissions
- """
- return self.marionette.execute_script("""
- let aus = Components.classes['@mozilla.org/updates/update-service;1']
- .getService(Components.interfaces.nsIApplicationUpdateService);
- return aus.canCheckForUpdates && aus.canApplyUpdates;
- """)
-
- @property
- def build_info(self):
- """Return information of the current build version
-
- :returns: A dictionary of build information
- """
- update_url = self.get_update_url(True)
-
- return {
- 'buildid': self.app_info.appBuildID,
- 'channel': self.update_channel,
- 'disabled_addons': self.marionette.get_pref(self.PREF_DISABLED_ADDONS),
- 'locale': self.app_info.locale,
- 'mar_channels': self.mar_channels.channels,
- 'update_url': update_url,
- 'update_snippet': self.get_update_snippet(update_url),
- 'user_agent': self.app_info.user_agent,
- 'version': self.app_info.version
- }
-
- @property
- def is_complete_update(self):
- """Return true if the offered update is a complete update
-
- :returns: True if the offered update is a complete update
- """
- # Throw when isCompleteUpdate is called without an update. This should
- # never happen except if the test is incorrectly written.
- assert self.active_update.exists, 'An active update has been found'
-
- patch_count = self.active_update.patch_count
- assert patch_count == 1 or patch_count == 2,\
- 'An update must have one or two patches included'
-
- # Ensure Partial and Complete patches produced have unique urls
- if patch_count == 2:
- patch0_url = self.active_update.get_patch_at(0)['URL']
- patch1_url = self.active_update.get_patch_at(1)['URL']
- assert patch0_url != patch1_url,\
- 'Partial and Complete download URLs are different'
-
- return self.active_update.selected_patch['type'] == 'complete'
-
- @property
- def mar_channels(self):
- """ Holds a reference to a :class:`MARChannels` object."""
- return self._mar_channels
-
- @property
- def os_version(self):
- """Returns information about the OS version
-
- :returns: The OS version
- """
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- let osVersion;
- try {
- osVersion = Services.sysinfo.getProperty("name") + " " +
- Services.sysinfo.getProperty("version");
- }
- catch (ex) {
- }
-
- if (osVersion) {
- try {
- osVersion += " (" + Services.sysinfo.getProperty("secondaryLibrary") + ")";
- }
- catch (e) {
- // Not all platforms have a secondary widget library,
- // so an error is nothing to worry about.
- }
- osVersion = encodeURIComponent(osVersion);
- }
- return osVersion;
- """)
-
- @property
- def patch_info(self):
- """ Returns information of the active update in the queue."""
- info = {'channel': self.update_channel}
-
- if (self.active_update.exists):
- info['buildid'] = self.active_update.buildID
- info['is_complete'] = self.is_complete_update
- info['size'] = self.active_update.selected_patch['size']
- info['type'] = self.update_type
- info['url_mirror'] = \
- self.active_update.selected_patch['finalURL'] or 'n/a'
- info['version'] = self.active_update.appVersion
-
- return info
-
- @property
- def staging_directory(self):
- """ Returns the path to the updates staging directory."""
- return self.marionette.execute_script("""
- let aus = Components.classes['@mozilla.org/updates/update-service;1']
- .getService(Components.interfaces.nsIApplicationUpdateService);
- return aus.getUpdatesDirectory().path;
- """)
-
- @property
- def update_channel(self):
- """Return the currently used update channel."""
- return self.marionette.get_pref(self.PREF_APP_UPDATE_CHANNEL,
- default_branch=True)
-
- @update_channel.setter
- def update_channel(self, channel):
- """Set the update channel to be used for update checks.
-
- :param channel: New update channel to use
-
- """
- writer = UpdateChannelWriter(self.marionette)
- writer.set_channel(channel)
-
- @property
- def update_type(self):
- """Returns the type of the active update."""
- return self.active_update.type
-
- def force_fallback(self):
- """Update the update.status file and set the status to 'failed:6'"""
- with open(os.path.join(self.staging_directory, 'update.status'), 'w') as f:
- f.write('failed: 6\n')
-
- def get_update_snippet(self, update_url):
- """Retrieve contents of the update snippet.
-
- :param update_url: URL to the update snippet
- """
- snippet = None
- try:
- import urllib2
- response = urllib2.urlopen(update_url)
- snippet = response.read()
- except Exception:
- pass
-
- return snippet
-
- def get_update_url(self, force=False):
- """Retrieve the AUS update URL the update snippet is retrieved from.
-
- :param force: Boolean flag to force an update check
-
- :returns: The URL of the update snippet
- """
- url = self.marionette.get_pref(self.PREF_APP_UPDATE_URL_OVERRIDE)
- if not url:
- url = self.marionette.get_pref(self.PREF_APP_UPDATE_URL)
-
- # Format the URL by replacing placeholders
- url = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/UpdateUtils.jsm")
- return UpdateUtils.formatUpdateURL(arguments[0]);
- """, script_args=[url])
-
- if force:
- if '?' in url:
- url += '&'
- else:
- url += '?'
- url += 'force=1'
-
- return url
-
-
-class UpdateChannelWriter(BaseLib):
- """Class to handle the update channel as listed in channel-prefs.js"""
- REGEX_UPDATE_CHANNEL = re.compile(r'("app\.update\.channel", ")([^"].*)(?=")')
-
- def __init__(self, *args, **kwargs):
- BaseLib.__init__(self, *args, **kwargs)
-
- self.file_path = self.marionette.execute_script("""
- Components.utils.import('resource://gre/modules/Services.jsm');
-
- let file = Services.dirsvc.get('PrfDef', Components.interfaces.nsIFile);
- file.append('channel-prefs.js');
-
- return file.path;
- """)
-
- def set_channel(self, channel):
- """Set default update channel.
-
- :param channel: New default update channel
- """
- with open(self.file_path) as f:
- file_contents = f.read()
-
- new_content = re.sub(
- self.REGEX_UPDATE_CHANNEL, r'\g<1>' + channel, file_contents)
- with open(self.file_path, 'w') as f:
- f.write(new_content)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/utils.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/utils.py
deleted file mode 100644
index 2b4ef07669..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/utils.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# 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.base import BaseLib
-
-
-class Utils(BaseLib):
- """Low-level access to utility actions."""
-
- def __init__(self, *args, **kwargs):
- super(Utils, self).__init__(*args, **kwargs)
-
- self._permissions = Permissions(self.marionette)
-
- @property
- def permissions(self):
- """Handling of various permissions for hosts.
-
- :returns: Instance of the Permissions class.
- """
- return self._permissions
-
- def compare_version(self, a, b):
- """Compare two version strings.
-
- :param a: The first version.
- :param b: The second version.
-
- :returns: -1 if a is smaller than b, 0 if equal, and 1 if larger.
- """
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- return Services.vc.compare(arguments[0], arguments[1]);
- """, script_args=[a, b])
-
- def sanitize(self, data_type):
- """Sanitize user data, including cache, cookies, offlineApps, history, formdata,
- downloads, passwords, sessions, siteSettings.
-
- Usage:
- sanitize(): Clears all user data.
- sanitize({ "sessions": True }): Clears only session user data.
-
- more: https://dxr.mozilla.org/mozilla-central/source/browser/base/content/sanitize.js
-
- :param data_type: optional, Information specifying data to be sanitized
- """
-
- with self.marionette.using_context('chrome'):
- result = self.marionette.execute_async_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- var data_type = arguments[0];
-
- var data_type = (typeof data_type === "undefined") ? {} : {
- cache: data_type.cache || false,
- cookies: data_type.cookies || false,
- downloads: data_type.downloads || false,
- formdata: data_type.formdata || false,
- history: data_type.history || false,
- offlineApps: data_type.offlineApps || false,
- passwords: data_type.passwords || false,
- sessions: data_type.sessions || false,
- siteSettings: data_type.siteSettings || false
- };
-
- // Load the sanitize script
- var tempScope = {};
- Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader)
- .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
-
- // Instantiate the Sanitizer
- var s = new tempScope.Sanitizer();
- s.prefDomain = "privacy.cpd.";
- var itemPrefs = Services.prefs.getBranch(s.prefDomain);
-
- // Apply options for what to sanitize
- for (var pref in data_type) {
- itemPrefs.setBoolPref(pref, data_type[pref]);
- };
-
- // Sanitize and wait for the promise to resolve
- var finished = false;
- s.sanitize().then(() => {
- for (let pref in data_type) {
- itemPrefs.clearUserPref(pref);
- };
- marionetteScriptFinished(true);
- }, aError => {
- for (let pref in data_type) {
- itemPrefs.clearUserPref(pref);
- };
- marionetteScriptFinished(false);
- });
- """, script_args=[data_type])
-
- if not result:
- raise MarionetteException('Sanitizing of profile data failed.')
-
-
-class Permissions(BaseLib):
-
- def add(self, host, permission):
- """Add a permission for web host.
-
- Permissions include safe-browsing, install, geolocation, and others described here:
- https://dxr.mozilla.org/mozilla-central/source/browser/modules/SitePermissions.jsm#144
- and elsewhere.
-
- :param host: The web host whose permission will be added.
- :param permission: The type of permission to be added.
- """
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let uri = Services.io.newURI(arguments[0], null, null);
- Services.perms.add(uri, arguments[1],
- Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
- """, script_args=[host, permission])
-
- def remove(self, host, permission):
- """Remove a permission for web host.
-
- Permissions include safe-browsing, install, geolocation, and others described here:
- https://dxr.mozilla.org/mozilla-central/source/browser/modules/SitePermissions.jsm#144
- and elsewhere.
-
- :param host: The web host whose permission will be removed.
- :param permission: The type of permission to be removed.
- """
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
- let uri = Services.io.newURI(arguments[0], null, null);
- Services.perms.remove(uri, arguments[1]);
- """, script_args=[host, permission])
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/base.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/base.py
deleted file mode 100644
index 8c805e2b53..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/base.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# 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):
- self._marionette = marionette
-
- @property
- def marionette(self):
- return self._marionette
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/decorators.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/decorators.py
deleted file mode 100644
index 1cdb64b00a..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/decorators.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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 functools import wraps
-from importlib import import_module
-
-
-class use_class_as_property(object):
- """
- This decorator imports a library module and sets an instance
- of the associated class as an attribute on the Puppeteer
- object and returns it.
-
- Note: return value of the wrapped function is ignored.
- """
- def __init__(self, lib):
- self.lib = lib
- self.mod_name, self.cls_name = self.lib.rsplit('.', 1)
-
- def __call__(self, func):
- @property
- @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.marionette)
- setattr(cls, tag, prop)
- func(cls, *args, **kwargs)
- return prop
- return _
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/errors.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/errors.py
deleted file mode 100644
index a518422e91..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/errors.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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
-
-
-class NoCertificateError(MarionetteException):
- pass
-
-
-class UnexpectedWindowTypeError(MarionetteException):
- pass
-
-
-class UnknownTabError(MarionetteException):
- pass
-
-
-class UnknownWindowError(MarionetteException):
- pass
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/mixins.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/mixins.py
deleted file mode 100644
index 645aa40a37..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/mixins.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# 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.puppeteer import Puppeteer
-from firefox_puppeteer.ui.browser.window import BrowserWindow
-
-
-class PuppeteerMixin(object):
- """Mix-in class for Firefox specific API modules exposed to test scope.
-
- It also provides common set-up and tear-down code for Firefox tests.
-
- Child test case classes are expected to also subclass MarionetteTestCase such
- that PuppeteerMixin is followed by MarionetteTestCase. This will insert the
- Puppeteer mixin before the MarionetteTestCase into the MRO.
-
- example:
- `class MyTestCase(PuppeteerMixin, MarionetteTestCase)`
-
- The key role of MarionetteTestCase is to set self.marionette appropriately
- in `setUp()`. 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 _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:
- message = ('A test must not leak window handles. This test started with '
- '%s open top level browsing contexts, but ended with %s.'
- ' Remaining Tabs URLs:') % (self._start_handle_count, handle_count)
- with self.marionette.using_context('content'):
- for tab in self.marionette.window_handles:
- if tab not in self._init_tab_handles:
- url.append(' %s' % self.marionette.get_url())
- self.assertListEqual(self._init_tab_handles, self.marionette.window_handles,
- message + ','.join(url))
- finally:
- # For clean-up make sure we work on a proper browser window
- if not self.browser or self.browser.closed:
- # Find a proper replacement browser window
- # TODO: We have to make this less error prone in case no browser is open.
- self.browser = self.puppeteer.windows.switch_to(
- lambda win: type(win) is BrowserWindow)
-
- # Ensure to close all the remaining chrome windows to give following
- # tests a proper start condition and make them not fail.
- self.puppeteer.windows.close_all([self.browser])
- self.browser.focus()
-
- # Also close all remaining tabs
- self.browser.tabbar.close_all_tabs([self.browser.tabbar.tabs[0]])
- self.browser.tabbar.tabs[0].switch_to()
-
- def restart(self, **kwargs):
- """Restart Firefox and re-initialize data.
-
- :param flags: Specific restart flags for Firefox
- """
- if kwargs.get('clean'):
- 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.puppeteer.windows.switch_to(lambda win: type(win) is BrowserWindow)
-
- def setUp(self, *args, **kwargs):
- super(PuppeteerMixin, 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.puppeteer = Puppeteer(self.marionette)
- self.browser = self.puppeteer.windows.current
- self.browser.focus()
-
- with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
- # Bug 1312674 - Navigating to about:blank twice can cause a hang in
- # Marionette. So try to always have a known default page loaded.
- self.marionette.navigate('about:')
-
- def tearDown(self, *args, **kwargs):
- self.marionette.set_context('chrome')
-
- try:
- # 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(PuppeteerMixin, self).tearDown(*args, **kwargs)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/puppeteer.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/puppeteer.py
deleted file mode 100644
index 1894a414b8..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/puppeteer.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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 decorators import use_class_as_property
-
-
-class Puppeteer(object):
- """The puppeteer class is used to expose additional API and UI libraries.
-
- Each library can be referenced by its puppeteer name as a member of a
- Puppeteer instance. For example, the `current_window` member of the
- `Browser` class can be accessed via `puppeteer.browser.current_window`.
- """
-
- def __init__(self, marionette):
- self._marionette = marionette
-
- @property
- def 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.
- """
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/__init__.py
+++ /dev/null
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/__init__.py
+++ /dev/null
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py
deleted file mode 100644
index 9d8d90603c..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/deck.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# 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.ui.base import UIBaseLib
-from firefox_puppeteer.ui.deck import Panel
-
-
-class Deck(UIBaseLib):
-
- def _create_panel_for_id(self, panel_id):
- """Creates an instance of :class:`Panel` for the specified panel id.
-
- :param panel_id: The ID of the panel to create an instance of.
-
- :returns: :class:`Panel` instance
- """
- mapping = {'apply': ApplyPanel,
- 'checkForUpdates': CheckForUpdatesPanel,
- '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)(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.
- """
- return self._create_panel_for_id('apply')
-
- @property
- def check_for_updates(self):
- """The :class:`CheckForUpdatesPanel` instance for the check for updates panel.
-
- :returns: :class:`CheckForUpdatesPanel` instance.
- """
- return self._create_panel_for_id('checkForUpdates')
-
- @property
- def checking_for_updates(self):
- """The :class:`CheckingForUpdatesPanel` instance for the checking for updates panel.
-
- :returns: :class:`CheckingForUpdatesPanel` instance.
- """
- return self._create_panel_for_id('checkingForUpdates')
-
- @property
- def download_and_install(self):
- """The :class:`DownloadAndInstallPanel` instance for the download and install panel.
-
- :returns: :class:`DownloadAndInstallPanel` instance.
- """
- return self._create_panel_for_id('downloadAndInstall')
-
- @property
- def download_failed(self):
- """The :class:`DownloadFailedPanel` instance for the download failed panel.
-
- :returns: :class:`DownloadFailedPanel` instance.
- """
- return self._create_panel_for_id('downloadFailed')
-
- @property
- def downloading(self):
- """The :class:`DownloadingPanel` instance for the downloading panel.
-
- :returns: :class:`DownloadingPanel` instance.
- """
- return self._create_panel_for_id('downloading')
-
- @property
- def no_updates_found(self):
- """The :class:`NoUpdatesFoundPanel` instance for the no updates found panel.
-
- :returns: :class:`NoUpdatesFoundPanel` instance.
- """
- return self._create_panel_for_id('noUpdatesFound')
-
- @property
- def panels(self):
- """List of all the :class:`Panel` instances of the current deck.
-
- :returns: List of :class:`Panel` instances.
- """
- panels = self.marionette.execute_script("""
- let deck = arguments[0];
- let panels = [];
-
- for (let index = 0; index < deck.children.length; index++) {
- if (deck.children[index].id) {
- panels.push(deck.children[index].id);
- }
- }
-
- return panels;
- """, script_args=[self.element])
-
- return [self._create_panel_for_id(panel) for panel in panels]
-
- @property
- def selected_index(self):
- """The index of the currently selected panel.
-
- :return: Index of the selected panel.
- """
- return int(self.element.get_property('selectedIndex'))
-
- @property
- def selected_panel(self):
- """A :class:`Panel` instance of the currently selected panel.
-
- :returns: :class:`Panel` instance.
- """
- return self.panels[self.selected_index]
-
-
-class ApplyPanel(Panel):
-
- @property
- def button(self):
- """The DOM element which represents the Update button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'updateButton')
-
-
-class CheckForUpdatesPanel(Panel):
-
- @property
- def button(self):
- """The DOM element which represents the Check for Updates button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'checkForUpdatesButton')
-
-
-class CheckingForUpdatesPanel(Panel):
- pass
-
-
-class DownloadAndInstallPanel(Panel):
-
- @property
- def button(self):
- """The DOM element which represents the Download button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'downloadAndInstallButton')
-
-
-class DownloadFailedPanel(Panel):
- pass
-
-
-class DownloadingPanel(Panel):
- pass
-
-
-class NoUpdatesFoundPanel(Panel):
- pass
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py
deleted file mode 100644
index 25037a4710..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/about_window/window.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.ui.about_window.deck import Deck
-from firefox_puppeteer.ui.windows import BaseWindow, Windows
-
-
-class AboutWindow(BaseWindow):
- """Representation of the About window."""
- window_type = 'Browser:About'
-
- dtds = [
- 'chrome://branding/locale/brand.dtd',
- 'chrome://browser/locale/aboutDialog.dtd',
- ]
-
- @property
- 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(self.marionette, self, deck)
-
-
-Windows.register_window(AboutWindow.window_type, AboutWindow)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/base.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/base.py
deleted file mode 100644
index 622568df98..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/base.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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 firefox_puppeteer.base import BaseLib
-from firefox_puppeteer.ui.windows import BaseWindow
-
-
-class UIBaseLib(BaseLib):
- """A base class for all UI element wrapper classes inside a chrome window."""
-
- def __init__(self, marionette, window, element):
- super(UIBaseLib, self).__init__(marionette)
-
- assert isinstance(window, BaseWindow)
- assert isinstance(element, HTMLElement)
-
- self._window = window
- self._element = element
-
- @property
- def element(self):
- """Returns the reference to the underlying DOM element.
-
- :returns: Reference to the DOM element
- """
- return self._element
-
- @property
- def window(self):
- """Returns the reference to the chrome window.
-
- :returns: :class:`BaseWindow` instance of the chrome window.
- """
- return self._window
-
-
-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
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/__init__.py
deleted file mode 100644
index c580d191c1..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/.
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py
deleted file mode 100644
index 2cf67ce7f8..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from abc import ABCMeta
-
-from marionette_driver import By
-
-from firefox_puppeteer.ui.base import UIBaseLib
-
-
-class BaseNotification(UIBaseLib):
- """Abstract base class for any kind of notification."""
-
- __metaclass__ = ABCMeta
-
- @property
- def close_button(self):
- """Provide access to the close button.
-
- :returns: The close button.
- """
- return self.element.find_element(By.ANON_ATTRIBUTE,
- {'anonid': 'closebutton'})
-
- @property
- def label(self):
- """Provide access to the notification label.
-
- :returns: The notification label.
- """
- return self.element.get_attribute('label')
-
- @property
- def origin(self):
- """Provide access to the notification origin.
-
- :returns: The notification origin.
- """
- return self.element.get_attribute('origin')
-
- def close(self, force=False):
- """Close the notification.
-
- :param force: Optional, if True force close the notification.
- Defaults to False.
- """
- if force:
- self.marionette.execute_script('arguments[0].click()',
- script_args=[self.close_button])
- else:
- self.close_button.click()
-
- self.window.wait_for_notification(None)
-
-
-class AddOnInstallBlockedNotification(BaseNotification):
- """Add-on install blocked notification."""
-
- @property
- def allow_button(self):
- """Provide access to the allow button.
-
- :returns: The allow button.
- """
- return self.element.find_element(
- By.ANON_ATTRIBUTE, {'anonid': 'button'}).find_element(
- By.ANON_ATTRIBUTE, {'anonid': 'button'})
-
-
-class AddOnInstallConfirmationNotification(BaseNotification):
- """Add-on install confirmation notification."""
-
- @property
- def addon_name(self):
- """Provide access to the add-on name.
-
- :returns: The add-on name.
- """
- label = self.element.find_element(
- By.CSS_SELECTOR, '#addon-install-confirmation-content label')
- return label.get_attribute('value')
-
- def cancel_button(self):
- """Provide access to the cancel button.
-
- :returns: The cancel button.
- """
- return self.element.find_element(
- By.ID, 'addon-install-confirmation-cancel')
-
- def install_button(self):
- """Provide access to the install button.
-
- :returns: The install button.
- """
- return self.element.find_element(
- By.ID, 'addon-install-confirmation-accept')
-
-
-class AddOnInstallCompleteNotification(BaseNotification):
- """Add-on install complete notification."""
-
- pass
-
-
-class AddOnInstallFailedNotification(BaseNotification):
- """Add-on install failed notification."""
-
- pass
-
-
-class AddOnProgressNotification(BaseNotification):
- """Add-on progress notification."""
-
- pass
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py
deleted file mode 100644
index 4fec98d995..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/tabbar.py
+++ /dev/null
@@ -1,388 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from marionette_driver import (
- By, Wait
-)
-
-from marionette_driver.errors import NoSuchElementException
-
-import firefox_puppeteer.errors as errors
-
-from firefox_puppeteer.api.security import Security
-from firefox_puppeteer.ui.base import UIBaseLib, DOMElement
-
-
-class TabBar(UIBaseLib):
- """Wraps the tabs toolbar DOM element inside a browser window."""
-
- # Properties for visual elements of the tabs toolbar #
-
- @property
- def menupanel(self):
- """A :class:`MenuPanel` instance which represents the menu panel
- at the far right side of the tabs toolbar.
-
- :returns: :class:`MenuPanel` instance.
- """
- return MenuPanel(self.marionette, self.window)
-
- @property
- def newtab_button(self):
- """The DOM element which represents the new tab button.
-
- :returns: Reference to the new tab button.
- """
- return self.toolbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'tabs-newtab-button'})
-
- @property
- def tabs(self):
- """List of all the :class:`Tab` instances of the current browser window.
-
- :returns: List of :class:`Tab` instances.
- """
- tabs = self.toolbar.find_elements(By.TAG_NAME, 'tab')
-
- return [Tab(self.marionette, self.window, tab) for tab in tabs]
-
- @property
- def toolbar(self):
- """The DOM element which represents the tab toolbar.
-
- :returns: Reference to the tabs toolbar.
- """
- return self.element
-
- # Properties for helpers when working with the tabs toolbar #
-
- @property
- def selected_index(self):
- """The index of the currently selected tab.
-
- :return: Index of the selected tab.
- """
- return int(self.toolbar.get_property('selectedIndex'))
-
- @property
- def selected_tab(self):
- """A :class:`Tab` instance of the currently selected tab.
-
- :returns: :class:`Tab` instance.
- """
- return self.tabs[self.selected_index]
-
- # Methods for helpers when working with the tabs toolbar #
-
- def close_all_tabs(self, exceptions=None):
- """Forces closing of all open tabs.
-
- There is an optional `exceptions` list, which can be used to exclude
- specific tabs from being closed.
-
- :param exceptions: Optional, list of :class:`Tab` instances not to close.
- """
- # Get handles from tab exceptions, and find those which can be closed
- for tab in self.tabs:
- if tab not in exceptions:
- tab.close(force=True)
-
- def close_tab(self, tab=None, trigger='menu', force=False):
- """Closes the tab by using the specified trigger.
-
- By default the currently selected tab will be closed. If another :class:`Tab`
- is specified, that one will be closed instead. Also when the tab is closed, a
- :func:`switch_to` call is automatically performed, so that the new selected
- tab becomes active.
-
- :param tab: Optional, the :class:`Tab` instance to close. Defaults to
- the currently selected tab.
-
- :param trigger: Optional, method to close the current tab. This can
- be a string with one of `menu` or `shortcut`, or a callback which gets triggered
- with the :class:`Tab` as parameter. Defaults to `menu`.
-
- :param force: Optional, forces the closing of the window by using the Gecko API.
- Defaults to `False`.
- """
- tab = tab or self.selected_tab
- tab.close(trigger, force)
-
- def open_tab(self, trigger='menu'):
- """Opens a new tab in the current browser window.
-
- If the tab opens in the foreground, a call to :func:`switch_to` will
- automatically be performed. But if it opens in the background, the current
- tab will keep its focus.
-
- :param trigger: Optional, method to open the new tab. This can
- be a string with one of `menu`, `button` or `shortcut`, or a callback
- which gets triggered with the current :class:`Tab` as parameter.
- Defaults to `menu`.
-
- :returns: :class:`Tab` instance for the opened tab.
- """
- start_handles = self.marionette.window_handles
-
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(self.selected_tab)
- elif trigger == 'button':
- self.window.tabbar.newtab_button.click()
- elif trigger == 'menu':
- self.window.menubar.select_by_id('file-menu',
- 'menu_newNavigatorTab')
- elif trigger == 'shortcut':
- self.window.send_shortcut(self.window.localize_entity('tabCmd.commandkey'),
- accel=True)
- # elif - need to add other cases
- else:
- raise ValueError('Unknown opening method: "%s"' % trigger)
-
- # TODO: Needs to be replaced with event handling code (bug 1121705)
- Wait(self.marionette).until(
- lambda mn: len(mn.window_handles) == len(start_handles) + 1,
- message='No new tab has been opened.')
-
- handles = self.marionette.window_handles
- [new_handle] = list(set(handles) - set(start_handles))
- [new_tab] = [tab for tab in self.tabs if tab.handle == new_handle]
-
- # if the new tab is the currently selected tab, switch to it
- if new_tab == self.selected_tab:
- new_tab.switch_to()
-
- return new_tab
-
- def switch_to(self, target):
- """Switches the context to the specified tab.
-
- :param target: The tab to switch to. `target` can be an index, a :class:`Tab`
- instance, or a callback that returns True in the context of the desired tab.
-
- :returns: Instance of the selected :class:`Tab`.
- """
- start_handle = self.marionette.current_window_handle
-
- if isinstance(target, int):
- return self.tabs[target].switch_to()
- elif isinstance(target, Tab):
- return target.switch_to()
- if callable(target):
- for tab in self.tabs:
- tab.switch_to()
- if target(tab):
- return tab
-
- self.marionette.switch_to_window(start_handle)
- raise errors.UnknownTabError("No tab found for '{}'".format(target))
-
- raise ValueError("The 'target' parameter must either be an index or a callable")
-
- @staticmethod
- def get_handle_for_tab(marionette, tab_element):
- """Retrieves the marionette handle for the given :class:`Tab` instance.
-
- :param marionette: An instance of the Marionette client.
-
- :param tab_element: The DOM element corresponding to a tab inside the tabs toolbar.
-
- :returns: `handle` of the tab.
- """
- # TODO: This introduces coupling with marionette's window handles
- # implementation. To avoid this, the capacity to get the XUL
- # element corresponding to the active window according to
- # marionette or a similar ability should be added to marionette.
- handle = marionette.execute_script("""
- let win = arguments[0].linkedBrowser;
- if (!win) {
- return null;
- }
- return win.outerWindowID.toString();
- """, script_args=[tab_element])
-
- return handle
-
-
-class Tab(UIBaseLib):
- """Wraps a tab DOM element."""
-
- def __init__(self, marionette, window, element):
- super(Tab, self).__init__(marionette, window, element)
-
- self._security = Security(self.marionette)
- self._handle = None
-
- # Properties for visual elements of tabs #
-
- @property
- def close_button(self):
- """The DOM element which represents the tab close button.
-
- :returns: Reference to the tab close button.
- """
- return self.tab_element.find_element(By.ANON_ATTRIBUTE, {'anonid': 'close-button'})
-
- @property
- def tab_element(self):
- """The inner tab DOM element.
-
- :returns: Tab DOM element.
- """
- return self.element
-
- # Properties for backend values
-
- @property
- def location(self):
- """Returns the current URL
-
- :returns: Current URL
- """
- self.switch_to()
-
- return self.marionette.execute_script("""
- return arguments[0].linkedBrowser.currentURI.spec;
- """, script_args=[self.tab_element])
-
- @property
- def certificate(self):
- """The SSL certificate assiciated with the loaded web page.
-
- :returns: Certificate details as JSON blob.
- """
- self.switch_to()
-
- return self._security.get_certificate_for_page(self.tab_element)
-
- # Properties for helpers when working with tabs #
-
- @property
- def handle(self):
- """The `handle` of the content window.
-
- :returns: content window `handle`.
- """
- # If no handle has been set yet, wait until it is available
- if not self._handle:
- self._handle = Wait(self.marionette).until(
- lambda mn: TabBar.get_handle_for_tab(mn, self.element),
- message='Tab handle could not be found.')
-
- return self._handle
-
- @property
- def selected(self):
- """Checks if the tab is selected.
-
- :return: `True` if the tab is selected.
- """
- return self.marionette.execute_script("""
- return arguments[0].hasAttribute('selected');
- """, script_args=[self.tab_element])
-
- # Methods for helpers when working with tabs #
-
- def __eq__(self, other):
- return self.handle == other.handle
-
- def close(self, trigger='menu', force=False):
- """Closes the tab by using the specified trigger.
-
- When the tab is closed a :func:`switch_to` call is automatically performed, so that
- the new selected tab becomes active.
-
- :param trigger: Optional, method in how to close the tab. This can
- be a string with one of `button`, `menu` or `shortcut`, or a callback which
- gets triggered with the current :class:`Tab` as parameter. Defaults to `menu`.
-
- :param force: Optional, forces the closing of the window by using the Gecko API.
- Defaults to `False`.
- """
- handle = self.handle
- start_handles = self.marionette.window_handles
-
- self.switch_to()
-
- if force:
- self.marionette.close()
- elif callable(trigger):
- trigger(self)
- elif trigger == 'button':
- self.close_button.click()
- elif trigger == 'menu':
- self.window.menubar.select_by_id('file-menu', 'menu_close')
- elif trigger == 'shortcut':
- self.window.send_shortcut(self.window.localize_entity('closeCmd.key'),
- accel=True)
- else:
- raise ValueError('Unknown closing method: "%s"' % trigger)
-
- Wait(self.marionette).until(
- lambda _: len(self.window.tabbar.tabs) == len(start_handles) - 1,
- message='Tab with handle "%s" has not been closed.' % handle)
-
- # Ensure to switch to the window handle which represents the new selected tab
- self.window.tabbar.selected_tab.switch_to()
-
- def select(self):
- """Selects the tab and sets the focus to it."""
- self.tab_element.click()
- self.switch_to()
-
- # Bug 1121705: Maybe we have to wait for TabSelect event
- Wait(self.marionette).until(
- lambda _: self.selected,
- message='Tab with handle "%s" could not be selected.' % self.handle)
-
- def switch_to(self):
- """Switches the context of Marionette to this tab.
-
- Please keep in mind that calling this method will not select the tab.
- Use the :func:`~Tab.select` method instead.
- """
- self.marionette.switch_to_window(self.handle)
-
-
-class MenuPanel(UIBaseLib):
-
- @property
- def popup(self):
- """
- :returns: The :class:`MenuPanelElement`.
- """
- popup = self.marionette.find_element(By.ID, 'PanelUI-popup')
- return self.MenuPanelElement(popup)
-
- class MenuPanelElement(DOMElement):
- """Wraps the menu panel."""
- _buttons = None
-
- @property
- def buttons(self):
- """
- :returns: A list of all the clickable buttons in the menu panel.
- """
- if not self._buttons:
- self._buttons = (self.find_element(By.ID, 'PanelUI-multiView')
- .find_element(By.ANON_ATTRIBUTE,
- {'anonid': 'viewContainer'})
- .find_elements(By.TAG_NAME,
- 'toolbarbutton'))
- return self._buttons
-
- def click(self, target=None):
- """
- Overrides HTMLElement.click to provide a target to click.
-
- :param target: The label associated with the button to click on,
- e.g., `New Private Window`.
- """
- if not target:
- return DOMElement.click(self)
-
- for button in self.buttons:
- if button.get_attribute('label') == target:
- return button.click()
- raise NoSuchElementException('Could not find "{}"" in the '
- 'menu panel UI'.format(target))
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py
deleted file mode 100644
index d490e488f1..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/toolbars.py
+++ /dev/null
@@ -1,641 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from marionette_driver import By, keys, Wait
-
-from firefox_puppeteer.ui.base import UIBaseLib
-
-
-class NavBar(UIBaseLib):
- """Provides access to the DOM elements contained in the
- navigation bar as well as the location bar."""
-
- def __init__(self, *args, **kwargs):
- super(NavBar, self).__init__(*args, **kwargs)
-
- self._locationbar = None
-
- @property
- def back_button(self):
- """Provides access to the DOM element back button in the navbar.
-
- :returns: Reference to the back button.
- """
- return self.marionette.find_element(By.ID, 'back-button')
-
- @property
- def forward_button(self):
- """Provides access to the DOM element forward button in the navbar.
-
- :returns: Reference to the forward button.
- """
- return self.marionette.find_element(By.ID, 'forward-button')
-
- @property
- def home_button(self):
- """Provides access to the DOM element home button in the navbar.
-
- :returns: Reference to the home button element
- """
- return self.marionette.find_element(By.ID, 'home-button')
-
- @property
- def locationbar(self):
- """Provides access to the DOM elements contained in the
- locationbar.
-
- See the :class:`LocationBar` reference.
- """
- if not self._locationbar:
- urlbar = self.marionette.find_element(By.ID, 'urlbar')
- self._locationbar = LocationBar(self.marionette, self.window, urlbar)
-
- return self._locationbar
-
- @property
- def menu_button(self):
- """Provides access to the DOM element menu button in the navbar.
-
- :returns: Reference to the menu button element.
- """
- return self.marionette.find_element(By.ID, 'PanelUI-menu-button')
-
- @property
- def toolbar(self):
- """The DOM element which represents the navigation toolbar.
-
- :returns: Reference to the navigation toolbar.
- """
- return self.element
-
-
-class LocationBar(UIBaseLib):
- """Provides access to and methods for the DOM elements contained in the
- locationbar (the text area of the ui that typically displays the current url)."""
-
- def __init__(self, *args, **kwargs):
- super(LocationBar, self).__init__(*args, **kwargs)
-
- self._autocomplete_results = None
- self._identity_popup = None
-
- @property
- def autocomplete_results(self):
- """Provides access to and methods for the location bar
- autocomplete results.
-
- See the :class:`AutocompleteResults` reference."""
- if not self._autocomplete_results:
- popup = self.marionette.find_element(By.ID, 'PopupAutoCompleteRichResult')
- self._autocomplete_results = AutocompleteResults(self.marionette,
- self.window, popup)
-
- return self._autocomplete_results
-
- def clear(self):
- """Clears the contents of the url bar (via the DELETE shortcut)."""
- self.focus('shortcut')
- self.urlbar.send_keys(keys.Keys.DELETE)
- Wait(self.marionette).until(
- lambda _: self.value == '',
- message='Contents of location bar could not be cleared.')
-
- def close_context_menu(self):
- """Closes the Location Bar context menu by a key event."""
- # TODO: This method should be implemented via the menu API.
- self.contextmenu.send_keys(keys.Keys.ESCAPE)
-
- @property
- def connection_icon(self):
- """ Provides access to the urlbar connection icon.
-
- :returns: Reference to the connection icon element.
- """
- return self.marionette.find_element(By.ID, 'connection-icon')
-
- @property
- def contextmenu(self):
- """Provides access to the urlbar context menu.
-
- :returns: Reference to the urlbar context menu.
- """
- # TODO: This method should be implemented via the menu API.
- parent = self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'textbox-input-box'})
- return parent.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input-box-contextmenu'})
-
- @property
- def focused(self):
- """Checks the focus state of the location bar.
-
- :returns: `True` if focused, otherwise `False`
- """
- return self.urlbar.get_attribute('focused') == 'true'
-
- @property
- def identity_icon(self):
- """ Provides access to the urlbar identity icon.
-
- :returns: Reference to the identity icon element.
- """
- return self.marionette.find_element(By.ID, 'identity-icon')
-
- def focus(self, event='click'):
- """Focus the location bar according to the provided event.
-
- :param eventt: The event to synthesize in order to focus the urlbar
- (one of `click` or `shortcut`).
- """
- if event == 'click':
- self.urlbar.click()
- elif event == 'shortcut':
- cmd_key = self.window.localize_entity('openCmd.commandkey')
- self.window.send_shortcut(cmd_key, accel=True)
- else:
- raise ValueError("An unknown event type was passed: %s" % event)
-
- Wait(self.marionette).until(
- lambda _: self.focused,
- message='Location bar has not be focused.')
-
- def get_contextmenu_entry(self, action):
- """Retrieves the urlbar context menu entry corresponding
- to the given action.
-
- :param action: The action corresponding to the retrieved value.
- :returns: Reference to the urlbar contextmenu entry.
- """
- # TODO: This method should be implemented via the menu API.
- entries = self.contextmenu.find_elements(By.CSS_SELECTOR, 'menuitem')
- filter_on = 'cmd_%s' % action
- found = [e for e in entries if e.get_attribute('cmd') == filter_on]
- return found[0] if len(found) else None
-
- @property
- def history_drop_marker(self):
- """Provides access to the history drop marker.
-
- :returns: Reference to the history drop marker.
- """
- return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'historydropmarker'})
-
- @property
- def identity_box(self):
- """The DOM element which represents the identity box.
-
- :returns: Reference to the identity box.
- """
- return self.marionette.find_element(By.ID, 'identity-box')
-
- @property
- def identity_country_label(self):
- """The DOM element which represents the identity icon country label.
-
- :returns: Reference to the identity icon country label.
- """
- return self.marionette.find_element(By.ID, 'identity-icon-country-label')
-
- @property
- def identity_organization_label(self):
- """The DOM element which represents the identity icon label.
-
- :returns: Reference to the identity icon label.
- """
- return self.marionette.find_element(By.ID, 'identity-icon-label')
-
- @property
- def identity_popup(self):
- """Provides utility members for accessing and manipulating the
- identity popup.
-
- See the :class:`IdentityPopup` reference.
- """
- if not self._identity_popup:
- popup = self.marionette.find_element(By.ID, 'identity-popup')
- self._identity_popup = IdentityPopup(self.marionette,
- self.window, popup)
-
- return self._identity_popup
-
- def load_url(self, url):
- """Load the specified url in the location bar by synthesized
- keystrokes.
-
- :param url: The url to load.
- """
- self.clear()
- self.focus('shortcut')
- self.urlbar.send_keys(url + keys.Keys.ENTER)
-
- @property
- def notification_popup(self):
- """Provides access to the DOM element notification popup.
-
- :returns: Reference to the notification popup.
- """
- return self.marionette.find_element(By.ID, "notification-popup")
-
- def open_identity_popup(self):
- """Open the identity popup."""
- self.identity_box.click()
- Wait(self.marionette).until(
- lambda _: self.identity_popup.is_open,
- message='Identity popup has not been opened.')
-
- @property
- def reload_button(self):
- """Provides access to the DOM element reload button.
-
- :returns: Reference to the reload button.
- """
- return self.marionette.find_element(By.ID, 'urlbar-reload-button')
-
- def reload_url(self, trigger='button', force=False):
- """Reload the currently open page.
-
- :param trigger: The event type to use to cause the reload (one of
- `shortcut`, `shortcut2`, or `button`).
- :param force: Whether to cause a forced reload.
- """
- # TODO: The force parameter is ignored for the moment. Use
- # mouse event modifiers or actions when they're ready.
- # Bug 1097705 tracks this feature in marionette.
- if trigger == 'button':
- self.reload_button.click()
- elif trigger == 'shortcut':
- cmd_key = self.window.localize_entity('reloadCmd.commandkey')
- self.window.send_shortcut(cmd_key)
- elif trigger == 'shortcut2':
- self.window.send_shortcut(keys.Keys.F5)
-
- @property
- def stop_button(self):
- """Provides access to the DOM element stop button.
-
- :returns: Reference to the stop button.
- """
- return self.marionette.find_element(By.ID, 'urlbar-stop-button')
-
- @property
- def urlbar(self):
- """Provides access to the DOM element urlbar.
-
- :returns: Reference to the url bar.
- """
- return self.marionette.find_element(By.ID, 'urlbar')
-
- @property
- def urlbar_input(self):
- """Provides access to the urlbar input element.
-
- :returns: Reference to the urlbar input.
- """
- return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input'})
-
- @property
- def value(self):
- """Provides access to the currently displayed value of the urlbar.
-
- :returns: The urlbar value.
- """
- return self.urlbar.get_property('value')
-
-
-class AutocompleteResults(UIBaseLib):
- """Wraps DOM elements and methods for interacting with autocomplete results."""
-
- def close(self, force=False):
- """Closes the urlbar autocomplete popup.
-
- :param force: If true, the popup is closed by its own hide function,
- otherwise a key event is sent to close the popup.
- """
- if not self.is_open:
- return
-
- if force:
- self.marionette.execute_script("""
- arguments[0].hidePopup();
- """, script_args=[self.element])
- else:
- self.element.send_keys(keys.Keys.ESCAPE)
-
- Wait(self.marionette).until(
- lambda _: not self.is_open,
- message='Autocomplete popup has not been closed.')
-
- def get_matching_text(self, result, match_type):
- """Returns an array of strings of the matching text within an autocomplete
- result in the urlbar.
-
- :param result: The result to inspect for matches.
- :param match_type: The type of match to search for (one of `title` or `url`).
- """
-
- if match_type not in ('title', 'url'):
- raise ValueError('match_type provided must be one of'
- '"title" or "url", not %s' % match_type)
-
- # Search for nodes of the given type with emphasized text
- emphasized_nodes = result.find_elements(
- By.ANON_ATTRIBUTE,
- {'class': 'ac-emphasize-text ac-emphasize-text-%s' % match_type}
- )
-
- return [node.get_property('textContent') for node in emphasized_nodes]
-
- @property
- def visible_results(self):
- """Supplies the list of visible autocomplete result nodes.
-
- :returns: The list of visible results.
- """
- match_count = self.element.get_property('_matchCount')
-
- return self.marionette.execute_script("""
- let rv = [];
- let node = arguments[0];
- let count = arguments[1];
-
- for (let i = 0; i < count; ++i) {
- rv.push(node.getItemAtIndex(i));
- }
-
- return rv;
- """, script_args=[self.results, match_count])
-
- @property
- def is_open(self):
- """Returns whether this popup is currently open.
-
- :returns: True when the popup is open, otherwise false.
- """
- return self.element.get_property('state') == 'open'
-
- @property
- def is_complete(self):
- """Returns when this popup is open and autocomplete results are complete.
-
- :returns: True, when autocomplete results have been populated.
- """
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- let win = Services.focus.activeWindow;
- if (win) {
- return win.gURLBar.controller.searchStatus >=
- Components.interfaces.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
- }
-
- return null;
- """)
-
- @property
- def results(self):
- """
- :returns: The autocomplete result container node.
- """
- return self.element.find_element(By.ANON_ATTRIBUTE,
- {'anonid': 'richlistbox'})
-
- @property
- def selected_index(self):
- """Provides the index of the selected item in the autocomplete list.
-
- :returns: The index.
- """
- return self.results.get_property('selectedIndex')
-
-
-class IdentityPopup(UIBaseLib):
- """Wraps DOM elements and methods for interacting with the identity popup."""
-
- def __init__(self, *args, **kwargs):
- super(IdentityPopup, self).__init__(*args, **kwargs)
-
- self._view = None
-
- @property
- def is_open(self):
- """Returns whether this popup is currently open.
-
- :returns: True when the popup is open, otherwise false.
- """
- return self.element.get_property('state') == 'open'
-
- def close(self, force=False):
- """Closes the identity popup by hitting the escape key.
-
- :param force: Optional, If `True` force close the popup.
- Defaults to `False`
- """
- if not self.is_open:
- return
-
- if force:
- self.marionette.execute_script("""
- arguments[0].hidePopup();
- """, script_args=[self.element])
- else:
- self.element.send_keys(keys.Keys.ESCAPE)
-
- Wait(self.marionette).until(
- lambda _: not self.is_open,
- message='Identity popup has not been closed.')
-
- @property
- def view(self):
- """Provides utility members for accessing and manipulating the
- identity popup's multi view.
-
- See the :class:`IdentityPopupMultiView` reference.
- """
- if not self._view:
- view = self.marionette.find_element(By.ID, 'identity-popup-multiView')
- self._view = IdentityPopupMultiView(self.marionette, self.window, view)
-
- return self._view
-
-
-class IdentityPopupMultiView(UIBaseLib):
-
- def _create_view_for_id(self, view_id):
- """Creates an instance of :class:`IdentityPopupView` for the specified view id.
-
- :param view_id: The ID of the view to create an instance of.
-
- :returns: :class:`IdentityPopupView` instance
- """
- mapping = {'identity-popup-mainView': IdentityPopupMainView,
- 'identity-popup-securityView': IdentityPopupSecurityView,
- }
-
- view = self.marionette.find_element(By.ID, view_id)
- return mapping.get(view_id, IdentityPopupView)(self.marionette, self.window, view)
-
- @property
- def main(self):
- """The DOM element which represents the main view.
-
- :returns: Reference to the main view.
- """
- return self._create_view_for_id('identity-popup-mainView')
-
- @property
- def security(self):
- """The DOM element which represents the security view.
-
- :returns: Reference to the security view.
- """
- return self._create_view_for_id('identity-popup-securityView')
-
-
-class IdentityPopupView(UIBaseLib):
-
- @property
- def selected(self):
- """Checks if the view is selected.
-
- :return: `True` if the view is selected.
- """
- return self.element.get_attribute('current') == 'true'
-
-
-class IdentityPopupMainView(IdentityPopupView):
-
- @property
- def selected(self):
- """Checks if the view is selected.
-
- :return: `True` if the view is selected.
- """
- return self.marionette.execute_script("""
- return arguments[0].panelMultiView.getAttribute('viewtype') == 'main';
- """, script_args=[self.element])
-
- @property
- def expander(self):
- """The DOM element which represents the expander button for the security content.
-
- :returns: Reference to the identity popup expander button.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-expander')
-
- @property
- def host(self):
- """The DOM element which represents the identity-popup content host.
-
- :returns: Reference to the identity-popup content host.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
-
- @property
- def insecure_connection_label(self):
- """The DOM element which represents the identity popup insecure connection label.
-
- :returns: Reference to the identity-popup insecure connection label.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
-
- @property
- def internal_connection_label(self):
- """The DOM element which represents the identity popup internal connection label.
-
- :returns: Reference to the identity-popup internal connection label.
- """
- return self.element.find_element(By.CSS_SELECTOR, 'description[when-connection=chrome]')
-
- @property
- def permissions(self):
- """The DOM element which represents the identity-popup permissions content.
-
- :returns: Reference to the identity-popup permissions.
- """
- return self.element.find_element(By.ID, 'identity-popup-permissions-content')
-
- @property
- def secure_connection_label(self):
- """The DOM element which represents the identity popup secure connection label.
-
- :returns: Reference to the identity-popup secure connection label.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
-
-
-class IdentityPopupSecurityView(IdentityPopupView):
-
- @property
- def disable_mixed_content_blocking_button(self):
- """The DOM element which represents the disable mixed content blocking button.
-
- :returns: Reference to the disable mixed content blocking button.
- """
- return self.element.find_element(By.CSS_SELECTOR,
- 'button[when-mixedcontent=active-blocked]')
-
- @property
- def enable_mixed_content_blocking_button(self):
- """The DOM element which represents the enable mixed content blocking button.
-
- :returns: Reference to the enable mixed content blocking button.
- """
- return self.element.find_element(By.CSS_SELECTOR,
- 'button[when-mixedcontent=active-loaded]')
-
- @property
- def host(self):
- """The DOM element which represents the identity-popup content host.
-
- :returns: Reference to the identity-popup content host.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
-
- @property
- def insecure_connection_label(self):
- """The DOM element which represents the identity popup insecure connection label.
-
- :returns: Reference to the identity-popup insecure connection label.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
-
- @property
- def more_info_button(self):
- """The DOM element which represents the identity-popup more info button.
-
- :returns: Reference to the identity-popup more info button.
- """
- label = self.window.localize_entity('identity.moreInfoLinkText2')
-
- return self.element.find_element(By.CSS_SELECTOR, u'button[label="{}"]'.format(label))
-
- @property
- def owner(self):
- """The DOM element which represents the identity-popup content owner.
-
- :returns: Reference to the identity-popup content owner.
- """
- return self.element.find_element(By.ID, 'identity-popup-content-owner')
-
- @property
- def owner_location(self):
- """The DOM element which represents the identity-popup content supplemental.
-
- :returns: Reference to the identity-popup content supplemental.
- """
- return self.element.find_element(By.ID, 'identity-popup-content-supplemental')
-
- @property
- def secure_connection_label(self):
- """The DOM element which represents the identity popup secure connection label.
-
- :returns: Reference to the identity-popup secure connection label.
- """
- return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
-
- @property
- def verifier(self):
- """The DOM element which represents the identity-popup content verifier.
-
- :returns: Reference to the identity-popup content verifier.
- """
- return self.element.find_element(By.ID, 'identity-popup-content-verifier')
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
deleted file mode 100644
index 728a2fd20c..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from marionette_driver import By, Wait
-from marionette_driver.errors import NoSuchElementException
-
-from firefox_puppeteer.ui.about_window.window import AboutWindow
-from firefox_puppeteer.ui.browser.notifications import (
- AddOnInstallBlockedNotification,
- AddOnInstallConfirmationNotification,
- AddOnInstallCompleteNotification,
- AddOnInstallFailedNotification,
- AddOnProgressNotification,
- BaseNotification)
-from firefox_puppeteer.ui.browser.tabbar import TabBar
-from firefox_puppeteer.ui.browser.toolbars import NavBar
-from firefox_puppeteer.ui.pageinfo.window import PageInfoWindow
-from firefox_puppeteer.ui.windows import BaseWindow, Windows
-
-
-class BrowserWindow(BaseWindow):
- """Representation of a browser window."""
-
- window_type = 'navigator:browser'
-
- dtds = [
- 'chrome://branding/locale/brand.dtd',
- 'chrome://browser/locale/aboutPrivateBrowsing.dtd',
- 'chrome://browser/locale/browser.dtd',
- 'chrome://browser/locale/netError.dtd',
- ]
-
- properties = [
- 'chrome://branding/locale/brand.properties',
- 'chrome://branding/locale/browserconfig.properties',
- 'chrome://browser/locale/browser.properties',
- 'chrome://browser/locale/preferences/preferences.properties',
- 'chrome://global/locale/browser.properties',
- ]
-
- def __init__(self, *args, **kwargs):
- super(BrowserWindow, self).__init__(*args, **kwargs)
-
- self._navbar = None
- self._tabbar = None
-
- @property
- def default_homepage(self):
- """The default homepage as used by the current locale.
-
- :returns: The default homepage for the current locale.
- """
- return self.marionette.get_pref('browser.startup.homepage',
- value_type='nsIPrefLocalizedString')
-
- @property
- def is_private(self):
- """Returns True if this is a Private Browsing window."""
- self.switch_to()
-
- with self.marionette.using_context('chrome'):
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-
- let chromeWindow = arguments[0].ownerDocument.defaultView;
- return PrivateBrowsingUtils.isWindowPrivate(chromeWindow);
- """, script_args=[self.window_element])
-
- @property
- def navbar(self):
- """Provides access to the navigation bar. This is the toolbar containing
- the back, forward and home buttons. It also contains the location bar.
-
- See the :class:`~ui.browser.toolbars.NavBar` reference.
- """
- self.switch_to()
-
- if not self._navbar:
- navbar = self.window_element.find_element(By.ID, 'nav-bar')
- self._navbar = NavBar(self.marionette, self, navbar)
-
- return self._navbar
-
- @property
- def notification(self):
- """Provides access to the currently displayed notification."""
-
- notifications_map = {
- 'addon-install-blocked-notification': AddOnInstallBlockedNotification,
- 'addon-install-confirmation-notification': AddOnInstallConfirmationNotification,
- 'addon-install-complete-notification': AddOnInstallCompleteNotification,
- 'addon-install-failed-notification': AddOnInstallFailedNotification,
- 'addon-progress-notification': AddOnProgressNotification,
- }
-
- try:
- notification = self.window_element.find_element(
- By.CSS_SELECTOR, '#notification-popup popupnotification')
-
- notification_id = notification.get_attribute('id')
- return notifications_map.get(notification_id, BaseNotification)(
- self.marionette, self, notification)
-
- except NoSuchElementException:
- return None # no notification is displayed
-
- def wait_for_notification(self, notification_class=BaseNotification,
- timeout=5):
- """Waits for the specified notification to be displayed.
-
- :param notification_class: Optional, the notification class to wait for.
- If `None` is specified it will wait for any notification to be closed.
- Defaults to `BaseNotification`.
- :param timeout: Optional, how long to wait for the expected notification.
- Defaults to 5 seconds.
- """
- wait = Wait(self.marionette, timeout=timeout)
-
- if notification_class:
- if notification_class is BaseNotification:
- message = 'No notification was shown.'
- else:
- message = '{0} was not shown.'.format(notification_class.__name__)
- wait.until(
- lambda _: isinstance(self.notification, notification_class),
- message=message)
- else:
- message = 'Unexpected notification shown.'
- wait.until(
- lambda _: self.notification is None,
- message='Unexpected notification shown.')
-
- @property
- def tabbar(self):
- """Provides access to the tab bar.
-
- See the :class:`~ui.browser.tabbar.TabBar` reference.
- """
- self.switch_to()
-
- if not self._tabbar:
- tabbrowser = self.window_element.find_element(By.ID, 'tabbrowser-tabs')
- self._tabbar = TabBar(self.marionette, self, tabbrowser)
-
- return self._tabbar
-
- def close(self, trigger='menu', force=False):
- """Closes the current browser window by using the specified trigger.
-
- :param trigger: Optional, method to close the current browser window. This can
- be a string with one of `menu` or `shortcut`, or a callback which gets triggered
- with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
-
- :param force: Optional, forces the closing of the window by using the Gecko API.
- Defaults to `False`.
- """
- def callback(win):
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(win)
- elif trigger == 'menu':
- self.menubar.select_by_id('file-menu', 'menu_closeWindow')
- elif trigger == 'shortcut':
- win.send_shortcut(win.localize_entity('closeCmd.key'),
- accel=True, shift=True)
- else:
- raise ValueError('Unknown closing method: "%s"' % trigger)
-
- BaseWindow.close(self, callback, force)
-
- def get_final_url(self, url):
- """Loads the page at `url` and returns the resulting url.
-
- This function enables testing redirects.
-
- :param url: The url to test.
- :returns: The resulting loaded url.
- """
- with self.marionette.using_context('content'):
- self.marionette.navigate(url)
- return self.marionette.get_url()
-
- def open_browser(self, trigger='menu', is_private=False):
- """Opens a new browser window by using the specified trigger.
-
- :param trigger: Optional, method in how to open the new browser window. This can
- be a string with one of `menu` or `shortcut`, or a callback which gets triggered
- with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
-
- :param is_private: Optional, if True the new window will be a private browsing one.
-
- :returns: :class:`BrowserWindow` instance for the new browser window.
- """
- def callback(win):
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(win)
- elif trigger == 'menu':
- menu_id = 'menu_newPrivateWindow' if is_private else 'menu_newNavigator'
- self.menubar.select_by_id('file-menu', menu_id)
- elif trigger == 'shortcut':
- cmd_key = 'privateBrowsingCmd.commandkey' if is_private else 'newNavigatorCmd.key'
- win.send_shortcut(win.localize_entity(cmd_key),
- accel=True, shift=is_private)
- else:
- raise ValueError('Unknown opening method: "%s"' % trigger)
-
- return BaseWindow.open_window(self, callback, BrowserWindow)
-
- def open_about_window(self, trigger='menu'):
- """Opens the about window by using the specified trigger.
-
- :param trigger: Optional, method in how to open the new browser window. This can
- either the string `menu` or a callback which gets triggered
- with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
-
- :returns: :class:`AboutWindow` instance of the opened window.
- """
- def callback(win):
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(win)
- elif trigger == 'menu':
- self.menubar.select_by_id('helpMenu', 'aboutName')
- else:
- raise ValueError('Unknown opening method: "%s"' % trigger)
-
- return BaseWindow.open_window(self, callback, AboutWindow)
-
- def open_page_info_window(self, trigger='menu'):
- """Opens the page info window by using the specified trigger.
-
- :param trigger: Optional, method in how to open the new browser window. This can
- be a string with one of `menu` or `shortcut`, or a callback which gets triggered
- with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
-
- :returns: :class:`PageInfoWindow` instance of the opened window.
- """
- def callback(win):
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(win)
- elif trigger == 'menu':
- self.menubar.select_by_id('tools-menu', 'menu_pageInfo')
- elif trigger == 'shortcut':
- if win.marionette.session_capabilities['platformName'] == 'windows_nt':
- raise ValueError('Page info shortcut not available on Windows.')
- win.send_shortcut(win.localize_entity('pageInfoCmd.commandkey'),
- accel=True)
- elif trigger == 'context_menu':
- # TODO: Add once we can do right clicks
- pass
- else:
- raise ValueError('Unknown opening method: "%s"' % trigger)
-
- return BaseWindow.open_window(self, callback, PageInfoWindow)
-
-
-Windows.register_window(BrowserWindow.window_type, BrowserWindow)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/deck.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/deck.py
deleted file mode 100644
index acc6d2458c..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/deck.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.ui.base import UIBaseLib
-
-
-class Panel(UIBaseLib):
-
- def __eq__(self, other):
- return self.element.get_attribute('id') == other.element.get_attribute('id')
-
- def __ne__(self, other):
- return self.element.get_attribute('id') != other.element.get_attribute('id')
-
- def __str__(self):
- return self.element.get_attribute('id')
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/menu.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/menu.py
deleted file mode 100644
index 8251daa017..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/menu.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# 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.base import BaseLib
-from firefox_puppeteer.ui.base 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
- the top level menus in the menubar.
-
- :returns: A list of :class:`MenuElement` instances.
- """
- menus = (self.marionette.find_element(By.ID, 'main-menubar')
- .find_elements(By.TAG_NAME, 'menu'))
- return [self.MenuElement(menu) for menu in menus]
-
- def get_menu(self, label):
- """Get a :class:`MenuElement` instance corresponding to the specified label.
-
- :param label: The label of the menu, e.g., **File** or **View**.
- :returns: A :class:`MenuElement` instance.
- """
- menu = [m for m in self.menus if m.get_attribute('label') == label]
-
- if not menu:
- raise NoSuchElementException('Could not find a menu with '
- 'label "{}"'.format(label))
-
- return menu[0]
-
- def get_menu_by_id(self, menu_id):
- """Get a :class:`MenuElement` instance corresponding to the specified
- ID.
-
- :param menu_id: The ID of the menu, e.g., **file-menu** or **view-menu**.
- :returns: A :class:`MenuElement` instance.
- """
- menu = [m for m in self.menus if m.get_attribute('id') == menu_id]
-
- if not menu:
- raise NoSuchElementException('Could not find a menu with '
- 'id "{}"'.format(menu_id))
-
- return menu[0]
-
- def select(self, label, item):
- """Select an item in a menu.
-
- :param label: The label of the menu, e.g., **File** or **View**.
- :param item: The label of the item in the menu, e.g., **New Tab**.
- """
- return self.get_menu(label).select(item)
-
- def select_by_id(self, menu_id, item_id):
- """Select an item in a menu.
-
- :param menu_id: The ID of the menu, e.g. **file-menu** or **view-menu**.
- :param item_id: The ID of the item in the menu, e.g. **menu_newNavigatorTab**.
- """
- return self.get_menu_by_id(menu_id).select_by_id(item_id)
-
- class MenuElement(DOMElement):
- """Wraps a menu element DOM element."""
-
- @property
- def items(self):
- """A list of menuitem DOM elements within this :class:`MenuElement` instance.
-
- :returns: A list of items in the menu.
- """
- return (self.find_element(By.TAG_NAME, 'menupopup')
- .find_elements(By.TAG_NAME, 'menuitem'))
-
- def select(self, label):
- """Click on a menu item within this menu.
-
- :param label: The label of the menu item, e.g., **New Tab**.
- """
- item = [l for l in self.items if l.get_attribute('label') == label]
-
- if not item:
- message = ("Item labeled '{}' not found in the '{}' menu"
- .format(label, self.get_attribute('label')))
- raise NoSuchElementException(message)
-
- return item[0].click()
-
- def select_by_id(self, menu_item_id):
- """Click on a menu item within this menu.
-
- :param menu_item_id: The ID of the menu item, e.g. **menu_newNavigatorTab**.
- """
- item = [l for l in self.items if l.get_attribute('id') ==
- menu_item_id]
-
- if not item:
- message = ("Item with ID '{}' not found in the '{}' menu"
- .format(menu_item_id, self.get_attribute('id')))
- raise NoSuchElementException(message)
-
- return item[0].click()
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/__init__.py
+++ /dev/null
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py
deleted file mode 100644
index 0f2a2167a8..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/deck.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# 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.ui.base import UIBaseLib
-from firefox_puppeteer.ui.deck import Panel
-
-
-class Deck(UIBaseLib):
-
- def _create_panel_for_id(self, panel_id):
- """Creates an instance of :class:`Panel` for the specified panel id.
-
- :param panel_id: The ID of the panel to create an instance of.
-
- :returns: :class:`Panel` instance
- """
- 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)(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.
- """
- return self._create_panel_for_id('feedPanel')
-
- @property
- def general(self):
- """The :class:`GeneralPanel` instance for the general panel.
-
- :returns: :class:`GeneralPanel` instance.
- """
- return self._create_panel_for_id('generalPanel')
-
- @property
- def media(self):
- """The :class:`MediaPanel` instance for the media panel.
-
- :returns: :class:`MediaPanel` instance.
- """
- return self._create_panel_for_id('mediaPanel')
-
- @property
- def panels(self):
- """List of all the :class:`Panel` instances of the current deck.
-
- :returns: List of :class:`Panel` instances.
- """
- panels = self.marionette.execute_script("""
- let deck = arguments[0];
- let panels = [];
-
- for (let index = 0; index < deck.children.length; index++) {
- if (deck.children[index].id) {
- panels.push(deck.children[index].id);
- }
- }
-
- return panels;
- """, script_args=[self.element])
-
- return [self._create_panel_for_id(panel) for panel in panels]
-
- @property
- def permissions(self):
- """The :class:`PermissionsPanel` instance for the permissions panel.
-
- :returns: :class:`PermissionsPanel` instance.
- """
- return self._create_panel_for_id('permPanel')
-
- @property
- def security(self):
- """The :class:`SecurityPanel` instance for the security panel.
-
- :returns: :class:`SecurityPanel` instance.
- """
- return self._create_panel_for_id('securityPanel')
-
- # Properties for helpers when working with the deck #
-
- @property
- def selected_index(self):
- """The index of the currently selected panel.
-
- :return: Index of the selected panel.
- """
- return int(self.element.get_property('selectedIndex'))
-
- @property
- def selected_panel(self):
- """A :class:`Panel` instance of the currently selected panel.
-
- :returns: :class:`Panel` instance.
- """
- return self.panels[self.selected_index]
-
- # Methods for helpers when working with the deck #
-
- def select(self, panel):
- """Selects the specified panel via the tab element.
-
- :param panel: The panel to select.
-
- :returns: :class:`Panel` instance of the selected panel.
- """
- panel.tab.click()
- Wait(self.marionette).until(
- lambda _: self.selected_panel == panel,
- message='Panel with ID "%s" could not be selected.' % panel)
-
- return panel
-
-
-class PageInfoPanel(Panel):
-
- @property
- def tab(self):
- """The DOM element which represents the corresponding tab element at the top.
-
- :returns: Reference to the tab element.
- """
- name = self.element.get_property('id').split('Panel')[0]
- return self.window.window_element.find_element(By.ID, name + 'Tab')
-
-
-class FeedPanel(PageInfoPanel):
- pass
-
-
-class GeneralPanel(PageInfoPanel):
- pass
-
-
-class MediaPanel(PageInfoPanel):
- pass
-
-
-class PermissionsPanel(PageInfoPanel):
- pass
-
-
-class SecurityPanel(PageInfoPanel):
-
- @property
- def domain(self):
- """The DOM element which represents the domain textbox.
-
- :returns: Reference to the textbox element.
- """
- return self.element.find_element(By.ID, 'security-identity-domain-value')
-
- @property
- def owner(self):
- """The DOM element which represents the owner textbox.
-
- :returns: Reference to the textbox element.
- """
- return self.element.find_element(By.ID, 'security-identity-owner-value')
-
- @property
- def verifier(self):
- """The DOM element which represents the verifier textbox.
-
- :returns: Reference to the textbox element.
- """
- return self.element.find_element(By.ID, 'security-identity-verifier-value')
-
- @property
- def view_certificate(self):
- """The DOM element which represents the view certificate button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'security-view-cert')
-
- @property
- def view_cookies(self):
- """The DOM element which represents the view cookies button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'security-view-cookies')
-
- @property
- def view_passwords(self):
- """The DOM element which represents the view passwords button.
-
- :returns: Reference to the button element.
- """
- return self.element.find_element(By.ID, 'security-view-password')
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py
deleted file mode 100644
index 070f39f790..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/pageinfo/window.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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.ui.pageinfo.deck import Deck
-from firefox_puppeteer.ui.windows import BaseWindow, Windows
-
-
-class PageInfoWindow(BaseWindow):
- """Representation of a page info window."""
-
- window_type = 'Browser:page-info'
-
- dtds = [
- 'chrome://browser/locale/pageInfo.dtd',
- ]
-
- properties = [
- 'chrome://browser/locale/browser.properties',
- 'chrome://browser/locale/pageInfo.properties',
- 'chrome://pippki/locale/pippki.properties',
- ]
-
- @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(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`.
-
- :param force: Optional, forces the closing of the window by using the Gecko API.
- Defaults to `False`.
- """
- def callback(win):
- # Prepare action which triggers the opening of the browser window
- if callable(trigger):
- trigger(win)
- elif trigger == 'menu':
- self.menubar.select_by_id('file-menu', 'menu_close')
- elif trigger == 'shortcut':
- win.send_shortcut(win.localize_entity('closeWindow.key'),
- accel=True)
- else:
- raise ValueError('Unknown closing method: "%s"' % trigger)
-
- super(PageInfoWindow, self).close(callback, force)
-
-
-Windows.register_window(PageInfoWindow.window_type, PageInfoWindow)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/__init__.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/__init__.py
deleted file mode 100644
index 0209966946..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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 dialog import UpdateWizardDialog
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py
deleted file mode 100644
index 19435b211f..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/dialog.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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.ui.update_wizard.wizard import Wizard
-from firefox_puppeteer.ui.windows import BaseWindow, Windows
-
-
-# Bug 1143020 - Subclass from BaseDialog ui class with possible wizard mixin
-class UpdateWizardDialog(BaseWindow):
- """Representation of the old Software Update Wizard Dialog."""
- window_type = 'Update:Wizard'
-
- dtds = [
- 'chrome://branding/locale/brand.dtd',
- 'chrome://mozapps/locale/update/updates.dtd',
- ]
-
- properties = [
- 'chrome://branding/locale/brand.properties',
- 'chrome://mozapps/locale/update/updates.properties',
- ]
-
- @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(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,
- message='Next panel has not been selected.')
-
-
-Windows.register_window(UpdateWizardDialog.window_type, UpdateWizardDialog)
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
deleted file mode 100644
index 9687ac9178..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
+++ /dev/null
@@ -1,291 +0,0 @@
-# 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.ui.base import UIBaseLib
-from firefox_puppeteer.ui.deck import Panel
-
-
-class Wizard(UIBaseLib):
-
- def __init__(self, *args, **kwargs):
- super(Wizard, self).__init__(*args, **kwargs)
-
- Wait(self.marionette).until(
- lambda _: self.selected_panel,
- message='No panel has been selected by default.')
-
- def _create_panel_for_id(self, panel_id):
- """Creates an instance of :class:`Panel` for the specified panel id.
-
- :param panel_id: The ID of the panel to create an instance of.
-
- :returns: :class:`Panel` instance
- """
- mapping = {'checking': CheckingPanel,
- 'downloading': DownloadingPanel,
- 'dummy': DummyPanel,
- 'errorpatching': ErrorPatchingPanel,
- 'errors': ErrorPanel,
- 'errorextra': ErrorExtraPanel,
- 'finished': FinishedPanel,
- 'finishedBackground': FinishedBackgroundPanel,
- 'manualUpdate': ManualUpdatePanel,
- 'noupdatesfound': NoUpdatesFoundPanel,
- '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)(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
- def cancel_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'cancel'})
-
- @property
- def extra1_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'extra1'})
-
- @property
- def extra2_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'extra2'})
-
- @property
- def previous_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'back'})
-
- @property
- def finish_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'finish'})
-
- @property
- def next_button(self):
- return self._buttons.find_element(By.ANON_ATTRIBUTE, {'dlgtype': 'next'})
-
- # Properties for visual panels of the wizard #
-
- @property
- def checking(self):
- """The checking for updates panel.
-
- :returns: :class:`CheckingPanel` instance.
- """
- return self._create_panel_for_id('checking')
-
- @property
- def downloading(self):
- """The downloading panel.
-
- :returns: :class:`DownloadingPanel` instance.
- """
- return self._create_panel_for_id('downloading')
-
- @property
- def dummy(self):
- """The dummy panel.
-
- :returns: :class:`DummyPanel` instance.
- """
- return self._create_panel_for_id('dummy')
-
- @property
- def error_patching(self):
- """The error patching panel.
-
- :returns: :class:`ErrorPatchingPanel` instance.
- """
- return self._create_panel_for_id('errorpatching')
-
- @property
- def error(self):
- """The errors panel.
-
- :returns: :class:`ErrorPanel` instance.
- """
- return self._create_panel_for_id('errors')
-
- @property
- def error_extra(self):
- """The error extra panel.
-
- :returns: :class:`ErrorExtraPanel` instance.
- """
- return self._create_panel_for_id('errorextra')
-
- @property
- def finished(self):
- """The finished panel.
-
- :returns: :class:`FinishedPanel` instance.
- """
- return self._create_panel_for_id('finished')
-
- @property
- def finished_background(self):
- """The finished background panel.
-
- :returns: :class:`FinishedBackgroundPanel` instance.
- """
- return self._create_panel_for_id('finishedBackground')
-
- @property
- def incompatible_check(self):
- """The incompatible check panel.
-
- :returns: :class:`IncompatibleCheckPanel` instance.
- """
- return self._create_panel_for_id('incompatibleCheck')
-
- @property
- def incompatible_list(self):
- """The incompatible list panel.
-
- :returns: :class:`IncompatibleListPanel` instance.
- """
- return self._create_panel_for_id('incompatibleList')
-
- @property
- def manual_update(self):
- """The manual update panel.
-
- :returns: :class:`ManualUpdatePanel` instance.
- """
- return self._create_panel_for_id('manualUpdate')
-
- @property
- def no_updates_found(self):
- """The no updates found panel.
-
- :returns: :class:`NoUpdatesFoundPanel` instance.
- """
- return self._create_panel_for_id('noupdatesfound')
-
- @property
- def updates_found_basic(self):
- """The updates found panel.
-
- :returns: :class:`UpdatesFoundPanel` instance.
- """
- return self._create_panel_for_id('updatesfoundbasic')
-
- @property
- def panels(self):
- """List of all the available :class:`Panel` instances.
-
- :returns: List of :class:`Panel` instances.
- """
- panels = self.marionette.execute_script("""
- let wizard = arguments[0];
- let panels = [];
-
- for (let index = 0; index < wizard.children.length; index++) {
- if (wizard.children[index].id) {
- panels.push(wizard.children[index].id);
- }
- }
-
- return panels;
- """, script_args=[self.element])
-
- return [self._create_panel_for_id(panel) for panel in panels]
-
- @property
- def selected_index(self):
- """The index of the currently selected panel.
-
- :return: Index of the selected panel.
- """
- return int(self.element.get_property('pageIndex'))
-
- @property
- def selected_panel(self):
- """A :class:`Panel` instance of the currently selected panel.
-
- :returns: :class:`Panel` instance.
- """
- return self._create_panel_for_id(self.element.get_attribute('currentpageid'))
-
-
-class CheckingPanel(Panel):
-
- @property
- def progress(self):
- """The DOM element which represents the progress meter.
-
- :returns: Reference to the progress element.
- """
- return self.element.find_element(By.ID, 'checkingProgress')
-
-
-class DownloadingPanel(Panel):
-
- @property
- def progress(self):
- """The DOM element which represents the progress meter.
-
- :returns: Reference to the progress element.
- """
- return self.element.find_element(By.ID, 'downloadProgress')
-
-
-class DummyPanel(Panel):
- pass
-
-
-class ErrorPatchingPanel(Panel):
- pass
-
-
-class ErrorPanel(Panel):
- pass
-
-
-class ErrorExtraPanel(Panel):
- pass
-
-
-class FinishedPanel(Panel):
- pass
-
-
-class FinishedBackgroundPanel(Panel):
- pass
-
-
-class IncompatibleCheckPanel(Panel):
-
- @property
- def progress(self):
- """The DOM element which represents the progress meter.
-
- :returns: Reference to the progress element.
- """
- return self.element.find_element(By.ID, 'incompatibleCheckProgress')
-
-
-class IncompatibleListPanel(Panel):
- pass
-
-
-class ManualUpdatePanel(Panel):
- pass
-
-
-class NoUpdatesFoundPanel(Panel):
- pass
-
-
-class UpdatesFoundBasicPanel(Panel):
- pass
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py
deleted file mode 100644
index 9248a39352..0000000000
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py
+++ /dev/null
@@ -1,435 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from marionette_driver import By, Wait
-from marionette_driver.errors import NoSuchWindowException
-from marionette_driver.keys import Keys
-
-import firefox_puppeteer.errors as errors
-
-from firefox_puppeteer.api.l10n import L10n
-from firefox_puppeteer.base import BaseLib
-from firefox_puppeteer.decorators import use_class_as_property
-
-
-class Windows(BaseLib):
-
- # Used for registering the different windows with this class to avoid
- # circular dependencies with BaseWindow
- windows_map = {}
-
- @property
- def all(self):
- """Retrieves a list of all open chrome windows.
-
- :returns: List of :class:`BaseWindow` instances corresponding to the
- windows in `marionette.chrome_window_handles`.
- """
- return [self.create_window_instance(handle) for handle in
- self.marionette.chrome_window_handles]
-
- @property
- def current(self):
- """Retrieves the currently selected chrome window.
-
- :returns: The :class:`BaseWindow` for the currently active window.
- """
- return self.create_window_instance(self.marionette.current_chrome_window_handle)
-
- @property
- def focused_chrome_window_handle(self):
- """Returns the currently focused chrome window handle.
-
- :returns: The `window handle` of the focused chrome window.
- """
- def get_active_handle(mn):
- with self.marionette.using_context('chrome'):
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- let win = Services.focus.activeWindow;
- if (win) {
- return win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
- .getInterface(Components.interfaces.nsIDOMWindowUtils)
- .outerWindowID.toString();
- }
-
- return null;
- """)
-
- # In case of `None` being returned no window is currently active. This can happen
- # when a focus change action is currently happening. So lets wait until it is done.
- return Wait(self.marionette).until(get_active_handle,
- message='No focused window has been found.')
-
- def close(self, handle):
- """Closes the chrome window with the given handle.
-
- :param handle: The handle of the chrome window.
- """
- self.switch_to(handle)
-
- # TODO: Maybe needs to wait as handled via an observer
- return self.marionette.close_chrome_window()
-
- def close_all(self, exceptions=None):
- """Closes all open chrome windows.
-
- There is an optional `exceptions` list, which can be used to exclude
- specific chrome windows from being closed.
-
- :param exceptions: Optional, list of :class:`BaseWindow` instances not to close.
- """
- windows_to_keep = exceptions or []
-
- # Get handles of windows_to_keep
- handles_to_keep = [entry.handle for entry in windows_to_keep]
-
- # Find handles to close and close them all
- handles_to_close = set(self.marionette.chrome_window_handles) - set(handles_to_keep)
- for handle in handles_to_close:
- self.close(handle)
-
- def create_window_instance(self, handle, expected_class=None):
- """Creates a :class:`BaseWindow` instance for the given chrome window.
-
- :param handle: The handle of the chrome window.
- :param expected_class: Optional, check for the correct window class.
- """
- current_handle = self.marionette.current_chrome_window_handle
- window = None
-
- with self.marionette.using_context('chrome'):
- try:
- # Retrieve window type to determine the type of chrome window
- if handle != self.marionette.current_chrome_window_handle:
- self.switch_to(handle)
- window_type = self.marionette.get_window_type()
- 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](self.marionette, handle)
- else:
- window = BaseWindow(self.marionette, 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)))
-
- # Before continuing ensure the chrome window has been completed loading
- Wait(self.marionette).until(
- lambda _: self.loaded(handle),
- message='Chrome window with handle "%s" did not finish loading.' % handle)
-
- return window
-
- def focus(self, handle):
- """Focuses the chrome window with the given handle.
-
- :param handle: The handle of the chrome window.
- """
- self.switch_to(handle)
-
- with self.marionette.using_context('chrome'):
- self.marionette.execute_script(""" window.focus(); """)
-
- Wait(self.marionette).until(
- lambda _: handle == self.focused_chrome_window_handle,
- message='Focus has not been set to chrome window handle "%s".' % handle)
-
- def loaded(self, handle):
- """Check if the chrome window with the given handle has been completed loading.
-
- :param handle: The handle of the chrome window.
-
- :returns: True, if the chrome window has been loaded.
- """
- with self.marionette.using_context('chrome'):
- return self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- let win = Services.wm.getOuterWindowWithId(Number(arguments[0]));
- return win.document.readyState == 'complete';
- """, script_args=[handle])
-
- def switch_to(self, target):
- """Switches context to the specified chrome window.
-
- :param target: The window to switch to. `target` can be a `handle` or a
- callback that returns True in the context of the desired
- window.
-
- :returns: Instance of the selected :class:`BaseWindow`.
- """
- target_handle = None
-
- if target in self.marionette.chrome_window_handles:
- target_handle = target
- elif callable(target):
- current_handle = self.marionette.current_chrome_window_handle
-
- # switches context if callback for a chrome window returns `True`.
- for handle in self.marionette.chrome_window_handles:
- self.marionette.switch_to_window(handle)
- window = self.create_window_instance(handle)
- if target(window):
- target_handle = handle
- break
-
- # if no handle has been found switch back to original window
- if not target_handle:
- self.marionette.switch_to_window(current_handle)
-
- if target_handle is None:
- raise NoSuchWindowException("No window found for '{}'"
- .format(target))
-
- # only switch if necessary
- if target_handle != self.marionette.current_chrome_window_handle:
- self.marionette.switch_to_window(target_handle)
-
- return self.create_window_instance(target_handle)
-
- @classmethod
- def register_window(cls, window_type, window_class):
- """Registers a chrome window with this class so that this class may in
- turn create the appropriate window instance later on.
-
- :param window_type: The type of window.
- :param window_class: The constructor of the window
- """
- cls.windows_map[window_type] = window_class
-
-
-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, window_handle):
- super(BaseWindow, self).__init__(marionette)
-
- self._l10n = L10n(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
-
- @property
- def closed(self):
- """Returns closed state of the chrome window.
-
- :returns: True if the window has been closed.
- """
- return self.handle not in self.marionette.chrome_window_handles
-
- @property
- def focused(self):
- """Returns `True` if the chrome window is focused.
-
- :returns: True if the window is focused.
- """
- self.switch_to()
-
- return self.handle == self._windows.focused_chrome_window_handle
-
- @property
- def handle(self):
- """Returns the `window handle` of the chrome window.
-
- :returns: `window handle`.
- """
- return self._handle
-
- @property
- def loaded(self):
- """Checks if the window has been fully loaded.
-
- :returns: True, if the window is loaded.
- """
- self._windows.loaded(self.handle)
-
- @use_class_as_property('ui.menu.MenuBar')
- def menubar(self):
- """Provides access to the menu bar, for example, the **File** menu.
-
- See the :class:`~ui.menu.MenuBar` reference.
- """
-
- @property
- def window_element(self):
- """Returns the inner DOM window element.
-
- :returns: DOM window element.
- """
- self.switch_to()
-
- return self.marionette.find_element(By.CSS_SELECTOR, ':root')
-
- def close(self, callback=None, force=False):
- """Closes the current chrome window.
-
- If this is the last remaining window, the Marionette session is ended.
-
- :param callback: Optional, function to trigger the window to open. It is
- triggered with the current :class:`BaseWindow` as parameter.
- Defaults to `window.open()`.
-
- :param force: Optional, forces the closing of the window by using the Gecko API.
- Defaults to `False`.
- """
- self.switch_to()
-
- # Bug 1121698
- # For more stable tests register an observer topic first
- prev_win_count = len(self.marionette.chrome_window_handles)
-
- handle = self.handle
- if force or callback is None:
- self._windows.close(handle)
- else:
- callback(self)
-
- # Bug 1121698
- # Observer code should let us ditch this wait code
- Wait(self.marionette).until(
- lambda m: len(m.chrome_window_handles) == prev_win_count - 1,
- message='Chrome window with handle "%s" has not been closed.' % handle)
-
- def focus(self):
- """Sets the focus to the current chrome window."""
- return self._windows.focus(self.handle)
-
- def localize_entity(self, entity_id):
- """Returns the localized string for the specified DTD entity id.
-
- :param entity_id: The id to retrieve the value from.
-
- :returns: The localized string for the requested entity.
-
- :raises MarionetteException: When entity id is not found.
- """
- return self._l10n.localize_entity(self.dtds, entity_id)
-
- def localize_property(self, property_id):
- """Returns the localized string for the specified property id.
-
- :param property_id: The id to retrieve the value from.
-
- :returns: The localized string for the requested property.
-
- :raises MarionetteException: When property id is not found.
- """
- return self._l10n.localize_property(self.properties, property_id)
-
- def open_window(self, callback=None, expected_window_class=None, focus=True):
- """Opens a new top-level chrome window.
-
- :param callback: Optional, function to trigger the window to open. It is
- triggered with the current :class:`BaseWindow` as parameter.
- Defaults to `window.open()`.
- :param expected_class: Optional, check for the correct window class.
- :param focus: Optional, if true, focus the new window.
- Defaults to `True`.
- """
- # Bug 1121698
- # For more stable tests register an observer topic first
- start_handles = self.marionette.chrome_window_handles
-
- self.switch_to()
- with self.marionette.using_context('chrome'):
- if callback is not None:
- callback(self)
- else:
- self.marionette.execute_script(""" window.open(); """)
-
- # TODO: Needs to be replaced with observer handling code (bug 1121698)
- def window_opened(mn):
- return len(mn.chrome_window_handles) == len(start_handles) + 1
- Wait(self.marionette).until(
- window_opened,
- message='No new chrome window has been opened.')
-
- handles = self.marionette.chrome_window_handles
- [new_handle] = list(set(handles) - set(start_handles))
-
- assert new_handle is not None
-
- window = self._windows.create_window_instance(new_handle, expected_window_class)
-
- if focus:
- window.focus()
-
- return window
-
- def send_shortcut(self, command_key, **kwargs):
- """Sends a keyboard shortcut to the window.
-
- :param command_key: The key (usually a letter) to be pressed.
-
- :param accel: Optional, If `True`, the `Accel` modifier key is pressed.
- This key differs between OS X (`Meta`) and Linux/Windows (`Ctrl`). Defaults to `False`.
-
- :param alt: Optional, If `True`, the `Alt` modifier key is pressed. Defaults to `False`.
-
- :param ctrl: Optional, If `True`, the `Ctrl` modifier key is pressed. Defaults to `False`.
-
- :param meta: Optional, If `True`, the `Meta` modifier key is pressed. Defaults to `False`.
-
- :param shift: Optional, If `True`, the `Shift` modifier key is pressed.
- Defaults to `False`.
- """
-
- platform = self.marionette.session_capabilities['platformName']
-
- keymap = {
- 'accel': Keys.META if platform == 'darwin' else Keys.CONTROL,
- 'alt': Keys.ALT,
- 'cmd': Keys.COMMAND,
- 'ctrl': Keys.CONTROL,
- 'meta': Keys.META,
- 'shift': Keys.SHIFT,
- }
-
- # Append all to press modifier keys
- keys = []
- for modifier in kwargs:
- if modifier not in keymap:
- raise KeyError('"%s" is not a known modifier' % modifier)
-
- if kwargs[modifier] is True:
- keys.append(keymap[modifier])
-
- # Bug 1125209 - Only lower-case command keys should be sent
- keys.append(command_key.lower())
-
- self.switch_to()
- self.window_element.send_keys(*keys)
-
- def switch_to(self, focus=False):
- """Switches the context to this chrome window.
-
- By default it will not focus the window. If that behavior is wanted, the
- `focus` parameter can be used.
-
- :param focus: If `True`, the chrome window will be focused.
-
- :returns: Current window as :class:`BaseWindow` instance.
- """
- if focus:
- self._windows.focus(self.handle)
- else:
- self._windows.switch_to(self.handle)
-
- return self
diff --git a/testing/marionette/puppeteer/firefox/requirements-docs.txt b/testing/marionette/puppeteer/firefox/requirements-docs.txt
deleted file mode 100644
index 9b4aa5d0a0..0000000000
--- a/testing/marionette/puppeteer/firefox/requirements-docs.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-sphinx
-sphinx_rtd_theme
-
-# Required by Readthedocs to install the firefox-puppeteer package
--e testing/marionette/puppeteer/firefox
diff --git a/testing/marionette/puppeteer/firefox/requirements.txt b/testing/marionette/puppeteer/firefox/requirements.txt
deleted file mode 100644
index bfacfffde8..0000000000
--- a/testing/marionette/puppeteer/firefox/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-marionette-driver >= 2.2.0
-mozinfo >= 0.8
diff --git a/testing/marionette/puppeteer/firefox/setup.py b/testing/marionette/puppeteer/firefox/setup.py
deleted file mode 100644
index 5efb36a61e..0000000000
--- a/testing/marionette/puppeteer/firefox/setup.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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
-import re
-from setuptools import setup, find_packages
-
-THIS_DIR = os.path.dirname(os.path.realpath(__name__))
-
-
-def read(*parts):
- with open(os.path.join(THIS_DIR, *parts)) as f:
- return f.read()
-
-
-def get_version():
- return re.findall("__version__ = '([\d\.]+)'",
- read('firefox_puppeteer', '__init__.py'), re.M)[0]
-
-
-setup(name='firefox-puppeteer',
- version=get_version(),
- description="Firefox Puppeteer",
- long_description='See http://firefox-puppeteer.readthedocs.org/',
- classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
- keywords='mozilla',
- author='Auto-tools',
- author_email='tools-marionette@lists.mozilla.org',
- url='https://wiki.mozilla.org/Auto-tools/Projects/Marionette/Puppeteer/Firefox',
- license='MPL',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=read('requirements.txt').splitlines(),
- )
diff --git a/testing/marionette/server.js b/testing/marionette/server.js
deleted file mode 100644
index 0d8a7bf23d..0000000000
--- a/testing/marionette/server.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-var {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
-const ServerSocket = CC("@mozilla.org/network/server-socket;1", "nsIServerSocket", "initSpecialConnection");
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-Cu.import("chrome://marionette/content/dispatcher.js");
-Cu.import("chrome://marionette/content/driver.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/simpletest.js");
-
-// Bug 1083711: Load transport.js as an SDK module instead of subscript
-loader.loadSubScript("resource://devtools/shared/transport/transport.js");
-
-const logger = Log.repository.getLogger("Marionette");
-
-this.EXPORTED_SYMBOLS = ["MarionetteServer"];
-
-const CONTENT_LISTENER_PREF = "marionette.contentListener";
-const MANAGE_OFFLINE_STATUS_PREF = "network.gonk.manage-offline-status";
-
-/**
- * Bootstraps Marionette and handles incoming client connections.
- *
- * Once started, it opens a TCP socket sporting the debugger transport
- * protocol on the provided port. For every new client a Dispatcher is
- * created.
- *
- * @param {number} port
- * Port for server to listen to.
- * @param {boolean} forceLocal
- * Listen only to connections from loopback if true. If false,
- * accept all connections.
- */
-this.MarionetteServer = function (port, forceLocal) {
- this.port = port;
- this.forceLocal = forceLocal;
- this.conns = {};
- this.nextConnId = 0;
- this.alive = false;
- this._acceptConnections = false;
-};
-
-/**
- * Function produces a GeckoDriver.
- *
- * Determines application nameto initialise the driver with.
- *
- * @return {GeckoDriver}
- * A driver instance.
- */
-MarionetteServer.prototype.driverFactory = function() {
- let appName = isMulet() ? "B2G" : Services.appinfo.name;
- let bypassOffline = false;
-
- Preferences.set(CONTENT_LISTENER_PREF, false);
-
- if (bypassOffline) {
- logger.debug("Bypassing offline status");
- Preferences.set(MANAGE_OFFLINE_STATUS_PREF, false);
- Services.io.manageOfflineStatus = false;
- Services.io.offline = false;
- }
-
- return new GeckoDriver(appName, this);
-};
-
-MarionetteServer.prototype.__defineSetter__("acceptConnections", function (value) {
- if (!value) {
- logger.info("New connections will no longer be accepted");
- } else {
- logger.info("New connections are accepted again");
- }
-
- this._acceptConnections = value;
-});
-
-MarionetteServer.prototype.start = function() {
- if (this.alive) {
- return;
- }
- let flags = Ci.nsIServerSocket.KeepWhenOffline;
- if (this.forceLocal) {
- flags |= Ci.nsIServerSocket.LoopbackOnly;
- }
- this.listener = new ServerSocket(this.port, flags, 1);
- this.listener.asyncListen(this);
- this.alive = true;
- this._acceptConnections = true;
-};
-
-MarionetteServer.prototype.stop = function() {
- if (!this.alive) {
- return;
- }
- this.closeListener();
- this.alive = false;
- this._acceptConnections = false;
-};
-
-MarionetteServer.prototype.closeListener = function() {
- this.listener.close();
- this.listener = null;
-};
-
-MarionetteServer.prototype.onSocketAccepted = function (
- serverSocket, clientSocket) {
- if (!this._acceptConnections) {
- logger.warn("New connections are currently not accepted");
- return;
- }
-
- let input = clientSocket.openInputStream(0, 0, 0);
- let output = clientSocket.openOutputStream(0, 0, 0);
- let transport = new DebuggerTransport(input, output);
- let connId = "conn" + this.nextConnId++;
-
- let dispatcher = new Dispatcher(connId, transport, this.driverFactory.bind(this));
- dispatcher.onclose = this.onConnectionClosed.bind(this);
- this.conns[connId] = dispatcher;
-
- logger.debug(`Accepted connection ${connId} from ${clientSocket.host}:${clientSocket.port}`);
- dispatcher.sayHello();
- transport.ready();
-};
-
-MarionetteServer.prototype.onConnectionClosed = function (conn) {
- let id = conn.connId;
- delete this.conns[id];
- logger.debug(`Closed connection ${id}`);
-};
-
-function isMulet() {
- return Preferences.get("b2g.is_mulet", false);
-}
diff --git a/testing/marionette/session.js b/testing/marionette/session.js
deleted file mode 100644
index 8bd16404f1..0000000000
--- a/testing/marionette/session.js
+++ /dev/null
@@ -1,457 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["session"];
-
-const logger = Log.repository.getLogger("Marionette");
-const {pprint} = error;
-
-// Enable testing this module, as Services.appinfo.* is not available
-// in xpcshell tests.
-const appinfo = {name: "<missing>", version: "<missing>"};
-try { appinfo.name = Services.appinfo.name.toLowerCase(); } catch (e) {}
-try { appinfo.version = Services.appinfo.version; } catch (e) {}
-
-/** State associated with a WebDriver session. */
-this.session = {};
-
-/** Representation of WebDriver session timeouts. */
-session.Timeouts = class {
- constructor () {
- // disabled
- this.implicit = 0;
- // five mintues
- this.pageLoad = 300000;
- // 30 seconds
- this.script = 30000;
- }
-
- toString () { return "[object session.Timeouts]"; }
-
- toJSON () {
- return {
- "implicit": this.implicit,
- "page load": this.pageLoad,
- "script": this.script,
- };
- }
-
- static fromJSON (json) {
- assert.object(json);
- let t = new session.Timeouts();
-
- for (let [typ, ms] of Object.entries(json)) {
- assert.positiveInteger(ms);
-
- switch (typ) {
- case "implicit":
- t.implicit = ms;
- break;
-
- case "script":
- t.script = ms;
- break;
-
- case "page load":
- t.pageLoad = ms;
- break;
-
- default:
- throw new InvalidArgumentError();
- }
- }
-
- return t;
- }
-};
-
-/** Enum of page loading strategies. */
-session.PageLoadStrategy = {
- None: "none",
- Eager: "eager",
- Normal: "normal",
-};
-
-/** Proxy configuration object representation. */
-session.Proxy = class {
- constructor() {
- this.proxyType = null;
- this.httpProxy = null;
- this.httpProxyPort = null;
- this.sslProxy = null;
- this.sslProxyPort = null;
- this.ftpProxy = null;
- this.ftpProxyPort = null;
- this.socksProxy = null;
- this.socksProxyPort = null;
- this.socksVersion = null;
- this.proxyAutoconfigUrl = null;
- }
-
- /**
- * Sets Firefox proxy settings.
- *
- * @return {boolean}
- * True if proxy settings were updated as a result of calling this
- * function, or false indicating that this function acted as
- * a no-op.
- */
- init() {
- switch (this.proxyType) {
- case "manual":
- Preferences.set("network.proxy.type", 1);
- if (this.httpProxy && this.httpProxyPort) {
- Preferences.set("network.proxy.http", this.httpProxy);
- Preferences.set("network.proxy.http_port", this.httpProxyPort);
- }
- if (this.sslProxy && this.sslProxyPort) {
- Preferences.set("network.proxy.ssl", this.sslProxy);
- Preferences.set("network.proxy.ssl_port", this.sslProxyPort);
- }
- if (this.ftpProxy && this.ftpProxyPort) {
- Preferences.set("network.proxy.ftp", this.ftpProxy);
- Preferences.set("network.proxy.ftp_port", this.ftpProxyPort);
- }
- if (this.socksProxy) {
- Preferences.set("network.proxy.socks", this.socksProxy);
- Preferences.set("network.proxy.socks_port", this.socksProxyPort);
- if (this.socksVersion) {
- Preferences.set("network.proxy.socks_version", this.socksVersion);
- }
- }
- return true;
-
- case "pac":
- Preferences.set("network.proxy.type", 2);
- Preferences.set("network.proxy.autoconfig_url", this.proxyAutoconfigUrl);
- return true;
-
- case "autodetect":
- Preferences.set("network.proxy.type", 4);
- return true;
-
- case "system":
- Preferences.set("network.proxy.type", 5);
- return true;
-
- case "noproxy":
- Preferences.set("network.proxy.type", 0);
- return true;
-
- default:
- return false;
- }
- }
-
- toString () { return "[object session.Proxy]"; }
-
- toJSON () {
- return marshal({
- proxyType: this.proxyType,
- httpProxy: this.httpProxy,
- httpProxyPort: this.httpProxyPort ,
- sslProxy: this.sslProxy,
- sslProxyPort: this.sslProxyPort,
- ftpProxy: this.ftpProxy,
- ftpProxyPort: this.ftpProxyPort,
- socksProxy: this.socksProxy,
- socksProxyPort: this.socksProxyPort,
- socksProxyVersion: this.socksProxyVersion,
- proxyAutoconfigUrl: this.proxyAutoconfigUrl,
- });
- }
-
- static fromJSON (json) {
- let p = new session.Proxy();
- if (typeof json == "undefined" || json === null) {
- return p;
- }
-
- assert.object(json);
-
- assert.in("proxyType", json);
- p.proxyType = json.proxyType;
-
- if (json.proxyType == "manual") {
- if (typeof json.httpProxy != "undefined") {
- p.httpProxy = assert.string(json.httpProxy);
- p.httpProxyPort = assert.positiveInteger(json.httpProxyPort);
- }
-
- if (typeof json.sslProxy != "undefined") {
- p.sslProxy = assert.string(json.sslProxy);
- p.sslProxyPort = assert.positiveInteger(json.sslProxyPort);
- }
-
- if (typeof json.ftpProxy != "undefined") {
- p.ftpProxy = assert.string(json.ftpProxy);
- p.ftpProxyPort = assert.positiveInteger(json.ftpProxyPort);
- }
-
- if (typeof json.socksProxy != "undefined") {
- p.socksProxy = assert.string(json.socksProxy);
- p.socksProxyPort = assert.positiveInteger(json.socksProxyPort);
- p.socksProxyVersion = assert.positiveInteger(json.socksProxyVersion);
- }
- }
-
- if (typeof json.proxyAutoconfigUrl != "undefined") {
- p.proxyAutoconfigUrl = assert.string(json.proxyAutoconfigUrl);
- }
-
- return p;
- }
-};
-
-/** WebDriver session capabilities representation. */
-session.Capabilities = class extends Map {
- constructor () {
- super([
- // webdriver
- ["browserName", appinfo.name],
- ["browserVersion", appinfo.version],
- ["platformName", Services.sysinfo.getProperty("name").toLowerCase()],
- ["platformVersion", Services.sysinfo.getProperty("version")],
- ["pageLoadStrategy", session.PageLoadStrategy.Normal],
- ["acceptInsecureCerts", false],
- ["timeouts", new session.Timeouts()],
- ["proxy", new session.Proxy()],
-
- // features
- ["rotatable", appinfo.name == "B2G"],
-
- // proprietary
- ["specificationLevel", 0],
- ["moz:processID", Services.appinfo.processID],
- ["moz:profile", maybeProfile()],
- ["moz:accessibilityChecks", false],
- ]);
- }
-
- set (key, value) {
- if (key === "timeouts" && !(value instanceof session.Timeouts)) {
- throw new TypeError();
- } else if (key === "proxy" && !(value instanceof session.Proxy)) {
- throw new TypeError();
- }
-
- return super.set(key, value);
- }
-
- toString() { return "[object session.Capabilities]"; }
-
- toJSON() {
- return marshal(this);
- }
-
- /**
- * Unmarshal a JSON object representation of WebDriver capabilities.
- *
- * @param {Object.<string, ?>=} json
- * WebDriver capabilities.
- * @param {boolean=} merge
- * If providing |json| with |desiredCapabilities| or
- * |requiredCapabilities| fields, or both, it should be set to
- * true to merge these before parsing. This indicates
- * that the input provided is from a client and not from
- * |session.Capabilities#toJSON|.
- *
- * @return {session.Capabilities}
- * Internal representation of WebDriver capabilities.
- */
- static fromJSON (json, {merge = false} = {}) {
- if (typeof json == "undefined" || json === null) {
- json = {};
- }
- assert.object(json);
-
- if (merge) {
- json = session.Capabilities.merge_(json);
- }
- return session.Capabilities.match_(json);
- }
-
- // Processes capabilities as described by WebDriver.
- static merge_ (json) {
- for (let entry of [json.desiredCapabilities, json.requiredCapabilities]) {
- if (typeof entry == "undefined" || entry === null) {
- continue;
- }
- assert.object(entry, error.pprint`Expected ${entry} to be a capabilities object`);
- }
-
- let desired = json.desiredCapabilities || {};
- let required = json.requiredCapabilities || {};
-
- // One level deep union merge of desired- and required capabilities
- // with preference on required
- return Object.assign({}, desired, required);
- }
-
- // Matches capabilities as described by WebDriver.
- static match_ (caps = {}) {
- let matched = new session.Capabilities();
-
- const defined = v => typeof v != "undefined" && v !== null;
- const wildcard = v => v === "*";
-
- // Iff |actual| provides some value, or is a wildcard or an exact
- // match of |expected|. This means it can be null or undefined,
- // or "*", or "firefox".
- function stringMatch (actual, expected) {
- return !defined(actual) || (wildcard(actual) || actual === expected);
- }
-
- for (let [k,v] of Object.entries(caps)) {
- switch (k) {
- case "browserName":
- let bname = matched.get("browserName");
- if (!stringMatch(v, bname)) {
- throw new TypeError(
- pprint`Given browserName ${v}, but my name is ${bname}`);
- }
- break;
-
- // TODO(ato): bug 1326397
- case "browserVersion":
- let bversion = matched.get("browserVersion");
- if (!stringMatch(v, bversion)) {
- throw new TypeError(
- pprint`Given browserVersion ${v}, ` +
- pprint`but current version is ${bversion}`);
- }
- break;
-
- case "platformName":
- let pname = matched.get("platformName");
- if (!stringMatch(v, pname)) {
- throw new TypeError(
- pprint`Given platformName ${v}, ` +
- pprint`but current platform is ${pname}`);
- }
- break;
-
- // TODO(ato): bug 1326397
- case "platformVersion":
- let pversion = matched.get("platformVersion");
- if (!stringMatch(v, pversion)) {
- throw new TypeError(
- pprint`Given platformVersion ${v}, ` +
- pprint`but current platform version is ${pversion}`);
- }
- break;
-
- case "acceptInsecureCerts":
- assert.boolean(v);
- matched.set("acceptInsecureCerts", v);
- break;
-
- case "pageLoadStrategy":
- if (Object.values(session.PageLoadStrategy).includes(v)) {
- matched.set("pageLoadStrategy", v);
- } else {
- throw new TypeError("Unknown page load strategy: " + v);
- }
- break;
-
- case "proxy":
- let proxy = session.Proxy.fromJSON(v);
- matched.set("proxy", proxy);
- break;
-
- case "timeouts":
- let timeouts = session.Timeouts.fromJSON(v);
- matched.set("timeouts", timeouts);
- break;
-
- case "specificationLevel":
- assert.positiveInteger(v);
- matched.set("specificationLevel", v);
- break;
-
- case "moz:accessibilityChecks":
- assert.boolean(v);
- matched.set("moz:accessibilityChecks", v);
- break;
- }
- }
-
- return matched;
- }
-};
-
-// Specialisation of |JSON.stringify| that produces JSON-safe object
-// literals, dropping empty objects and entries which values are undefined
-// or null. Objects are allowed to produce their own JSON representations
-// by implementing a |toJSON| function.
-function marshal(obj) {
- let rv = Object.create(null);
-
- function* iter(mapOrObject) {
- if (mapOrObject instanceof Map) {
- for (const [k,v] of mapOrObject) {
- yield [k,v];
- }
- } else {
- for (const k of Object.keys(mapOrObject)) {
- yield [k, mapOrObject[k]];
- }
- }
- }
-
- for (let [k,v] of iter(obj)) {
- // Skip empty values when serialising to JSON.
- if (typeof v == "undefined" || v === null) {
- continue;
- }
-
- // Recursively marshal objects that are able to produce their own
- // JSON representation.
- if (typeof v.toJSON == "function") {
- v = marshal(v.toJSON());
- }
-
- // Or do the same for object literals.
- else if (isObject(v)) {
- v = marshal(v);
- }
-
- // And finally drop (possibly marshaled) objects which have no
- // entries.
- if (!isObjectEmpty(v)) {
- rv[k] = v;
- }
- }
-
- return rv;
-}
-
-function isObject(obj) {
- return Object.prototype.toString.call(obj) == "[object Object]";
-}
-
-function isObjectEmpty(obj) {
- return isObject(obj) && Object.keys(obj).length === 0;
-}
-
-// Services.dirsvc is not accessible from content frame scripts,
-// but we should not panic about that.
-function maybeProfile() {
- try {
- return Services.dirsvc.get("ProfD", Ci.nsIFile).path;
- } catch (e) {
- return "<protected>";
- }
-}
diff --git a/testing/marionette/simpletest.js b/testing/marionette/simpletest.js
deleted file mode 100644
index b179d2a8c2..0000000000
--- a/testing/marionette/simpletest.js
+++ /dev/null
@@ -1,208 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["simpletest"];
-
-this.simpletest = {};
-
-/**
- * The simpletest harness, exposed in the script evaluation sandbox.
- */
-simpletest.Harness = class {
- constructor(window, context, contentLogger, timeout, testName) {
- this.window = window;
- this.tests = [];
- this.logger = contentLogger;
- this.context = context;
- this.timeout = timeout;
- this.testName = testName;
- this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
- this.TEST_UNEXPECTED_PASS = "TEST-UNEXPECTED-PASS";
- this.TEST_PASS = "TEST-PASS";
- this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL";
- }
-
- get exports() {
- return new Map([
- ["ok", this.ok.bind(this)],
- ["is", this.is.bind(this)],
- ["isnot", this.isnot.bind(this)],
- ["todo", this.todo.bind(this)],
- ["log", this.log.bind(this)],
- ["getLogs", this.getLogs.bind(this)],
- ["generate_results", this.generate_results.bind(this)],
- ["waitFor", this.waitFor.bind(this)],
- ["TEST_PASS", this.TEST_PASS],
- ["TEST_KNOWN_FAIL", this.TEST_KNOWN_FAIL],
- ["TEST_UNEXPECTED_FAIL", this.TEST_UNEXPECTED_FAIL],
- ["TEST_UNEXPECTED_PASS", this.TEST_UNEXPECTED_PASS],
- ]);
- }
-
- addTest(condition, name, passString, failString, diag, state) {
- let test = {
- result: !!condition,
- name: name,
- diag: diag,
- state: state
- };
- this.logResult(
- test,
- typeof passString == "undefined" ? this.TEST_PASS : passString,
- typeof failString == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString);
- this.tests.push(test);
- }
-
- ok(condition, name, passString, failString) {
- let diag = `${this.repr(condition)} was ${!!condition}, expected true`;
- this.addTest(condition, name, passString, failString, diag);
- }
-
- is(a, b, name, passString, failString) {
- let pass = (a == b);
- let diag = pass ? this.repr(a) + " should equal " + this.repr(b)
- : "got " + this.repr(a) + ", expected " + this.repr(b);
- this.addTest(pass, name, passString, failString, diag);
- }
-
- isnot(a, b, name, passString, failString) {
- let pass = (a != b);
- let diag = pass ? this.repr(a) + " should not equal " + this.repr(b)
- : "didn't expect " + this.repr(a) + ", but got it";
- this.addTest(pass, name, passString, failString, diag);
- }
-
- todo(condition, name, passString, failString) {
- let diag = this.repr(condition) + " was expected false";
- this.addTest(!condition,
- name,
- typeof(passString) == "undefined" ? this.TEST_KNOWN_FAIL : passString,
- typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString,
- diag,
- "todo");
- }
-
- log(msg, level) {
- dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n");
- if (this.logger) {
- this.logger.log(msg, level);
- }
- }
-
- // TODO(ato): Suspect this isn't used anywhere
- getLogs() {
- if (this.logger) {
- return this.logger.get();
- }
- }
-
- generate_results() {
- let passed = 0;
- let failures = [];
- let expectedFailures = [];
- let unexpectedSuccesses = [];
- for (let i in this.tests) {
- let isTodo = (this.tests[i].state == "todo");
- if(this.tests[i].result) {
- if (isTodo) {
- expectedFailures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
- }
- else {
- passed++;
- }
- }
- else {
- if (isTodo) {
- unexpectedSuccesses.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
- }
- else {
- failures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
- }
- }
- }
- // Reset state in case this object is reused for more tests.
- this.tests = [];
- return {
- passed: passed,
- failures: failures,
- expectedFailures: expectedFailures,
- unexpectedSuccesses: unexpectedSuccesses,
- };
- }
-
- logToFile(file) {
- //TODO
- }
-
- logResult(test, passString, failString) {
- //TODO: dump to file
- let resultString = test.result ? passString : failString;
- let diagnostic = test.name + (test.diag ? " - " + test.diag : "");
- let msg = resultString + " | " + this.testName + " | " + diagnostic;
- dump("MARIONETTE TEST RESULT:" + msg + "\n");
- }
-
- repr(o) {
- if (typeof o == "undefined") {
- return "undefined";
- } else if (o === null) {
- return "null";
- }
-
- try {
- if (typeof o.__repr__ == "function") {
- return o.__repr__();
- } else if (typeof o.repr == "function" && o.repr !== arguments.callee) {
- return o.repr();
- }
- } catch (e) {}
-
- try {
- if (typeof o.NAME === "string" &&
- (o.toString === Function.prototype.toString || o.toString === Object.prototype.toString)) {
- return o.NAME;
- }
- } catch (e) {}
-
- let ostring;
- try {
- ostring = (o + "");
- } catch (e) {
- return "[" + typeof(o) + "]";
- }
-
- if (typeof o == "function") {
- o = ostring.replace(/^\s+/, "");
- let idx = o.indexOf("{");
- if (idx != -1) {
- o = o.substr(0, idx) + "{...}";
- }
- }
- return ostring;
- }
-
- waitFor(callback, test, timeout) {
- if (test()) {
- callback();
- return;
- }
-
- let now = new Date();
- let deadline = (timeout instanceof Date) ? timeout :
- new Date(now.valueOf() + (typeof timeout == "undefined" ? this.timeout : timeout));
- if (deadline <= now) {
- dump("waitFor timeout: " + test.toString() + "\n");
- // the script will timeout here, so no need to raise a separate
- // timeout exception
- return;
- }
- this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline);
- }
-};
diff --git a/testing/marionette/test_action.js b/testing/marionette/test_action.js
deleted file mode 100644
index 1c58ced766..0000000000
--- a/testing/marionette/test_action.js
+++ /dev/null
@@ -1,627 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/action.js");
-Cu.import("chrome://marionette/content/element.js");
-Cu.import("chrome://marionette/content/error.js");
-
-action.inputStateMap = new Map();
-
-add_test(function test_createAction() {
- Assert.throws(() => new action.Action(), InvalidArgumentError,
- "Missing Action constructor args");
- Assert.throws(() => new action.Action(1, 2), InvalidArgumentError,
- "Missing Action constructor args");
- Assert.throws(
- () => new action.Action(1, 2, "sometype"), /Expected string/, "Non-string arguments.");
- ok(new action.Action("id", "sometype", "sometype"));
-
- run_next_test();
-});
-
-add_test(function test_defaultPointerParameters() {
- let defaultParameters = {pointerType: action.PointerType.Mouse};
- deepEqual(action.PointerParameters.fromJson(), defaultParameters);
-
- run_next_test();
-});
-
-add_test(function test_processPointerParameters() {
- let check = (regex, message, arg) => checkErrors(
- regex, action.PointerParameters.fromJson, [arg], message);
- let parametersData;
- for (let d of ["foo", "", "get", "Get"]) {
- parametersData = {pointerType: d};
- let message = `parametersData: [pointerType: ${parametersData.pointerType}]`;
- check(/Unknown pointerType/, message, parametersData);
- }
- parametersData.pointerType = "mouse"; //TODO "pen";
- deepEqual(action.PointerParameters.fromJson(parametersData),
- {pointerType: "mouse"}); //TODO action.PointerType.Pen});
-
- run_next_test();
-});
-
-add_test(function test_processPointerUpDownAction() {
- let actionItem = {type: "pointerDown"};
- let actionSequence = {type: "pointer", id: "some_id"};
- for (let d of [-1, "a"]) {
- actionItem.button = d;
- checkErrors(
- /Expected 'button' \(.*\) to be >= 0/, action.Action.fromJson, [actionSequence, actionItem],
- `button: ${actionItem.button}`);
- }
- actionItem.button = 5;
- let act = action.Action.fromJson(actionSequence, actionItem);
- equal(act.button, actionItem.button);
-
- run_next_test();
-});
-
-add_test(function test_validateActionDurationAndCoordinates() {
- let actionItem = {};
- let actionSequence = {id: "some_id"};
- let check = function (type, subtype, message = undefined) {
- message = message || `duration: ${actionItem.duration}, subtype: ${subtype}`;
- actionItem.type = subtype;
- actionSequence.type = type;
- checkErrors(/Expected '.*' \(.*\) to be >= 0/,
- action.Action.fromJson, [actionSequence, actionItem], message);
- };
- for (let d of [-1, "a"]) {
- actionItem.duration = d;
- check("none", "pause");
- check("pointer", "pointerMove");
- }
- actionItem.duration = 5000;
- for (let name of ["x", "y"]) {
- actionItem[name] = "a";
- actionItem.type = "pointerMove";
- actionSequence.type = "pointer";
- checkErrors(/Expected '.*' \(.*\) to be an Integer/,
- action.Action.fromJson, [actionSequence, actionItem],
- `duration: ${actionItem.duration}, subtype: pointerMove`);
- }
- run_next_test();
-});
-
-add_test(function test_processPointerMoveActionOriginValidation() {
- let actionSequence = {type: "pointer", id: "some_id"};
- let actionItem = {duration: 5000, type: "pointerMove"};
- for (let d of [-1, {a: "blah"}, []]) {
- actionItem.origin = d;
-
- checkErrors(/Expected \'origin\' to be a string or a web element reference/,
- action.Action.fromJson,
- [actionSequence, actionItem],
- `actionItem.origin: (${getTypeString(d)})`);
- }
-
- run_next_test();
-});
-
-add_test(function test_processPointerMoveActionOriginStringValidation() {
- let actionSequence = {type: "pointer", id: "some_id"};
- let actionItem = {duration: 5000, type: "pointerMove"};
- for (let d of ["a", "", "get", "Get"]) {
- actionItem.origin = d;
- checkErrors(/Unknown pointer-move origin/,
- action.Action.fromJson,
- [actionSequence, actionItem],
- `actionItem.origin: ${d}`);
- }
-
- run_next_test();
-});
-
-add_test(function test_processPointerMoveActionElementOrigin() {
- let actionSequence = {type: "pointer", id: "some_id"};
- let actionItem = {duration: 5000, type: "pointerMove"};
- actionItem.origin = {[element.Key]: "something"};
- let a = action.Action.fromJson(actionSequence, actionItem);
- deepEqual(a.origin, actionItem.origin);
- run_next_test();
-});
-
-add_test(function test_processPointerMoveActionDefaultOrigin() {
- let actionSequence = {type: "pointer", id: "some_id"};
- // origin left undefined
- let actionItem = {duration: 5000, type: "pointerMove"};
- let a = action.Action.fromJson(actionSequence, actionItem);
- deepEqual(a.origin, action.PointerOrigin.Viewport);
- run_next_test();
-});
-
-add_test(function test_processPointerMoveAction() {
- let actionSequence = {id: "some_id", type: "pointer"};
- let actionItems = [
- {
- duration: 5000,
- type: "pointerMove",
- origin: undefined,
- x: undefined,
- y: undefined,
- },
- {
- duration: undefined,
- type: "pointerMove",
- origin: {[element.Key]: "id", [element.LegacyKey]: "id"},
- x: undefined,
- y: undefined,
- },
- {
- duration: 5000,
- type: "pointerMove",
- x: 0,
- y: undefined,
- origin: undefined,
- },
- {
- duration: 5000,
- type: "pointerMove",
- x: 1,
- y: 2,
- origin: undefined,
- },
- ];
- for (let expected of actionItems) {
- let actual = action.Action.fromJson(actionSequence, expected);
- ok(actual instanceof action.Action);
- equal(actual.duration, expected.duration);
- equal(actual.x, expected.x);
- equal(actual.y, expected.y);
-
- let origin = expected.origin;
- if (typeof origin == "undefined") {
- origin = action.PointerOrigin.Viewport;
- }
- deepEqual(actual.origin, origin);
-
- }
- run_next_test();
-});
-
-add_test(function test_computePointerDestinationViewport() {
- let act = { type: "pointerMove", x: 100, y: 200, origin: "viewport"};
- let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
- // these values should not affect the outcome
- inputState.x = "99";
- inputState.y = "10";
- let target = action.computePointerDestination(act, inputState);
- equal(act.x, target.x);
- equal(act.y, target.y);
-
- run_next_test();
-});
-
-add_test(function test_computePointerDestinationPointer() {
- let act = { type: "pointerMove", x: 100, y: 200, origin: "pointer"};
- let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
- inputState.x = 10;
- inputState.y = 99;
- let target = action.computePointerDestination(act, inputState);
- equal(act.x + inputState.x, target.x);
- equal(act.y + inputState.y, target.y);
-
-
- run_next_test();
-});
-
-add_test(function test_computePointerDestinationElement() {
- // origin represents a web element
- // using an object literal instead to test default case in computePointerDestination
- let act = {type: "pointerMove", x: 100, y: 200, origin: {}};
- let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
- let elementCenter = {x: 10, y: 99};
- let target = action.computePointerDestination(act, inputState, elementCenter);
- equal(act.x + elementCenter.x, target.x);
- equal(act.y + elementCenter.y, target.y);
-
- Assert.throws(
- () => action.computePointerDestination(act, inputState, {a: 1}),
- InvalidArgumentError,
- "Invalid element center coordinates.");
-
- Assert.throws(
- () => action.computePointerDestination(act, inputState, undefined),
- InvalidArgumentError,
- "Undefined element center coordinates.");
-
- run_next_test();
-});
-
-add_test(function test_processPointerAction() {
- let actionSequence = {
- type: "pointer",
- id: "some_id",
- parameters: {
- pointerType: "mouse" //TODO "touch"
- },
- };
- let actionItems = [
- {
- duration: 2000,
- type: "pause",
- },
- {
- type: "pointerMove",
- duration: 2000,
- },
- {
- type: "pointerUp",
- button: 1,
- }
- ];
- for (let expected of actionItems) {
- let actual = action.Action.fromJson(actionSequence, expected);
- equal(actual.type, actionSequence.type);
- equal(actual.subtype, expected.type);
- equal(actual.id, actionSequence.id);
- if (expected.type === "pointerUp") {
- equal(actual.button, expected.button);
- } else {
- equal(actual.duration, expected.duration);
- }
- if (expected.type !== "pause") {
- equal(actual.pointerType, actionSequence.parameters.pointerType);
- }
- }
-
- run_next_test();
-});
-
-add_test(function test_processPauseAction() {
- let actionItem = {type: "pause", duration: 5000};
- let actionSequence = {id: "some_id"};
- for (let type of ["none", "key", "pointer"]) {
- actionSequence.type = type;
- let act = action.Action.fromJson(actionSequence, actionItem);
- ok(act instanceof action.Action);
- equal(act.type, type);
- equal(act.subtype, actionItem.type);
- equal(act.id, actionSequence.id);
- equal(act.duration, actionItem.duration);
- }
- actionItem.duration = undefined;
- let act = action.Action.fromJson(actionSequence, actionItem);
- equal(act.duration, actionItem.duration);
-
- run_next_test();
-});
-
-add_test(function test_processActionSubtypeValidation() {
- let actionItem = {type: "dancing"};
- let actionSequence = {id: "some_id"};
- let check = function (regex) {
- let message = `type: ${actionSequence.type}, subtype: ${actionItem.type}`;
- checkErrors(regex, action.Action.fromJson, [actionSequence, actionItem], message);
- };
- for (let type of ["none", "key", "pointer"]) {
- actionSequence.type = type;
- check(new RegExp(`Unknown subtype for ${type} action`));
- }
- run_next_test();
-});
-
-add_test(function test_processKeyActionUpDown() {
- let actionSequence = {type: "key", id: "some_id"};
- let actionItem = {type: "keyDown"};
-
- for (let v of [-1, undefined, [], ["a"], {length: 1}, null]) {
- actionItem.value = v;
- let message = `actionItem.value: (${getTypeString(v)})`;
- Assert.throws(() => action.Action.fromJson(actionSequence, actionItem),
- InvalidArgumentError, message);
- Assert.throws(() => action.Action.fromJson(actionSequence, actionItem),
- /Expected 'value' to be a string that represents single code point/, message);
- }
-
- actionItem.value = "\uE004";
- let act = action.Action.fromJson(actionSequence, actionItem);
- ok(act instanceof action.Action);
- equal(act.type, actionSequence.type);
- equal(act.subtype, actionItem.type);
- equal(act.id, actionSequence.id);
- equal(act.value, actionItem.value);
-
- run_next_test();
-});
-
-add_test(function test_processInputSourceActionSequenceValidation() {
- let actionSequence = {type: "swim", id: "some id"};
- let check = (message, regex) => checkErrors(
- regex, action.Sequence.fromJson, [actionSequence], message);
- check(`actionSequence.type: ${actionSequence.type}`, /Unknown action type/);
- action.inputStateMap.clear();
-
- actionSequence.type = "none";
- actionSequence.id = -1;
- check(`actionSequence.id: ${getTypeString(actionSequence.id)}`,
- /Expected 'id' to be a string/);
- action.inputStateMap.clear();
-
- actionSequence.id = undefined;
- check(`actionSequence.id: ${getTypeString(actionSequence.id)}`,
- /Expected 'id' to be defined/);
- action.inputStateMap.clear();
-
- actionSequence.id = "some_id";
- actionSequence.actions = -1;
- check(`actionSequence.actions: ${getTypeString(actionSequence.actions)}`,
- /Expected 'actionSequence.actions' to be an Array/);
- action.inputStateMap.clear();
-
- run_next_test();
-});
-
-add_test(function test_processInputSourceActionSequence() {
- let actionItem = { type: "pause", duration: 5};
- let actionSequence = {
- type: "none",
- id: "some id",
- actions: [actionItem],
- };
- let expectedAction = new action.Action(actionSequence.id, "none", actionItem.type);
- expectedAction.duration = actionItem.duration;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_processInputSourceActionSequencePointer() {
- let actionItem = {type: "pointerDown", button: 1};
- let actionSequence = {
- type: "pointer",
- id: "9",
- actions: [actionItem],
- parameters: {
- pointerType: "mouse" // TODO "pen"
- },
- };
- let expectedAction = new action.Action(
- actionSequence.id, actionSequence.type, actionItem.type);
- expectedAction.pointerType = actionSequence.parameters.pointerType;
- expectedAction.button = actionItem.button;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_processInputSourceActionSequenceKey() {
- let actionItem = {type: "keyUp", value: "a"};
- let actionSequence = {
- type: "key",
- id: "9",
- actions: [actionItem],
- };
- let expectedAction = new action.Action(
- actionSequence.id, actionSequence.type, actionItem.type);
- expectedAction.value = actionItem.value;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-
-add_test(function test_processInputSourceActionSequenceInputStateMap() {
- let id = "1";
- let actionItem = {type: "pause", duration: 5000};
- let actionSequence = {
- type: "key",
- id: id,
- actions: [actionItem],
- };
- let wrongInputState = new action.InputState.Null();
- action.inputStateMap.set(actionSequence.id, wrongInputState);
- checkErrors(/to be mapped to/, action.Sequence.fromJson, [actionSequence],
- `${actionSequence.type} using ${wrongInputState}`);
- action.inputStateMap.clear();
- let rightInputState = new action.InputState.Key();
- action.inputStateMap.set(id, rightInputState);
- let acts = action.Sequence.fromJson(actionSequence);
- equal(acts.length, 1);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_processPointerActionInputStateMap() {
- let actionItem = {type: "pointerDown"};
- let id = "1";
- let parameters = {pointerType: "mouse"};
- let a = new action.Action(id, "pointer", actionItem.type);
- let wrongInputState = new action.InputState.Key();
- action.inputStateMap.set(id, wrongInputState);
- checkErrors(
- /to be mapped to InputState whose type is/, action.processPointerAction,
- [id, parameters, a],
- `type "pointer" with ${wrongInputState.type} in inputState`);
- action.inputStateMap.clear();
-
- // TODO - uncomment once pen is supported
- //wrongInputState = new action.InputState.Pointer("pen");
- //action.inputStateMap.set(id, wrongInputState);
- //checkErrors(
- // /to be mapped to InputState whose subtype is/, action.processPointerAction,
- // [id, parameters, a],
- // `subtype ${parameters.pointerType} with ${wrongInputState.subtype} in inputState`);
- //action.inputStateMap.clear();
-
- let rightInputState = new action.InputState.Pointer("mouse");
- action.inputStateMap.set(id, rightInputState);
- action.processPointerAction(id, parameters, a);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_createInputState() {
- for (let kind in action.InputState) {
- let state;
- if (kind == "Pointer") {
- state = new action.InputState[kind]("mouse");
- } else {
- state = new action.InputState[kind]();
- }
- ok(state);
- if (kind === "Null") {
- equal(state.type, "none");
- } else {
- equal(state.type, kind.toLowerCase());
- }
- }
- Assert.throws(() => new action.InputState.Pointer(), InvalidArgumentError,
- "Missing InputState.Pointer constructor arg");
- Assert.throws(() => new action.InputState.Pointer("foo"), InvalidArgumentError,
- "Invalid InputState.Pointer constructor arg");
- run_next_test();
-});
-
-add_test(function test_extractActionChainValidation() {
- for (let actions of [-1, "a", undefined, null]) {
- let message = `actions: ${getTypeString(actions)}`;
- Assert.throws(() => action.Chain.fromJson(actions),
- InvalidArgumentError, message);
- Assert.throws(() => action.Chain.fromJson(actions),
- /Expected 'actions' to be an Array/, message);
- }
- run_next_test();
-});
-
-add_test(function test_extractActionChainEmpty() {
- deepEqual(action.Chain.fromJson([]), []);
- run_next_test();
-});
-
-add_test(function test_extractActionChain_oneTickOneInput() {
- let actionItem = {type: "pause", duration: 5000};
- let actionSequence = {
- type: "none",
- id: "some id",
- actions: [actionItem],
- };
- let expectedAction = new action.Action(actionSequence.id, "none", actionItem.type);
- expectedAction.duration = actionItem.duration;
- let actionsByTick = action.Chain.fromJson([actionSequence]);
- equal(1, actionsByTick.length);
- equal(1, actionsByTick[0].length);
- deepEqual(actionsByTick, [[expectedAction]]);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_extractActionChain_twoAndThreeTicks() {
- let mouseActionItems = [
- {
- type: "pointerDown",
- button: 2,
- },
- {
- type: "pointerUp",
- button: 2,
- },
- ];
- let mouseActionSequence = {
- type: "pointer",
- id: "7",
- actions: mouseActionItems,
- parameters: {
- pointerType: "mouse" //TODO "touch"
- },
- };
- let keyActionItems = [
- {
- type: "keyDown",
- value: "a",
- },
- {
- type: "pause",
- duration: 4,
- },
- {
- type: "keyUp",
- value: "a",
- },
- ];
- let keyActionSequence = {
- type: "key",
- id: "1",
- actions: keyActionItems,
- };
- let actionsByTick = action.Chain.fromJson([keyActionSequence, mouseActionSequence]);
- // number of ticks is same as longest action sequence
- equal(keyActionItems.length, actionsByTick.length);
- equal(2, actionsByTick[0].length);
- equal(2, actionsByTick[1].length);
- equal(1, actionsByTick[2].length);
- let expectedAction = new action.Action(keyActionSequence.id, "key", keyActionItems[2].type);
- expectedAction.value = keyActionItems[2].value;
- deepEqual(actionsByTick[2][0], expectedAction);
- action.inputStateMap.clear();
-
- // one empty action sequence
- actionsByTick = action.Chain.fromJson(
- [keyActionSequence, {type: "none", id: "some", actions: []}]);
- equal(keyActionItems.length, actionsByTick.length);
- equal(1, actionsByTick[0].length);
- action.inputStateMap.clear();
- run_next_test();
-});
-
-add_test(function test_computeTickDuration() {
- let expected = 8000;
- let tickActions = [
- {type: "none", subtype: "pause", duration: 5000},
- {type: "key", subtype: "pause", duration: 1000},
- {type: "pointer", subtype: "pointerMove", duration: 6000},
- // invalid because keyDown should not have duration, so duration should be ignored.
- {type: "key", subtype: "keyDown", duration: 100000},
- {type: "pointer", subtype: "pause", duration: expected},
- {type: "pointer", subtype: "pointerUp"},
- ];
- equal(expected, action.computeTickDuration(tickActions));
- run_next_test();
-});
-
-add_test(function test_computeTickDuration_empty() {
- equal(0, action.computeTickDuration([]));
- run_next_test();
-});
-
-add_test(function test_computeTickDuration_noDurations() {
- let tickActions = [
- // invalid because keyDown should not have duration, so duration should be ignored.
- {type: "key", subtype: "keyDown", duration: 100000},
- // undefined duration permitted
- {type: "none", subtype: "pause"},
- {type: "pointer", subtype: "pointerMove"},
- {type: "pointer", subtype: "pointerDown"},
- {type: "key", subtype: "keyUp"},
- ];
-
- equal(0, action.computeTickDuration(tickActions));
- run_next_test();
-});
-
-
-// helpers
-function getTypeString(obj) {
- return Object.prototype.toString.call(obj);
-};
-
-function checkErrors(regex, func, args, message) {
- if (typeof message == "undefined") {
- message = `actionFunc: ${func.name}; args: ${args}`;
- }
- Assert.throws(() => func.apply(this, args), InvalidArgumentError, message);
- Assert.throws(() => func.apply(this, args), regex, message);
-};
diff --git a/testing/marionette/test_assert.js b/testing/marionette/test_assert.js
deleted file mode 100644
index c14f2852e3..0000000000
--- a/testing/marionette/test_assert.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/assert.js");
-Cu.import("chrome://marionette/content/error.js");
-
-add_test(function test_session() {
- assert.session({sessionId: "foo"});
- for (let typ of [null, undefined, ""]) {
- Assert.throws(() => assert.session({sessionId: typ}), InvalidSessionIDError);
- }
-
- run_next_test();
-});
-
-add_test(function test_platforms() {
- // at least one will fail
- let raised;
- for (let fn of [assert.firefox, assert.fennec, assert.b2g, assert.mobile]) {
- try {
- fn();
- } catch (e) {
- raised = e;
- }
- }
- ok(raised instanceof UnsupportedOperationError);
-
- run_next_test();
-});
-
-add_test(function test_defined() {
- assert.defined({});
- Assert.throws(() => assert.defined(undefined), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_number() {
- assert.number(1);
- assert.number(0);
- assert.number(-1);
- assert.number(1.2);
- for (let i of ["foo", "1", {}, [], NaN, Infinity, undefined]) {
- Assert.throws(() => assert.number(i), InvalidArgumentError);
- }
- run_next_test();
-});
-
-add_test(function test_integer() {
- assert.integer(1);
- assert.integer(0);
- assert.integer(-1);
- Assert.throws(() => assert.integer("foo"), InvalidArgumentError);
- Assert.throws(() => assert.integer(1.2), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_positiveInteger() {
- assert.positiveInteger(1);
- assert.positiveInteger(0);
- Assert.throws(() => assert.positiveInteger(-1), InvalidArgumentError);
- Assert.throws(() => assert.positiveInteger("foo"), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_boolean() {
- assert.boolean(true);
- assert.boolean(false);
- Assert.throws(() => assert.boolean("false"), InvalidArgumentError);
- Assert.throws(() => assert.boolean(undefined), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_string() {
- assert.string("foo");
- assert.string(`bar`);
- Assert.throws(() => assert.string(42), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_object() {
- assert.object({});
- assert.object(new Object());
- for (let typ of [42, "foo", true, null, undefined]) {
- Assert.throws(() => assert.object(typ), InvalidArgumentError);
- }
-
- run_next_test();
-});
-
-add_test(function test_in() {
- assert.in("foo", {foo: 42});
- for (let typ of [{}, 42, true, null, undefined]) {
- Assert.throws(() => assert.in("foo", typ), InvalidArgumentError);
- }
-
- run_next_test();
-});
-
-add_test(function test_array() {
- assert.array([]);
- assert.array(new Array());
- Assert.throws(() => assert.array(42), InvalidArgumentError);
- Assert.throws(() => assert.array({}), InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_that() {
- equal(1, assert.that(n => n + 1)(1));
- Assert.throws(() => assert.that(() => false)());
- Assert.throws(() => assert.that(val => val)(false));
- Assert.throws(() => assert.that(val => val, "foo", SessionNotCreatedError)(false),
- SessionNotCreatedError);
-
- run_next_test();
-});
diff --git a/testing/marionette/test_element.js b/testing/marionette/test_element.js
deleted file mode 100644
index f565bd8c02..0000000000
--- a/testing/marionette/test_element.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/* 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/. */
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/element.js");
-
-let el = {
- getBoundingClientRect: function() {
- return {
- top: 0,
- left: 0,
- width: 100,
- height: 100,
- };
- }
-};
-
-add_test(function test_coordinates() {
- let p = element.coordinates(el);
- ok(p.hasOwnProperty("x"));
- ok(p.hasOwnProperty("y"));
- equal("number", typeof p.x);
- equal("number", typeof p.y);
-
- deepEqual({x: 50, y: 50}, element.coordinates(el));
- deepEqual({x: 10, y: 10}, element.coordinates(el, 10, 10));
- deepEqual({x: -5, y: -5}, element.coordinates(el, -5, -5));
-
- Assert.throws(() => element.coordinates(null));
-
- Assert.throws(() => element.coordinates(el, "string", undefined));
- Assert.throws(() => element.coordinates(el, undefined, "string"));
- Assert.throws(() => element.coordinates(el, "string", "string"));
- Assert.throws(() => element.coordinates(el, {}, undefined));
- Assert.throws(() => element.coordinates(el, undefined, {}));
- Assert.throws(() => element.coordinates(el, {}, {}));
- Assert.throws(() => element.coordinates(el, [], undefined));
- Assert.throws(() => element.coordinates(el, undefined, []));
- Assert.throws(() => element.coordinates(el, [], []));
-
- run_next_test();
-});
-
-add_test(function test_isWebElementReference() {
- strictEqual(element.isWebElementReference({[element.Key]: "some_id"}), true);
- strictEqual(element.isWebElementReference({[element.LegacyKey]: "some_id"}), true);
- strictEqual(element.isWebElementReference(
- {[element.LegacyKey]: "some_id", [element.Key]: "2"}), true);
- strictEqual(element.isWebElementReference({}), false);
- strictEqual(element.isWebElementReference({"key": "blah"}), false);
-
- run_next_test();
-});
diff --git a/testing/marionette/test_error.js b/testing/marionette/test_error.js
deleted file mode 100644
index a905f02f06..0000000000
--- a/testing/marionette/test_error.js
+++ /dev/null
@@ -1,431 +0,0 @@
-/* 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/. */
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
-function notok(condition) {
- ok(!(condition));
-}
-
-add_test(function test_isError() {
- notok(error.isError(null));
- notok(error.isError([]));
- notok(error.isError(new Date()));
-
- ok(error.isError(new Components.Exception()));
- ok(error.isError(new Error()));
- ok(error.isError(new EvalError()));
- ok(error.isError(new InternalError()));
- ok(error.isError(new RangeError()));
- ok(error.isError(new ReferenceError()));
- ok(error.isError(new SyntaxError()));
- ok(error.isError(new TypeError()));
- ok(error.isError(new URIError()));
- ok(error.isError(new WebDriverError()));
- ok(error.isError(new InvalidArgumentError()));
-
- run_next_test();
-});
-
-add_test(function test_isWebDriverError() {
- notok(error.isWebDriverError(new Components.Exception()));
- notok(error.isWebDriverError(new Error()));
- notok(error.isWebDriverError(new EvalError()));
- notok(error.isWebDriverError(new InternalError()));
- notok(error.isWebDriverError(new RangeError()));
- notok(error.isWebDriverError(new ReferenceError()));
- notok(error.isWebDriverError(new SyntaxError()));
- notok(error.isWebDriverError(new TypeError()));
- notok(error.isWebDriverError(new URIError()));
-
- ok(error.isWebDriverError(new WebDriverError()));
- ok(error.isWebDriverError(new InvalidArgumentError()));
- ok(error.isWebDriverError(new JavaScriptError()));
-
- run_next_test();
-});
-
-add_test(function test_wrap() {
- // webdriver-derived errors should not be wrapped
- equal(error.wrap(new WebDriverError()).name, "WebDriverError");
- ok(error.wrap(new WebDriverError()) instanceof WebDriverError);
- equal(error.wrap(new InvalidArgumentError()).name, "InvalidArgumentError");
- ok(error.wrap(new InvalidArgumentError()) instanceof WebDriverError);
- ok(error.wrap(new InvalidArgumentError()) instanceof InvalidArgumentError);
-
- // JS errors should be wrapped in WebDriverError
- equal(error.wrap(new Error()).name, "WebDriverError");
- ok(error.wrap(new Error()) instanceof WebDriverError);
- equal(error.wrap(new EvalError()).name, "WebDriverError");
- equal(error.wrap(new InternalError()).name, "WebDriverError");
- equal(error.wrap(new RangeError()).name, "WebDriverError");
- equal(error.wrap(new ReferenceError()).name, "WebDriverError");
- equal(error.wrap(new SyntaxError()).name, "WebDriverError");
- equal(error.wrap(new TypeError()).name, "WebDriverError");
- equal(error.wrap(new URIError()).name, "WebDriverError");
-
- // wrapped JS errors should retain their type
- // as part of the message field
- equal(error.wrap(new WebDriverError("foo")).message, "foo");
- equal(error.wrap(new TypeError("foo")).message, "TypeError: foo");
-
- run_next_test();
-});
-
-add_test(function test_stringify() {
- equal("<unprintable error>", error.stringify());
- equal("<unprintable error>", error.stringify("foo"));
- equal("[object Object]", error.stringify({}));
- equal("[object Object]\nfoo", error.stringify({stack: "foo"}));
- equal("Error: foo", error.stringify(new Error("foo")).split("\n")[0]);
- equal("WebDriverError: foo",
- error.stringify(new WebDriverError("foo")).split("\n")[0]);
- equal("InvalidArgumentError: foo",
- error.stringify(new InvalidArgumentError("foo")).split("\n")[0]);
-
- run_next_test();
-});
-
-add_test(function test_pprint() {
- equal('[object Object] {"foo":"bar"}', error.pprint`${{foo: "bar"}}`);
-
- equal("[object Number] 42", error.pprint`${42}`);
- equal("[object Boolean] true", error.pprint`${true}`);
- equal("[object Undefined] undefined", error.pprint`${undefined}`);
- equal("[object Null] null", error.pprint`${null}`);
-
- let complexObj = {toJSON: () => "foo"};
- equal('[object Object] "foo"', error.pprint`${complexObj}`);
-
- let cyclic = {};
- cyclic.me = cyclic;
- equal("[object Object] <cyclic object value>", error.pprint`${cyclic}`);
-
- let el = {
- nodeType: 1,
- localName: "input",
- id: "foo",
- classList: {length: 1},
- className: "bar baz",
- };
- equal('<input id="foo" class="bar baz">', error.pprint`${el}`);
-
- run_next_test();
-});
-
-add_test(function test_toJSON() {
- let e0 = new WebDriverError();
- let e0s = e0.toJSON();
- equal(e0s.error, "webdriver error");
- equal(e0s.message, "");
- equal(e0s.stacktrace, e0.stack);
-
- let e1 = new WebDriverError("a");
- let e1s = e1.toJSON();
- equal(e1s.message, e1.message);
- equal(e1s.stacktrace, e1.stack);
-
- let e2 = new JavaScriptError("first", "second", "third", "fourth");
- let e2s = e2.toJSON();
- equal(e2.status, e2s.error);
- equal(e2.message, e2s.message);
- ok(e2s.stacktrace.match(/second/));
- ok(e2s.stacktrace.match(/third/));
- ok(e2s.stacktrace.match(/fourth/));
-
- run_next_test();
-});
-
-add_test(function test_fromJSON() {
- Assert.throws(() => WebDriverError.fromJSON({error: "foo"}),
- /Not of WebDriverError descent/);
- Assert.throws(() => WebDriverError.fromJSON({error: "Error"}),
- /Not of WebDriverError descent/);
- Assert.throws(() => WebDriverError.fromJSON({}),
- /Undeserialisable error type/);
- Assert.throws(() => WebDriverError.fromJSON(undefined),
- /TypeError/);
-
- // stacks will be different
- let e1 = new WebDriverError("1");
- let e1r = WebDriverError.fromJSON({error: "webdriver error", message: "1"});
- ok(e1r instanceof WebDriverError);
- equal(e1r.name, e1.name);
- equal(e1r.status, e1.status);
- equal(e1r.message, e1.message);
-
- // stacks will be different
- let e2 = new InvalidArgumentError("2");
- let e2r = WebDriverError.fromJSON({error: "invalid argument", message: "2"});
- ok(e2r instanceof WebDriverError);
- ok(e2r instanceof InvalidArgumentError);
- equal(e2r.name, e2.name);
- equal(e2r.status, e2.status);
- equal(e2r.message, e2.message);
-
- // test stacks
- let e3j = {error: "no such element", message: "3", stacktrace: "4"};
- let e3r = WebDriverError.fromJSON(e3j);
- ok(e3r instanceof WebDriverError);
- ok(e3r instanceof NoSuchElementError);
- equal(e3r.name, "NoSuchElementError");
- equal(e3r.status, e3j.error);
- equal(e3r.message, e3j.message);
- equal(e3r.stack, e3j.stacktrace);
-
- // parity with toJSON
- let e4 = new JavaScriptError("first", "second", "third", "fourth");
- let e4s = e4.toJSON();
- deepEqual(e4, WebDriverError.fromJSON(e4s));
-
- run_next_test();
-});
-
-add_test(function test_WebDriverError() {
- let err = new WebDriverError("foo");
- equal("WebDriverError", err.name);
- equal("foo", err.message);
- equal("webdriver error", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_ElementClickInterceptedError() {
- let otherEl = {
- nodeType: 1,
- localName: "a",
- classList: [],
- };
- let obscuredEl = {
- nodeType: 1,
- localName: "b",
- classList: [],
- ownerDocument: {
- elementFromPoint: function (x, y) {
- return otherEl;
- },
- },
- style: {
- pointerEvents: "auto",
- }
- };
-
- let err1 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2});
- equal("ElementClickInterceptedError", err1.name);
- equal("Element <b> is not clickable at point (1,2) " +
- "because another element <a> obscures it",
- err1.message);
- equal("element click intercepted", err1.status);
- ok(err1 instanceof WebDriverError);
-
- obscuredEl.style.pointerEvents = "none";
- let err2 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2});
- equal("Element <b> is not clickable at point (1,2) " +
- "because it does not have pointer events enabled, " +
- "and element <a> would receive the click instead",
- err2.message);
-
- run_next_test();
-});
-
-add_test(function test_ElementNotAccessibleError() {
- let err = new ElementNotAccessibleError("foo");
- equal("ElementNotAccessibleError", err.name);
- equal("foo", err.message);
- equal("element not accessible", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_ElementNotInteractableError() {
- let err = new ElementNotInteractableError("foo");
- equal("ElementNotInteractableError", err.name);
- equal("foo", err.message);
- equal("element not interactable", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_InvalidArgumentError() {
- let err = new InvalidArgumentError("foo");
- equal("InvalidArgumentError", err.name);
- equal("foo", err.message);
- equal("invalid argument", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_InvalidElementStateError() {
- let err = new InvalidElementStateError("foo");
- equal("InvalidElementStateError", err.name);
- equal("foo", err.message);
- equal("invalid element state", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_InvalidSelectorError() {
- let err = new InvalidSelectorError("foo");
- equal("InvalidSelectorError", err.name);
- equal("foo", err.message);
- equal("invalid selector", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_InvalidSessionIDError() {
- let err = new InvalidSessionIDError("foo");
- equal("InvalidSessionIDError", err.name);
- equal("foo", err.message);
- equal("invalid session id", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_JavaScriptError() {
- let err = new JavaScriptError("foo");
- equal("JavaScriptError", err.name);
- equal("foo", err.message);
- equal("javascript error", err.status);
- ok(err instanceof WebDriverError);
-
- equal("undefined", new JavaScriptError(undefined).message);
- // TODO(ato): Bug 1240550
- //equal("funcname @file", new JavaScriptError("message", "funcname", "file").stack);
- equal("funcname @file, line line",
- new JavaScriptError("message", "funcname", "file", "line").stack);
-
- // TODO(ato): More exhaustive tests for JS stack computation
-
- run_next_test();
-});
-
-add_test(function test_NoAlertOpenError() {
- let err = new NoAlertOpenError("foo");
- equal("NoAlertOpenError", err.name);
- equal("foo", err.message);
- equal("no such alert", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_NoSuchElementError() {
- let err = new NoSuchElementError("foo");
- equal("NoSuchElementError", err.name);
- equal("foo", err.message);
- equal("no such element", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_NoSuchFrameError() {
- let err = new NoSuchFrameError("foo");
- equal("NoSuchFrameError", err.name);
- equal("foo", err.message);
- equal("no such frame", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_NoSuchWindowError() {
- let err = new NoSuchWindowError("foo");
- equal("NoSuchWindowError", err.name);
- equal("foo", err.message);
- equal("no such window", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_ScriptTimeoutError() {
- let err = new ScriptTimeoutError("foo");
- equal("ScriptTimeoutError", err.name);
- equal("foo", err.message);
- equal("script timeout", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_SessionNotCreatedError() {
- let err = new SessionNotCreatedError("foo");
- equal("SessionNotCreatedError", err.name);
- equal("foo", err.message);
- equal("session not created", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_StaleElementReferenceError() {
- let err = new StaleElementReferenceError("foo");
- equal("StaleElementReferenceError", err.name);
- equal("foo", err.message);
- equal("stale element reference", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_TimeoutError() {
- let err = new TimeoutError("foo");
- equal("TimeoutError", err.name);
- equal("foo", err.message);
- equal("timeout", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_UnableToSetCookieError() {
- let err = new UnableToSetCookieError("foo");
- equal("UnableToSetCookieError", err.name);
- equal("foo", err.message);
- equal("unable to set cookie", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_UnknownCommandError() {
- let err = new UnknownCommandError("foo");
- equal("UnknownCommandError", err.name);
- equal("foo", err.message);
- equal("unknown command", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_UnknownError() {
- let err = new UnknownError("foo");
- equal("UnknownError", err.name);
- equal("foo", err.message);
- equal("unknown error", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
-
-add_test(function test_UnsupportedOperationError() {
- let err = new UnsupportedOperationError("foo");
- equal("UnsupportedOperationError", err.name);
- equal("foo", err.message);
- equal("unsupported operation", err.status);
- ok(err instanceof WebDriverError);
-
- run_next_test();
-});
diff --git a/testing/marionette/test_message.js b/testing/marionette/test_message.js
deleted file mode 100644
index 2ef20a4541..0000000000
--- a/testing/marionette/test_message.js
+++ /dev/null
@@ -1,204 +0,0 @@
-/* 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/. */
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/message.js");
-
-add_test(function test_MessageOrigin() {
- equal(0, MessageOrigin.Client);
- equal(1, MessageOrigin.Server);
-
- run_next_test();
-});
-
-add_test(function test_Message_fromMsg() {
- let cmd = new Command(4, "foo");
- let resp = new Response(5, () => {});
-
- ok(Message.fromMsg(cmd.toMsg()) instanceof Command);
- ok(Message.fromMsg(resp.toMsg()) instanceof Response);
- Assert.throws(() => Message.fromMsg([3, 4, 5, 6]),
- /Unrecognised message type in packet/);
-
- run_next_test();
-});
-
-add_test(function test_Command() {
- let cmd = new Command(42, "foo", {bar: "baz"});
- equal(42, cmd.id);
- equal("foo", cmd.name);
- deepEqual({bar: "baz"}, cmd.parameters);
- equal(null, cmd.onerror);
- equal(null, cmd.onresult);
- equal(MessageOrigin.Client, cmd.origin);
- equal(false, cmd.sent);
-
- run_next_test();
-});
-
-add_test(function test_Command_onresponse() {
- let onerrorOk = false;
- let onresultOk = false;
-
- let cmd = new Command();
- cmd.onerror = () => onerrorOk = true;
- cmd.onresult = () => onresultOk = true;
-
- let errorResp = new Response();
- errorResp.error = new WebDriverError("foo");
-
- let bodyResp = new Response();
- bodyResp.body = "bar";
-
- cmd.onresponse(errorResp);
- equal(true, onerrorOk);
- equal(false, onresultOk);
-
- cmd.onresponse(bodyResp);
- equal(true, onresultOk);
-
- run_next_test();
-});
-
-add_test(function test_Command_fromMsg() {
- let cmd = new Command(42, "bar", {bar: "baz"});
- let msg = cmd.toMsg();
-
- equal(Command.TYPE, msg[0]);
- equal(cmd.id, msg[1]);
- equal(cmd.name, msg[2]);
- equal(cmd.parameters, msg[3]);
-
- run_next_test();
-});
-
-add_test(function test_Command_toString() {
- let cmd = new Command(42, "foo", {bar: "baz"});
- equal(`Command {id: ${cmd.id}, ` +
- `name: ${JSON.stringify(cmd.name)}, ` +
- `parameters: ${JSON.stringify(cmd.parameters)}}`,
- cmd.toString());
-
- run_next_test();
-});
-
-add_test(function test_Command_fromMsg() {
- let c1 = new Command(42, "foo", {bar: "baz"});
-
- let msg = c1.toMsg();
- let c2 = Command.fromMsg(msg);
-
- equal(c1.id, c2.id);
- equal(c1.name, c2.name);
- equal(c1.parameters, c2.parameters);
-
- run_next_test();
-});
-
-add_test(function test_Command_TYPE() {
- equal(0, Command.TYPE);
- run_next_test();
-});
-
-add_test(function test_Response() {
- let handler = () => run_next_test();
-
- let resp = new Response(42, handler);
- equal(42, resp.id);
- equal(null, resp.error);
- ok("origin" in resp);
- equal(MessageOrigin.Server, resp.origin);
- equal(false, resp.sent);
- equal(handler, resp.respHandler_);
-
- run_next_test();
-});
-
-add_test(function test_Response_sendConditionally() {
- let fired = false;
- let resp = new Response(42, () => fired = true);
- resp.sendConditionally(r => false);
- equal(false, resp.sent);
- equal(false, fired);
- resp.sendConditionally(r => true);
- equal(true, resp.sent);
- equal(true, fired);
-
- run_next_test();
-});
-
-add_test(function test_Response_send() {
- let fired = false;
- let resp = new Response(42, () => fired = true);
- resp.send();
- equal(true, resp.sent);
- equal(true, fired);
-
- run_next_test();
-});
-
-add_test(function test_Response_sendError() {
- let err = new WebDriverError();
- let resp = new Response(42, r => {
- equal(err.toJSON().error, r.error.error);
- equal(null, r.body);
- equal(false, r.sent);
- });
-
- resp.sendError(err);
- equal(true, resp.sent);
- Assert.throws(() => resp.send(), /already been sent/);
-
- resp.sent = false;
- Assert.throws(() => resp.sendError(new Error()));
-
- run_next_test();
-});
-
-add_test(function test_Response_toMsg() {
- let resp = new Response(42);
- let msg = resp.toMsg();
-
- equal(Response.TYPE, msg[0]);
- equal(resp.id, msg[1]);
- equal(resp.error, msg[2]);
- equal(resp.body, msg[3]);
-
- run_next_test();
-});
-
-add_test(function test_Response_toString() {
- let resp = new Response(42);
- resp.error = "foo";
- resp.body = "bar";
-
- equal(`Response {id: ${resp.id}, ` +
- `error: ${JSON.stringify(resp.error)}, ` +
- `body: ${JSON.stringify(resp.body)}}`,
- resp.toString());
-
- run_next_test();
-});
-
-add_test(function test_Response_fromMsg() {
- let r1 = new Response(42);
- r1.error = "foo";
- r1.body = "bar";
-
- let msg = r1.toMsg();
- let r2 = Response.fromMsg(msg);
-
- equal(r1.id, r2.id);
- equal(r1.error, r2.error);
- equal(r1.body, r2.body);
-
- run_next_test();
-});
-
-add_test(function test_Response_TYPE() {
- equal(1, Response.TYPE);
- run_next_test();
-});
diff --git a/testing/marionette/test_navigate.js b/testing/marionette/test_navigate.js
deleted file mode 100644
index 6fe29ec653..0000000000
--- a/testing/marionette/test_navigate.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/* 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/. */
-
-const {utils: Cu} = Components;
-
-Cu.importGlobalProperties(["URL"]);
-
-Cu.import("chrome://marionette/content/navigate.js");
-
-add_test(function test_isLoadEventExpected() {
- Assert.throws(() => navigate.isLoadEventExpected(undefined),
- /Expected at least one URL/);
-
- equal(true, navigate.isLoadEventExpected("http://a/"));
- equal(true, navigate.isLoadEventExpected("http://a/", "http://a/"));
- equal(true, navigate.isLoadEventExpected("http://a/", "http://a/b"));
- equal(true, navigate.isLoadEventExpected("http://a/", "http://b"));
- equal(true, navigate.isLoadEventExpected("http://a/", "data:text/html;charset=utf-8,foo"));
- equal(true, navigate.isLoadEventExpected("about:blank", "http://a/"));
- equal(true, navigate.isLoadEventExpected("http://a/", "about:blank"));
- equal(true, navigate.isLoadEventExpected("http://a/", "https://a/"));
-
- equal(false, navigate.isLoadEventExpected("http://a/", "javascript:whatever"));
- equal(false, navigate.isLoadEventExpected("http://a/", "http://a/#"));
- equal(false, navigate.isLoadEventExpected("http://a/", "http://a/#b"));
- equal(false, navigate.isLoadEventExpected("http://a/#b", "http://a/#b"));
- equal(false, navigate.isLoadEventExpected("http://a/#b", "http://a/#c"));
- equal(false, navigate.isLoadEventExpected("data:text/html;charset=utf-8,foo", "data:text/html;charset=utf-8,foo#bar"));
- equal(false, navigate.isLoadEventExpected("data:text/html;charset=utf-8,foo", "data:text/html;charset=utf-8,foo#"));
-
- run_next_test();
-});
-
-add_test(function test_IdempotentURL() {
- Assert.throws(() => new navigate.IdempotentURL(undefined));
- Assert.throws(() => new navigate.IdempotentURL(true));
- Assert.throws(() => new navigate.IdempotentURL({}));
- Assert.throws(() => new navigate.IdempotentURL(42));
-
- // propagated URL properties
- let u1 = new URL("http://a/b");
- let u2 = new navigate.IdempotentURL(u1);
- equal(u1.host, u2.host);
- equal(u1.hostname, u2.hostname);
- equal(u1.href, u2.href);
- equal(u1.origin, u2.origin);
- equal(u1.password, u2.password);
- equal(u1.port, u2.port);
- equal(u1.protocol, u2.protocol);
- equal(u1.search, u2.search);
- equal(u1.username, u2.username);
-
- // specialisations
- equal("#b", new navigate.IdempotentURL("http://a/#b").hash);
- equal("#", new navigate.IdempotentURL("http://a/#").hash);
- equal("", new navigate.IdempotentURL("http://a/").hash);
- equal("#bar", new navigate.IdempotentURL("data:text/html;charset=utf-8,foo#bar").hash);
- equal("#", new navigate.IdempotentURL("data:text/html;charset=utf-8,foo#").hash);
- equal("", new navigate.IdempotentURL("data:text/html;charset=utf-8,foo").hash);
-
- equal("/", new navigate.IdempotentURL("http://a/").pathname);
- equal("/", new navigate.IdempotentURL("http://a/#b").pathname);
- equal("text/html;charset=utf-8,foo", new navigate.IdempotentURL("data:text/html;charset=utf-8,foo#bar").pathname);
-
- run_next_test();
-});
diff --git a/testing/marionette/test_session.js b/testing/marionette/test_session.js
deleted file mode 100644
index ef45573a73..0000000000
--- a/testing/marionette/test_session.js
+++ /dev/null
@@ -1,370 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-Cu.import("chrome://marionette/content/error.js");
-Cu.import("chrome://marionette/content/session.js");
-
-add_test(function test_Timeouts_ctor() {
- let ts = new session.Timeouts();
- equal(ts.implicit, 0);
- equal(ts.pageLoad, 300000);
- equal(ts.script, 30000);
-
- run_next_test();
-});
-
-add_test(function test_Timeouts_toString() {
- equal(new session.Timeouts().toString(), "[object session.Timeouts]");
-
- run_next_test();
-});
-
-add_test(function test_Timeouts_toJSON() {
- let ts = new session.Timeouts();
- deepEqual(ts.toJSON(), {"implicit": 0, "page load": 300000, "script": 30000});
-
- run_next_test();
-});
-
-add_test(function test_Timeouts_fromJSON() {
- let json = {
- "implicit": 10,
- "page load": 20,
- "script": 30,
- };
- let ts = session.Timeouts.fromJSON(json);
- equal(ts.implicit, json["implicit"]);
- equal(ts.pageLoad, json["page load"]);
- equal(ts.script, json["script"]);
-
- run_next_test();
-});
-
-add_test(function test_PageLoadStrategy() {
- equal(session.PageLoadStrategy.None, "none");
- equal(session.PageLoadStrategy.Eager, "eager");
- equal(session.PageLoadStrategy.Normal, "normal");
-
- run_next_test();
-});
-
-add_test(function test_Proxy_ctor() {
- let p = new session.Proxy();
- let props = [
- "proxyType",
- "httpProxy",
- "httpProxyPort",
- "sslProxy",
- "sslProxyPort",
- "ftpProxy",
- "ftpProxyPort",
- "socksProxy",
- "socksProxyPort",
- "socksVersion",
- "proxyAutoconfigUrl",
- ];
- for (let prop of props) {
- ok(prop in p, `${prop} in ${JSON.stringify(props)}`);
- equal(p[prop], null);
- }
-
- run_next_test();
-});
-
-add_test(function test_Proxy_init() {
- let p = new session.Proxy();
-
- // no changed made, and 5 (system) is default
- equal(p.init(), false);
- equal(Preferences.get("network.proxy.type"), 5);
-
- // pac
- p.proxyType = "pac";
- p.proxyAutoconfigUrl = "http://localhost:1234";
- ok(p.init());
-
- equal(Preferences.get("network.proxy.type"), 2);
- equal(Preferences.get("network.proxy.autoconfig_url"),
- "http://localhost:1234");
-
- // autodetect
- p = new session.Proxy();
- p.proxyType = "autodetect";
- ok(p.init());
- equal(Preferences.get("network.proxy.type"), 4);
-
- // system
- p = new session.Proxy();
- p.proxyType = "system";
- ok(p.init());
- equal(Preferences.get("network.proxy.type"), 5);
-
- // noproxy
- p = new session.Proxy();
- p.proxyType = "noproxy";
- ok(p.init());
- equal(Preferences.get("network.proxy.type"), 0);
-
- run_next_test();
-});
-
-add_test(function test_Proxy_toString() {
- equal(new session.Proxy().toString(), "[object session.Proxy]");
-
- run_next_test();
-});
-
-add_test(function test_Proxy_toJSON() {
- let p = new session.Proxy();
- deepEqual(p.toJSON(), {});
-
- p = new session.Proxy();
- p.proxyType = "manual";
- deepEqual(p.toJSON(), {proxyType: "manual"});
-
- run_next_test();
-});
-
-add_test(function test_Proxy_fromJSON() {
- deepEqual({}, session.Proxy.fromJSON(undefined).toJSON());
- deepEqual({}, session.Proxy.fromJSON(null).toJSON());
-
- for (let typ of [true, 42, "foo", []]) {
- Assert.throws(() => session.Proxy.fromJSON(typ), InvalidArgumentError);
- }
-
- // must contain proxyType
- Assert.throws(() => session.Proxy.fromJSON({}), InvalidArgumentError);
- deepEqual({proxyType: "foo"},
- session.Proxy.fromJSON({proxyType: "foo"}).toJSON());
-
- // manual
- session.Proxy.fromJSON({proxyType: "manual"});
-
- for (let proxy of ["httpProxy", "sslProxy", "ftpProxy", "socksProxy"]) {
- let manual = {proxyType: "manual"};
-
- for (let typ of [true, 42, [], {}, null]) {
- manual[proxy] = typ;
- Assert.throws(() => session.Proxy.fromJSON(manual),
- InvalidArgumentError);
- }
-
- manual[proxy] = "foo";
- Assert.throws(() => session.Proxy.fromJSON(manual),
- InvalidArgumentError);
-
- for (let typ of ["bar", true, [], {}, null, undefined]) {
- manual[proxy + "Port"] = typ;
- Assert.throws(() => session.Proxy.fromJSON(manual),
- InvalidArgumentError);
- }
-
- manual[proxy] = "foo";
- manual[proxy + "Port"] = 1234;
-
- let expected = {
- "proxyType": "manual",
- [proxy]: "foo",
- [proxy + "Port"]: 1234,
- };
-
- if (proxy == "socksProxy") {
- manual.socksProxyVersion = 42;
- expected.socksProxyVersion = 42;
- }
- deepEqual(expected, session.Proxy.fromJSON(manual).toJSON());
- }
-
- Assert.throws(() => session.Proxy.fromJSON(
- {proxyType: "manual", socksProxy: "foo", socksProxyPort: 1234}),
- InvalidArgumentError);
-
- run_next_test();
-});
-
-add_test(function test_Capabilities_ctor() {
- let caps = new session.Capabilities();
- ok(caps.has("browserName"));
- ok(caps.has("browserVersion"));
- ok(caps.has("platformName"));
- ok(caps.has("platformVersion"));
- equal(session.PageLoadStrategy.Normal, caps.get("pageLoadStrategy"));
- equal(false, caps.get("acceptInsecureCerts"));
- ok(caps.get("timeouts") instanceof session.Timeouts);
- ok(caps.get("proxy") instanceof session.Proxy);
-
- ok(caps.has("rotatable"));
-
- equal(0, caps.get("specificationLevel"));
- ok(caps.has("moz:processID"));
- ok(caps.has("moz:profile"));
- equal(false, caps.get("moz:accessibilityChecks"));
-
- run_next_test();
-});
-
-add_test(function test_Capabilities_toString() {
- equal("[object session.Capabilities]", new session.Capabilities().toString());
-
- run_next_test();
-});
-
-add_test(function test_Capabilities_toJSON() {
- let caps = new session.Capabilities();
- let json = caps.toJSON();
-
- equal(caps.get("browserName"), json.browserName);
- equal(caps.get("browserVersion"), json.browserVersion);
- equal(caps.get("platformName"), json.platformName);
- equal(caps.get("platformVersion"), json.platformVersion);
- equal(caps.get("pageLoadStrategy"), json.pageLoadStrategy);
- equal(caps.get("acceptInsecureCerts"), json.acceptInsecureCerts);
- deepEqual(caps.get("timeouts").toJSON(), json.timeouts);
- equal(undefined, json.proxy);
-
- equal(caps.get("rotatable"), json.rotatable);
-
- equal(caps.get("specificationLevel"), json.specificationLevel);
- equal(caps.get("moz:processID"), json["moz:processID"]);
- equal(caps.get("moz:profile"), json["moz:profile"]);
- equal(caps.get("moz:accessibilityChecks"), json["moz:accessibilityChecks"]);
-
- run_next_test();
-});
-
-add_test(function test_Capabilities_fromJSON() {
- const {fromJSON} = session.Capabilities;
-
- // plain
- for (let typ of [{}, null, undefined]) {
- ok(fromJSON(typ, {merge: true}).has("browserName"));
- ok(fromJSON(typ, {merge: false}).has("browserName"));
- }
- for (let typ of [true, 42, "foo", []]) {
- Assert.throws(() =>
- fromJSON(typ, {merge: true}), InvalidArgumentError);
- Assert.throws(() =>
- fromJSON(typ, {merge: false}), InvalidArgumentError);
- }
-
- // merging
- let desired = {"moz:accessibilityChecks": false};
- let required = {"moz:accessibilityChecks": true};
- let matched = fromJSON(
- {desiredCapabilities: desired, requiredCapabilities: required},
- {merge: true});
- ok(matched.has("moz:accessibilityChecks"));
- equal(true, matched.get("moz:accessibilityChecks"));
-
- // desiredCapabilities/requriedCapabilities types
- for (let typ of [undefined, null, {}]) {
- ok(fromJSON({desiredCapabilities: typ}, {merge: true}));
- ok(fromJSON({requiredCapabilities: typ}, {merge: true}));
- }
- for (let typ of [true, 42, "foo", []]) {
- Assert.throws(() => fromJSON({desiredCapabilities: typ}, {merge: true}));
- Assert.throws(() => fromJSON({requiredCapabilities: typ}, {merge: true}));
- }
-
- // matching
- let caps = new session.Capabilities();
-
- ok(fromJSON({browserName: caps.get("browserName")}));
- ok(fromJSON({browserName: null}));
- ok(fromJSON({browserName: undefined}));
- ok(fromJSON({browserName: "*"}));
- Assert.throws(() => fromJSON({browserName: "foo"}));
-
- ok(fromJSON({browserVersion: caps.get("browserVersion")}));
- ok(fromJSON({browserVersion: null}));
- ok(fromJSON({browserVersion: undefined}));
- ok(fromJSON({browserVersion: "*"}));
- Assert.throws(() => fromJSON({browserVersion: "foo"}));
-
- ok(fromJSON({platformName: caps.get("platformName")}));
- ok(fromJSON({platformName: null}));
- ok(fromJSON({platformName: undefined}));
- ok(fromJSON({platformName: "*"}));
- Assert.throws(() => fromJSON({platformName: "foo"}));
-
- ok(fromJSON({platformVersion: caps.get("platformVersion")}));
- ok(fromJSON({platformVersion: null}));
- ok(fromJSON({platformVersion: undefined}));
- ok(fromJSON({platformVersion: "*"}));
- Assert.throws(() => fromJSON({platformVersion: "foo"}));
-
- caps = fromJSON({acceptInsecureCerts: true});
- equal(true, caps.get("acceptInsecureCerts"));
- caps = fromJSON({acceptInsecureCerts: false});
- equal(false, caps.get("acceptInsecureCerts"));
- Assert.throws(() => fromJSON({acceptInsecureCerts: "foo"}));
-
- for (let strategy of Object.values(session.PageLoadStrategy)) {
- caps = fromJSON({pageLoadStrategy: strategy});
- equal(strategy, caps.get("pageLoadStrategy"));
- }
- Assert.throws(() => fromJSON({pageLoadStrategy: "foo"}));
-
- let proxyConfig = {proxyType: "manual"};
- caps = fromJSON({proxy: proxyConfig});
- equal("manual", caps.get("proxy").proxyType);
-
- let timeoutsConfig = {implicit: 123};
- caps = fromJSON({timeouts: timeoutsConfig});
- equal(123, caps.get("timeouts").implicit);
-
- equal(0, caps.get("specificationLevel"));
- caps = fromJSON({specificationLevel: 123});
- equal(123, caps.get("specificationLevel"));
- Assert.throws(() => fromJSON({specificationLevel: "foo"}));
- Assert.throws(() => fromJSON({specificationLevel: -1}));
-
- caps = fromJSON({"moz:accessibilityChecks": true});
- equal(true, caps.get("moz:accessibilityChecks"));
- caps = fromJSON({"moz:accessibilityChecks": false});
- equal(false, caps.get("moz:accessibilityChecks"));
- Assert.throws(() => fromJSON({"moz:accessibilityChecks": "foo"}));
-
- run_next_test();
-});
-
-// use session.Proxy.toJSON to test marshal
-add_test(function test_marshal() {
- let proxy = new session.Proxy();
-
- // drop empty fields
- deepEqual({}, proxy.toJSON());
- proxy.proxyType = "manual";
- deepEqual({proxyType: "manual"}, proxy.toJSON());
- proxy.proxyType = null;
- deepEqual({}, proxy.toJSON());
- proxy.proxyType = undefined;
- deepEqual({}, proxy.toJSON());
-
- // iterate over object literals
- proxy.proxyType = {foo: "bar"};
- deepEqual({proxyType: {foo: "bar"}}, proxy.toJSON());
-
- // iterate over complex object that implement toJSON
- proxy.proxyType = new session.Proxy();
- deepEqual({}, proxy.toJSON());
- proxy.proxyType.proxyType = "manual";
- deepEqual({proxyType: {proxyType: "manual"}}, proxy.toJSON());
-
- // drop objects with no entries
- proxy.proxyType = {foo: {}};
- deepEqual({}, proxy.toJSON());
- proxy.proxyType = {foo: new session.Proxy()};
- deepEqual({}, proxy.toJSON());
-
- run_next_test();
-});
diff --git a/testing/marionette/unit.ini b/testing/marionette/unit.ini
deleted file mode 100644
index 082106267f..0000000000
--- a/testing/marionette/unit.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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/.
-
-# xpcshell unit tests for Marionette
-
-[DEFAULT]
-skip-if = appname == "thunderbird"
-
-[test_action.js]
-[test_assert.js]
-[test_element.js]
-[test_error.js]
-[test_message.js]
-[test_navigate.js]
-[test_session.js]