Unreviewed. Update W3C WebDriver imported tests.
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Mar 2018 07:56:41 +0000 (07:56 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Mar 2018 07:56:41 +0000 (07:56 +0000)
* imported/w3c/importer.json:
* imported/w3c/tools/webdriver/webdriver/transport.py:
* imported/w3c/tools/wptrunner/MANIFEST.in:
* imported/w3c/tools/wptrunner/README.rst:
* imported/w3c/tools/wptrunner/requirements.txt:
* imported/w3c/tools/wptrunner/requirements_chrome.txt:
* imported/w3c/tools/wptrunner/requirements_edge.txt:
* imported/w3c/tools/wptrunner/requirements_firefox.txt:
* imported/w3c/tools/wptrunner/requirements_ie.txt:
* imported/w3c/tools/wptrunner/requirements_opera.txt:
* imported/w3c/tools/wptrunner/requirements_sauce.txt:
* imported/w3c/tools/wptrunner/requirements_servo.txt:
* imported/w3c/tools/wptrunner/setup.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/chrome.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/chrome_android.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/edge.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/ie.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/opera.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/server-locations.txt: Removed.
* imported/w3c/tools/wptrunner/wptrunner/browsers/servo.py:
* imported/w3c/tools/wptrunner/wptrunner/browsers/servodriver.py:
* imported/w3c/tools/wptrunner/wptrunner/config.json: Removed.
* imported/w3c/tools/wptrunner/wptrunner/environment.py:
* imported/w3c/tools/wptrunner/wptrunner/executors/executorservo.py:
* imported/w3c/tools/wptrunner/wptrunner/font.py:
* imported/w3c/tools/wptrunner/wptrunner/hosts.py: Removed.
* imported/w3c/tools/wptrunner/wptrunner/testrunner.py:
* imported/w3c/tools/wptrunner/wptrunner/tests/browsers/__init__.py: Added.
* imported/w3c/tools/wptrunner/wptrunner/tests/test_hosts.py: Removed.
* imported/w3c/tools/wptrunner/wptrunner/webdriver_server.py:
* imported/w3c/tools/wptrunner/wptrunner/wptrunner.py:
* imported/w3c/webdriver/OWNERS:
* imported/w3c/webdriver/tests/actions/mouse.py:
* imported/w3c/webdriver/tests/actions/mouse_dblclick.py:
* imported/w3c/webdriver/tests/actions/pointer_origin.py: Added.
* imported/w3c/webdriver/tests/actions/support/mouse.py:
* imported/w3c/webdriver/tests/element_click/bubbling.py:
* imported/w3c/webdriver/tests/element_click/select.py:
* imported/w3c/webdriver/tests/element_send_keys/form_controls.py:
* imported/w3c/webdriver/tests/element_send_keys/interactability.py:
* imported/w3c/webdriver/tests/execute_script/cyclic.py:
* imported/w3c/webdriver/tests/fullscreen_window.py:
* imported/w3c/webdriver/tests/interface.html:
* imported/w3c/webdriver/tests/state/get_element_property.py:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229166 268f45cc-cd09-0410-ab3c-d52691b4dbfc

47 files changed:
WebDriverTests/ChangeLog
WebDriverTests/imported/w3c/importer.json
WebDriverTests/imported/w3c/tools/webdriver/webdriver/transport.py
WebDriverTests/imported/w3c/tools/wptrunner/MANIFEST.in
WebDriverTests/imported/w3c/tools/wptrunner/README.rst
WebDriverTests/imported/w3c/tools/wptrunner/requirements.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_chrome.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_edge.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_firefox.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_ie.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_opera.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_sauce.txt
WebDriverTests/imported/w3c/tools/wptrunner/requirements_servo.txt
WebDriverTests/imported/w3c/tools/wptrunner/setup.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/chrome.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/chrome_android.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/edge.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/ie.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/opera.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/server-locations.txt [deleted file]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/servo.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/servodriver.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/config.json [deleted file]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/environment.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/executors/executorservo.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/font.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/hosts.py [deleted file]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/testrunner.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/__init__.py [new file with mode: 0644]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/test_hosts.py [deleted file]
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/webdriver_server.py
WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/wptrunner.py
WebDriverTests/imported/w3c/webdriver/OWNERS
WebDriverTests/imported/w3c/webdriver/tests/actions/mouse.py
WebDriverTests/imported/w3c/webdriver/tests/actions/mouse_dblclick.py
WebDriverTests/imported/w3c/webdriver/tests/actions/pointer_origin.py [new file with mode: 0644]
WebDriverTests/imported/w3c/webdriver/tests/actions/support/mouse.py
WebDriverTests/imported/w3c/webdriver/tests/element_click/bubbling.py
WebDriverTests/imported/w3c/webdriver/tests/element_click/select.py
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/form_controls.py
WebDriverTests/imported/w3c/webdriver/tests/element_send_keys/interactability.py
WebDriverTests/imported/w3c/webdriver/tests/execute_script/cyclic.py
WebDriverTests/imported/w3c/webdriver/tests/fullscreen_window.py
WebDriverTests/imported/w3c/webdriver/tests/interface.html
WebDriverTests/imported/w3c/webdriver/tests/state/get_element_property.py

index a76edf9..5598a30 100644 (file)
@@ -1,3 +1,54 @@
+2018-03-01  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        Unreviewed. Update W3C WebDriver imported tests.
+
+        * imported/w3c/importer.json:
+        * imported/w3c/tools/webdriver/webdriver/transport.py:
+        * imported/w3c/tools/wptrunner/MANIFEST.in:
+        * imported/w3c/tools/wptrunner/README.rst:
+        * imported/w3c/tools/wptrunner/requirements.txt:
+        * imported/w3c/tools/wptrunner/requirements_chrome.txt:
+        * imported/w3c/tools/wptrunner/requirements_edge.txt:
+        * imported/w3c/tools/wptrunner/requirements_firefox.txt:
+        * imported/w3c/tools/wptrunner/requirements_ie.txt:
+        * imported/w3c/tools/wptrunner/requirements_opera.txt:
+        * imported/w3c/tools/wptrunner/requirements_sauce.txt:
+        * imported/w3c/tools/wptrunner/requirements_servo.txt:
+        * imported/w3c/tools/wptrunner/setup.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/chrome.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/chrome_android.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/edge.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/firefox.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/ie.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/opera.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/sauce.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/server-locations.txt: Removed.
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/servo.py:
+        * imported/w3c/tools/wptrunner/wptrunner/browsers/servodriver.py:
+        * imported/w3c/tools/wptrunner/wptrunner/config.json: Removed.
+        * imported/w3c/tools/wptrunner/wptrunner/environment.py:
+        * imported/w3c/tools/wptrunner/wptrunner/executors/executorservo.py:
+        * imported/w3c/tools/wptrunner/wptrunner/font.py:
+        * imported/w3c/tools/wptrunner/wptrunner/hosts.py: Removed.
+        * imported/w3c/tools/wptrunner/wptrunner/testrunner.py:
+        * imported/w3c/tools/wptrunner/wptrunner/tests/browsers/__init__.py: Added.
+        * imported/w3c/tools/wptrunner/wptrunner/tests/test_hosts.py: Removed.
+        * imported/w3c/tools/wptrunner/wptrunner/webdriver_server.py:
+        * imported/w3c/tools/wptrunner/wptrunner/wptrunner.py:
+        * imported/w3c/webdriver/OWNERS:
+        * imported/w3c/webdriver/tests/actions/mouse.py:
+        * imported/w3c/webdriver/tests/actions/mouse_dblclick.py:
+        * imported/w3c/webdriver/tests/actions/pointer_origin.py: Added.
+        * imported/w3c/webdriver/tests/actions/support/mouse.py:
+        * imported/w3c/webdriver/tests/element_click/bubbling.py:
+        * imported/w3c/webdriver/tests/element_click/select.py:
+        * imported/w3c/webdriver/tests/element_send_keys/form_controls.py:
+        * imported/w3c/webdriver/tests/element_send_keys/interactability.py:
+        * imported/w3c/webdriver/tests/execute_script/cyclic.py:
+        * imported/w3c/webdriver/tests/fullscreen_window.py:
+        * imported/w3c/webdriver/tests/interface.html:
+        * imported/w3c/webdriver/tests/state/get_element_property.py:
+
 2018-02-02  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Update Selenium WebDriver imported tests.
index 5395bd2..fb47860 100644 (file)
@@ -1,6 +1,6 @@
 {
     "repository": "https://github.com/w3c/web-platform-tests.git",
-    "revision": "d848423ebc60882f98b6712d03ffe23af1ff7741",
+    "revision": "549b9cc8d48cfb683eecb3fd3909f93001d2e8f6",
     "paths_to_import": [
         "tools/webdriver",
         "tools/wptrunner",
index d62271f..9a1670a 100644 (file)
@@ -39,8 +39,8 @@ class Response(object):
         try:
             body = json.load(http_response, cls=decoder, **kwargs)
         except ValueError:
-            raise ValueError("Failed to decode response body as JSON:\n"
-                "%s" % json.dumps(body, indent=2))
+            raise ValueError("Failed to decode response body as JSON:\n" +
+                http_response.read())
 
         return cls(http_response.status, body)
 
index 7083923..d36344f 100644 (file)
@@ -4,5 +4,3 @@ include wptrunner.default.ini
 include wptrunner/testharness_runner.html
 include wptrunner/*.js
 include wptrunner/executors/*.js
-include wptrunner/config.json
-include wptrunner/browsers/server-locations.txt
\ No newline at end of file
index 834e07e..4890e3a 100644 (file)
@@ -197,7 +197,7 @@ language e.g.::
 
   if debug and (platform == "linux" or platform == "osx"): FAIL
 
-For test expectations the avaliable variables are those in the
+For test expectations the available variables are those in the
 `run_info` which for desktop are `version`, `os`, `bits`, `processor`,
 `debug` and `product`.
 
index 8281f6d..6da3a33 100644 (file)
@@ -1,5 +1,5 @@
-html5lib >= 0.99
-mozinfo >= 0.7
-mozlog >= 3.5
-mozdebug >= 0.1
-urllib3[secure]
+html5lib == 1.0.1
+mozinfo == 0.10
+mozlog == 3.7
+mozdebug == 0.1
+urllib3[secure] == 1.22
index 44b7f5a..43413cf 100644 (file)
@@ -1,6 +1,6 @@
-marionette_driver >= 2.4
-mozprofile >= 0.21
-mozprocess >= 0.19
-mozcrash >= 0.13
-mozrunner >= 6.7
-mozleak >= 0.1
+marionette_driver == 2.5.0
+mozprofile == 0.29
+mozprocess == 0.26
+mozcrash == 1.0
+mozrunner == 6.14
+mozleak == 0.1
index 7da5141..63d3edd 100644 (file)
@@ -50,9 +50,7 @@ setup(name=PACKAGE_NAME,
                                   "executors/reftest-wait.js",
                                   "testharnessreport.js",
                                   "testharness_runner.html",
-                                  "config.json",
                                   "wptrunner.default.ini",
-                                  "browsers/server-locations.txt",
                                   "browsers/sauce_setup/*",
                                   "prefs/*"]},
       include_package_data=True,
index 215fccf..7f9a21c 100644 (file)
@@ -60,8 +60,7 @@ def env_extras(**kwargs):
 
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true"}
+    return {"bind_hostname": "true"}
 
 
 class ChromeBrowser(Browser):
index 9e53bc6..3e832cb 100644 (file)
@@ -1,3 +1,6 @@
+import subprocess
+
+from ..config import *
 from .base import Browser, ExecutorBrowser, require_arg
 from ..webdriver_server import ChromeDriverServer
 from ..executors import executor_kwargs as base_executor_kwargs
@@ -17,6 +20,8 @@ __wptrunner__ = {"product": "chrome_android",
                  "env_extras": "env_extras",
                  "env_options": "env_options"}
 
+_wptserve_ports = set()
+
 
 def check_args(**kwargs):
     require_arg(kwargs, "webdriver_binary")
@@ -32,13 +37,19 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
                     **kwargs):
     from selenium.webdriver import DesiredCapabilities
 
+    # Use extend() to modify the global list in place.
+    _wptserve_ports.update(set(
+        server_config['ports']['http'] + server_config['ports']['https'] +
+        server_config['ports']['ws'] + server_config['ports']['wss']
+    ))
+
     executor_kwargs = base_executor_kwargs(test_type, server_config,
                                            cache_manager, **kwargs)
     executor_kwargs["close_after_done"] = True
     capabilities = dict(DesiredCapabilities.CHROME.items())
     capabilities["chromeOptions"] = {}
     # required to start on mobile
-    capabilities["chromeOptions"]["androidPackage"] = "com.android.chrome"
+    capabilities["chromeOptions"]["androidPackage"] = "com.google.android.apps.chrome"
 
     for (kwarg, capability) in [("binary", "binary"), ("binary_args", "args")]:
         if kwargs[kwarg] is not None:
@@ -57,8 +68,7 @@ def env_extras(**kwargs):
 
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true"}
+    return {"bind_hostname": "true"}
 
 
 class ChromeAndroidBrowser(Browser):
@@ -76,6 +86,17 @@ class ChromeAndroidBrowser(Browser):
                                          binary=webdriver_binary,
                                          args=webdriver_args)
 
+    def _adb_run(self, args):
+        self.logger.info('adb ' + ' '.join(args))
+        subprocess.check_call(['adb'] + args)
+
+    def setup(self):
+        self._adb_run(['wait-for-device'])
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+        for port in _wptserve_ports:
+            self._adb_run(['reverse', 'tcp:%d' % port, 'tcp:%d' % port])
+
     def start(self, **kwargs):
         self.server.start(block=False)
 
@@ -93,6 +114,8 @@ class ChromeAndroidBrowser(Browser):
 
     def cleanup(self):
         self.stop()
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
 
     def executor_browser(self):
         return ExecutorBrowser, {"webdriver_url": self.server.url}
index db4ae00..094405c 100644 (file)
@@ -38,8 +38,7 @@ def env_extras(**kwargs):
     return []
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true",
+    return {"bind_hostname": "true",
             "supports_debugger": False}
 
 class EdgeBrowser(Browser):
index 6d1f58d..acec0ef 100644 (file)
@@ -3,12 +3,12 @@ import platform
 import signal
 import subprocess
 import sys
+import tempfile
 
 import mozinfo
 import mozleak
 from mozprocess import ProcessHandler
 from mozprofile import FirefoxProfile, Preferences
-from mozprofile.permissions import ServerLocations
 from mozrunner import FirefoxRunner
 from mozrunner.utils import get_stack_fixer_function
 from mozcrash import mozcrash
@@ -23,7 +23,6 @@ from ..executors import executor_kwargs as base_executor_kwargs
 from ..executors.executormarionette import (MarionetteTestharnessExecutor,
                                             MarionetteRefTestExecutor,
                                             MarionetteWdspecExecutor)
-from ..environment import hostnames
 
 
 here = os.path.join(os.path.split(__file__)[0])
@@ -80,7 +79,8 @@ def browser_kwargs(test_type, run_info_data, **kwargs):
                                                          **kwargs),
             "leak_check": kwargs["leak_check"],
             "stylo_threads": kwargs["stylo_threads"],
-            "chaos_mode_flags": kwargs["chaos_mode_flags"]}
+            "chaos_mode_flags": kwargs["chaos_mode_flags"],
+            "config": kwargs["config"]}
 
 
 def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
@@ -102,7 +102,7 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
         if kwargs["binary_args"]:
             options["args"] = kwargs["binary_args"]
         options["prefs"] = {
-            "network.dns.localDomains": ",".join(hostnames)
+            "network.dns.localDomains": ",".join(server_config['domains'].values())
         }
         capabilities["moz:firefoxOptions"] = options
     if kwargs["certutil_binary"] is None:
@@ -117,6 +117,11 @@ def env_extras(**kwargs):
 
 
 def env_options():
+    # The server host is set to 127.0.0.1 as Firefox is configured (through the
+    # network.dns.localDomains preference set below) to resolve the test
+    # domains to localhost without relying on the network stack.
+    #
+    # https://github.com/w3c/web-platform-tests/pull/9480
     return {"host": "127.0.0.1",
             "external_host": "web-platform.test",
             "bind_hostname": "false",
@@ -143,7 +148,7 @@ class FirefoxBrowser(Browser):
                  symbols_path=None, stackwalk_binary=None, certutil_binary=None,
                  ca_certificate_path=None, e10s=False, stackfix_dir=None,
                  binary_args=None, timeout_multiplier=None, leak_check=False, stylo_threads=1,
-                 chaos_mode_flags=None):
+                 chaos_mode_flags=None, config=None):
         Browser.__init__(self, logger)
         self.binary = binary
         self.prefs_root = prefs_root
@@ -159,6 +164,7 @@ class FirefoxBrowser(Browser):
         self.certutil_binary = certutil_binary
         self.e10s = e10s
         self.binary_args = binary_args
+        self.config = config
         if stackfix_dir:
             self.stack_fixer = get_stack_fixer_function(stackfix_dir,
                                                         self.symbols_path)
@@ -189,15 +195,12 @@ class FirefoxBrowser(Browser):
         if self.chaos_mode_flags is not None:
             env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
 
-        locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
-
         preferences = self.load_prefs()
 
-        self.profile = FirefoxProfile(locations=locations,
-                                      preferences=preferences)
+        self.profile = FirefoxProfile(preferences=preferences)
         self.profile.set_preferences({"marionette.port": self.marionette_port,
                                       "dom.disable_open_during_load": False,
-                                      "network.dns.localDomains": ",".join(hostnames),
+                                      "network.dns.localDomains": ",".join(self.config['domains'].values()),
                                       "network.proxy.type": 0,
                                       "places.history.enabled": False,
                                       "dom.send_after_paint_to_content": True,
index 13f5827..9c0007e 100644 (file)
@@ -42,8 +42,7 @@ def env_extras(**kwargs):
     return []
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true",
+    return {"bind_hostname": "true",
             "supports_debugger": False}
 
 class InternetExplorerBrowser(Browser):
index 57edfa0..693a19a 100644 (file)
@@ -60,8 +60,7 @@ def env_extras(**kwargs):
 
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true"}
+    return {"bind_hostname": "true"}
 
 
 class OperaBrowser(Browser):
index 4c1be1c..69ebc07 100644 (file)
@@ -113,8 +113,7 @@ def env_extras(**kwargs):
 
 
 def env_options():
-    return {"host": "web-platform.test",
-            "bind_hostname": "true",
+    return {"bind_hostname": "true",
             "supports_debugger": False}
 
 
@@ -134,8 +133,23 @@ class SauceConnect():
         self.sauce_connect_binary = kwargs.get("sauce_connect_binary")
         self.sc_process = None
         self.temp_dir = None
+        self.env_config = None
+
+    def __call__(self, env_options, env_config):
+        self.env_config = env_config
+
+        return self
+
+    def __enter__(self):
+        # Because this class implements the context manager protocol, it is
+        # possible for instances to be provided to the `with` statement
+        # directly. This class implements the callable protocol so that data
+        # which is not available during object initialization can be provided
+        # prior to this moment. Instances must be invoked in preparation for
+        # the context manager protocol, but this additional constraint is not
+        # itself part of the protocol.
+        assert self.env_config is not None, 'The instance has been invoked.'
 
-    def __enter__(self, options):
         if not self.sauce_connect_binary:
             self.temp_dir = tempfile.mkdtemp()
             get_tar("https://saucelabs.com/downloads/sc-4.4.9-linux.tar.gz", self.temp_dir)
@@ -153,8 +167,7 @@ class SauceConnect():
             "--metrics-address=0.0.0.0:9876",
             "--readyfile=./sauce_is_ready",
             "--tunnel-domains",
-            "web-platform.test",
-            "*.web-platform.test"
+            ",".join(self.env_config['domains'].values())
         ])
 
         # Timeout config vars
@@ -181,6 +194,7 @@ class SauceConnect():
             raise SauceException("Unable to start Sauce Connect Proxy. Process exited with code %s", self.sc_process.returncode)
 
     def __exit__(self, exc_type, exc_val, exc_tb):
+        self.env_config = None
         self.sc_process.terminate()
         if self.temp_dir and os.path.exists(self.temp_dir):
             try:
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/server-locations.txt b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/browsers/server-locations.txt
deleted file mode 100644 (file)
index 5dcaf4b..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-http://localhost:8000    primary
-
-http://web-platform.test:8000
-http://www.web-platform.test:8000
-http://www1.web-platform.test:8000
-http://www2.web-platform.test:8000
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8000
-http://xn--lve-6lad.web-platform.test:8000
-
-http://web-platform.test:8001
-http://www.web-platform.test:8001
-http://www1.web-platform.test:8001
-http://www2.web-platform.test:8001
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8001
-http://xn--lve-6lad.web-platform.test:8001
-
-https://web-platform.test:8443
-https://www.web-platform.test:8443
-https://www1.web-platform.test:8443
-https://www2.web-platform.test:8443
-https://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8443
-https://xn--lve-6lad.web-platform.test:8443
-
-# These are actually ws servers, but until mozprofile is
-# fixed we have to pretend that they are http servers
-http://web-platform.test:8888
-http://www.web-platform.test:8888
-http://www1.web-platform.test:8888
-http://www2.web-platform.test:8888
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8888
-http://xn--lve-6lad.web-platform.test:8888
index 17fa598..f163631 100644 (file)
@@ -54,7 +54,7 @@ def env_extras(**kwargs):
 def env_options():
     return {"host": "127.0.0.1",
             "external_host": "web-platform.test",
-            "bind_hostname": "false",
+            "bind_hostname": False,
             "testharnessreport": "testharnessreport-servo.js",
             "supports_debugger": True}
 
index c251de8..89504b2 100644 (file)
@@ -1,9 +1,12 @@
 import os
+import shutil
 import subprocess
 import tempfile
 
 from mozprocess import ProcessHandler
 
+from tools.serve.serve import make_hosts_file
+
 from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser
 from ..executors import executor_kwargs as base_executor_kwargs
 from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor,
@@ -26,14 +29,6 @@ __wptrunner__ = {
     "update_properties": "update_properties",
 }
 
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
 
 def check_args(**kwargs):
     require_arg(kwargs, "binary")
@@ -69,10 +64,10 @@ def update_properties():
     return ["debug", "os", "version", "processor", "bits"], None
 
 
-def make_hosts_file():
+def write_hosts_file(config):
     hosts_fd, hosts_path = tempfile.mkstemp()
     with os.fdopen(hosts_fd, "w") as f:
-        f.write(hosts_text)
+        f.write(make_hosts_file(config, "127.0.0.1"))
     return hosts_path
 
 
@@ -87,7 +82,7 @@ class ServoWebDriverBrowser(Browser):
         self.webdriver_port = None
         self.proc = None
         self.debug_info = debug_info
-        self.hosts_path = make_hosts_file()
+        self.hosts_path = write_hosts_file()
         self.command = None
         self.user_stylesheets = user_stylesheets if user_stylesheets else []
 
@@ -158,6 +153,7 @@ class ServoWebDriverBrowser(Browser):
 
     def cleanup(self):
         self.stop()
+        shutil.rmtree(os.path.dirname(self.hosts_file))
 
     def executor_browser(self):
         assert self.webdriver_port is not None
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/config.json b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/config.json
deleted file mode 100644 (file)
index d146424..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{"host": "%(host)s",
- "ports":{"http":[8000, 8001],
-          "https":[8443],
-          "ws":[8888]},
- "check_subdomains":false,
- "bind_hostname":%(bind_hostname)s,
- "ssl":{}}
index 7115341..8ecbb4b 100644 (file)
@@ -18,14 +18,6 @@ serve = None
 sslutils = None
 
 
-hostnames = ["web-platform.test",
-             "www.web-platform.test",
-             "www1.web-platform.test",
-             "www2.web-platform.test",
-             "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
-             "xn--lve-6lad.web-platform.test"]
-
-
 def do_delayed_imports(logger, test_paths):
     global serve, sslutils
 
@@ -92,18 +84,29 @@ class TestEnvironment(object):
         self.cache_manager = multiprocessing.Manager()
         self.stash = serve.stash.StashServer()
         self.env_extras = env_extras
+        self.env_extras_cms = None
 
 
     def __enter__(self):
         self.stash.__enter__()
         self.ssl_env.__enter__()
         self.cache_manager.__enter__()
-        for cm in self.env_extras:
-            cm.__enter__(self.options)
-        self.setup_server_logging()
+
         self.config = self.load_config()
+        self.setup_server_logging()
         ports = serve.get_ports(self.config, self.ssl_env)
         self.config = serve.normalise_config(self.config, ports)
+
+        assert self.env_extras_cms is None, (
+            "A TestEnvironment object cannot be nested")
+
+        self.env_extras_cms = []
+
+        for env in self.env_extras:
+            cm = env(self.options, self.config)
+            cm.__enter__()
+            self.env_extras_cms.append(cm)
+
         self.servers = serve.start(self.config, self.ssl_env,
                                    self.get_routes())
         if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive:
@@ -116,8 +119,11 @@ class TestEnvironment(object):
         for scheme, servers in self.servers.iteritems():
             for port, server in servers:
                 server.kill()
-        for cm in self.env_extras:
+        for cm in self.env_extras_cms:
             cm.__exit__(exc_type, exc_val, exc_tb)
+
+        self.env_extras_cms = None
+
         self.cache_manager.__exit__(exc_type, exc_val, exc_tb)
         self.ssl_env.__exit__(exc_type, exc_val, exc_tb)
         self.stash.__exit__()
@@ -130,15 +136,23 @@ class TestEnvironment(object):
 
     def load_config(self):
         default_config_path = os.path.join(serve_path(self.test_paths), "config.default.json")
-        local_config_path = os.path.join(here, "config.json")
+        local_config = {
+            "ports": {
+                "http": [8000, 8001],
+                "https": [8443],
+                "ws": [8888]
+            },
+            "check_subdomains": False,
+            "bind_hostname": self.options["bind_hostname"],
+            "ssl": {}
+        }
+
+        if "host" in self.options:
+            local_config["host"] = self.options["host"]
 
         with open(default_config_path) as f:
             default_config = json.load(f)
 
-        with open(local_config_path) as f:
-            data = f.read()
-            local_config = json.loads(data % self.options)
-
         #TODO: allow non-default configuration for ssl
 
         local_config["external_host"] = self.options.get("external_host", None)
index ca8ec8a..edacddd 100644 (file)
@@ -13,6 +13,8 @@ from collections import defaultdict
 
 from mozprocess import ProcessHandler
 
+from tools.serve.serve import make_hosts_file
+
 from .base import (ExecutorException,
                    Protocol,
                    RefTestImplementation,
@@ -30,18 +32,10 @@ webdriver = None
 
 extra_timeout = 5  # seconds
 
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
-def make_hosts_file():
+def write_hosts_file(config):
     hosts_fd, hosts_path = tempfile.mkstemp()
     with os.fdopen(hosts_fd, "w") as f:
-        f.write(hosts_text)
+        f.write(make_hosts_file(config, "127.0.0.1"))
     return hosts_path
 
 
@@ -57,7 +51,7 @@ class ServoTestharnessExecutor(ProcessTestExecutor):
         self.result_data = None
         self.result_flag = None
         self.protocol = Protocol(self, browser)
-        self.hosts_path = make_hosts_file()
+        self.hosts_path = write_hosts_file(server_config)
 
     def teardown(self):
         try:
@@ -191,7 +185,7 @@ class ServoRefTestExecutor(ProcessTestExecutor):
         self.screenshot_cache = screenshot_cache
         self.implementation = RefTestImplementation(self)
         self.tempdir = tempfile.mkdtemp()
-        self.hosts_path = make_hosts_file()
+        self.hosts_path = write_hosts_file(server_config)
 
     def teardown(self):
         try:
index fdf1b12..79fca42 100644 (file)
@@ -17,7 +17,10 @@ class FontInstaller(object):
         self.created_dir = False
         self.fonts = fonts
 
-    def __enter__(self, options=None):
+    def __call__(self, env_options=None, env_config=None):
+        return self
+
+    def __enter__(self):
         for _, font_path in self.fonts.items():
             font_name = font_path.split('/')[-1]
             install = getattr(self, 'install_%s_font' % SYSTEM, None)
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/hosts.py b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/hosts.py
deleted file mode 100644 (file)
index 915c17f..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-from __future__ import unicode_literals
-
-
-class HostsLine(object):
-    def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None):
-        self.ip_address = ip_address
-        self.canonical_hostname = canonical_hostname
-        self.aliases = aliases if aliases is not None else []
-        self.comment = comment
-        if self.ip_address is None:
-            assert self.canonical_hostname is None
-            assert not self.aliases
-            assert self.comment is not None
-
-    @classmethod
-    def from_string(cls, line):
-        if not line.strip():
-            return
-
-        line = line.strip()
-
-        ip_address = None
-        canonical_hostname = None
-        aliases = []
-        comment = None
-
-        comment_parts = line.split("#", 1)
-        if len(comment_parts) > 1:
-            comment = comment_parts[1]
-
-        data = comment_parts[0].strip()
-
-        if data:
-            fields = data.split()
-            if len(fields) < 2:
-                raise ValueError("Invalid hosts line")
-
-            ip_address = fields[0]
-            canonical_hostname = fields[1]
-            aliases = fields[2:]
-
-        return cls(ip_address, canonical_hostname, aliases, comment)
-
-
-class HostsFile(object):
-    def __init__(self):
-        self.data = []
-        self.by_hostname = {}
-
-    def set_host(self, host):
-        if host.canonical_hostname is None:
-            self.data.append(host)
-        elif host.canonical_hostname in self.by_hostname:
-            old_host = self.by_hostname[host.canonical_hostname]
-            old_host.ip_address = host.ip_address
-            old_host.aliases = host.aliases
-            old_host.comment = host.comment
-        else:
-            self.data.append(host)
-            self.by_hostname[host.canonical_hostname] = host
-
-    @classmethod
-    def from_file(cls, f):
-        rv = cls()
-        for line in f:
-            host = HostsLine.from_string(line)
-            if host is not None:
-                rv.set_host(host)
-        return rv
-
-    def to_string(self):
-        field_widths = [0, 0]
-        for line in self.data:
-            if line.ip_address is not None:
-                field_widths[0] = max(field_widths[0], len(line.ip_address))
-                field_widths[1] = max(field_widths[1], len(line.canonical_hostname))
-
-        lines = []
-
-        for host in self.data:
-            line = ""
-            if host.ip_address is not None:
-                ip_string = host.ip_address.ljust(field_widths[0])
-                hostname_str = host.canonical_hostname
-                if host.aliases:
-                    hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]),
-                                              " ".join(host.aliases))
-                line = "%s %s" % (ip_string, hostname_str)
-            if host.comment:
-                if line:
-                    line += " "
-                line += "#%s" % host.comment
-            lines.append(line)
-
-        lines.append("")
-
-        return "\n".join(lines)
-
-    def to_file(self, f):
-        f.write(self.to_string().encode("utf8"))
index 85ffbe3..16623f7 100644 (file)
@@ -229,7 +229,6 @@ class BrowserManager(object):
     def cleanup(self):
         if self.init_timer is not None:
             self.init_timer.cancel()
-        self.browser.cleanup()
 
     def check_for_crashes(self):
         self.browser.check_for_crashes()
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/__init__.py b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/browsers/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/test_hosts.py b/WebDriverTests/imported/w3c/tools/wptrunner/wptrunner/tests/test_hosts.py
deleted file mode 100644 (file)
index e7d41f3..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import unittest
-import sys
-from os.path import join, dirname
-from cStringIO import StringIO
-
-sys.path.insert(0, join(dirname(__file__), "..", ".."))
-
-from wptrunner import hosts
-
-
-class HostsTest(unittest.TestCase):
-    def do_test(self, input, expected):
-        host_file = hosts.HostsFile.from_file(StringIO(input))
-        self.assertEquals(host_file.to_string(), expected)
-
-    def test_simple(self):
-        self.do_test("""127.0.0.1    \tlocalhost  alias # comment
-# Another comment""",
-                     """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
-    def test_blank_lines(self):
-        self.do_test("""127.0.0.1    \tlocalhost  alias # comment
-
-\r
-    \t
-# Another comment""",
-                     """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
-    def test_whitespace(self):
-        self.do_test("""    \t127.0.0.1    \tlocalhost  alias # comment     \r
-    \t# Another comment""",
-                     """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
-    def test_alignment(self):
-        self.do_test("""127.0.0.1    \tlocalhost  alias
-192.168.1.1 another_host    another_alias
-""","""127.0.0.1   localhost    alias
-192.168.1.1 another_host another_alias
-""")
-
-    def test_multiple_same_name(self):
-        # The semantics are that we overwrite earlier entries with the same name
-        self.do_test("""127.0.0.1    \tlocalhost  alias
-192.168.1.1 localhost    another_alias""","""192.168.1.1 localhost another_alias
-""")
-
-if __name__ == "__main__":
-    unittest.main()
index 7b78898..8a3f9c9 100644 (file)
@@ -137,9 +137,9 @@ class ChromeDriverServer(WebDriverServer):
 
 class EdgeDriverServer(WebDriverServer):
     def __init__(self, logger, binary="microsoftwebdriver.exe", port=None,
-                 base_path="", args=None):
+                 base_path="", host="localhost", args=None):
         WebDriverServer.__init__(
-            self, logger, binary, port=port, base_path=base_path, args=args)
+            self, logger, binary, host=host, port=port, args=args)
 
     def make_command(self):
         return [self.binary,
index 6677902..d3d9d07 100644 (file)
@@ -218,6 +218,7 @@ def run_tests(config, test_paths, product, **kwargs):
                     browser_kwargs = get_browser_kwargs(test_type,
                                                         run_info,
                                                         ssl_env=ssl_env,
+                                                        config=test_environment.config,
                                                         **kwargs)
 
                     executor_cls = executor_classes.get(test_type)
index bb7e145..f852653 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from tests.actions.support.mouse import get_center
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
 from tests.actions.support.refine import get_events, filter_dict
 from tests.support.asserts import assert_move_to_coordinates
 from tests.support.inline import inline
@@ -12,11 +12,6 @@ def link_doc(dest):
     return inline(content)
 
 
-# TODO use pytest.approx once we upgrade to pytest > 3.0
-def approx(n, m, tolerance=1):
-    return abs(n - m) <= tolerance
-
-
 def test_click_at_coordinates(session, test_actions_page, mouse_chain):
     div_point = {
         "x": 82,
@@ -35,7 +30,7 @@ def test_click_at_coordinates(session, test_actions_page, mouse_chain):
         assert e["button"] == 0
     expected = [
         {"type": "mousedown", "buttons": 1},
-        {"type": "mouseup",  "buttons": 0},
+        {"type": "mouseup", "buttons": 0},
         {"type": "click", "buttons": 0},
     ]
     filtered_events = [filter_dict(e, expected[0]) for e in events]
@@ -55,7 +50,7 @@ def test_context_menu_at_coordinates(session, test_actions_page, mouse_chain):
     events = get_events(session)
     expected = [
         {"type": "mousedown", "button": 2},
-        {"type": "contextmenu",  "button": 2},
+        {"type": "contextmenu", "button": 2},
     ]
     assert len(events) == 4
     filtered_events = [filter_dict(e, expected[0]) for e in events]
@@ -68,7 +63,7 @@ def test_context_menu_at_coordinates(session, test_actions_page, mouse_chain):
 
 def test_click_element_center(session, test_actions_page, mouse_chain):
     outer = session.find.css("#outer", all=False)
-    center = get_center(outer.rect)
+    center = get_inview_center(outer.rect, get_viewport_rect(session))
     mouse_chain.click(element=outer).perform()
     events = get_events(session)
     assert len(events) == 4
@@ -76,8 +71,8 @@ def test_click_element_center(session, test_actions_page, mouse_chain):
     assert ["mousemove", "mousedown", "mouseup", "click"] == event_types
     for e in events:
         if e["type"] != "mousemove":
-            assert approx(e["pageX"], center["x"])
-            assert approx(e["pageY"], center["y"])
+            assert pytest.approx(e["pageX"], center["x"])
+            assert pytest.approx(e["pageY"], center["y"])
             assert e["target"] == "outer"
 
 
@@ -102,8 +97,9 @@ def test_click_navigation(session, url, release_actions):
 
 
 @pytest.mark.parametrize("drag_duration", [0, 300, 800])
-@pytest.mark.parametrize("dx, dy",
-    [(20, 0), (0, 15), (10, 15), (-20, 0), (10, -15), (-10, -15)])
+@pytest.mark.parametrize("dx, dy", [
+    (20, 0), (0, 15), (10, 15), (-20, 0), (10, -15), (-10, -15)
+])
 def test_drag_and_drop(session,
                        test_actions_page,
                        mouse_chain,
@@ -112,7 +108,7 @@ def test_drag_and_drop(session,
                        drag_duration):
     drag_target = session.find.css("#dragTarget", all=False)
     initial_rect = drag_target.rect
-    initial_center = get_center(initial_rect)
+    initial_center = get_inview_center(initial_rect, get_viewport_rect(session))
     # Conclude chain with extra move to allow time for last queued
     # coordinate-update of drag_target and to test that drag_target is "dropped".
     mouse_chain \
@@ -125,8 +121,8 @@ def test_drag_and_drop(session,
     # mouseup that ends the drag is at the expected destination
     e = get_events(session)[1]
     assert e["type"] == "mouseup"
-    assert approx(e["pageX"], initial_center["x"] + dx)
-    assert approx(e["pageY"], initial_center["y"] + dy)
+    assert pytest.approx(e["pageX"], initial_center["x"] + dx)
+    assert pytest.approx(e["pageY"], initial_center["y"] + dy)
     # check resulting location of the dragged element
     final_rect = drag_target.rect
     assert initial_rect["x"] + dx == final_rect["x"]
index e9e4c26..bdd3905 100644 (file)
@@ -1,6 +1,6 @@
 import pytest
 
-from tests.actions.support.mouse import get_center
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
 from tests.actions.support.refine import get_events, filter_dict
 from tests.support.asserts import assert_move_to_coordinates
 
@@ -63,7 +63,7 @@ def test_dblclick_at_coordinates(dblclick_session, mouse_chain, click_pause):
 
 def test_dblclick_with_pause_after_second_pointerdown(dblclick_session, mouse_chain):
         outer = dblclick_session.find.css("#outer", all=False)
-        center = get_center(outer.rect)
+        center = get_inview_center(outer.rect, get_viewport_rect(dblclick_session))
         mouse_chain \
             .pointer_move(int(center["x"]), int(center["y"])) \
             .click() \
@@ -88,7 +88,7 @@ def test_dblclick_with_pause_after_second_pointerdown(dblclick_session, mouse_ch
 
 def test_no_dblclick(dblclick_session, mouse_chain):
         outer = dblclick_session.find.css("#outer", all=False)
-        center = get_center(outer.rect)
+        center = get_inview_center(outer.rect, get_viewport_rect(dblclick_session))
         mouse_chain \
             .pointer_move(int(center["x"]), int(center["y"])) \
             .click() \
diff --git a/WebDriverTests/imported/w3c/webdriver/tests/actions/pointer_origin.py b/WebDriverTests/imported/w3c/webdriver/tests/actions/pointer_origin.py
new file mode 100644 (file)
index 0000000..cad59f0
--- /dev/null
@@ -0,0 +1,129 @@
+import pytest
+
+from webdriver import MoveTargetOutOfBoundsException
+
+from tests.actions.support.mouse import get_inview_center, get_viewport_rect
+from tests.support.inline import inline
+
+
+def origin_doc(inner_style, outer_style=""):
+    return inline("""
+      <div id="outer" style="{1}"
+           onmousemove="window.coords = {{x: event.clientX, y: event.clientY}}">
+        <div id="inner" style="{0}"></div>
+      </div>
+    """.format(inner_style, outer_style))
+
+
+def get_click_coordinates(session):
+    return session.execute_script("return window.coords;")
+
+
+def test_viewport_inside(session, mouse_chain):
+    point = {"x": 50, "y": 50}
+
+    session.url = origin_doc("width: 100px; height: 50px; background: green;")
+    mouse_chain \
+        .pointer_move(point["x"], point["y"], origin="viewport") \
+        .perform()
+
+    click_coords = session.execute_script("return window.coords;")
+    assert pytest.approx(click_coords["x"], point["x"])
+    assert pytest.approx(click_coords["y"], point["y"])
+
+
+def test_viewport_outside(session, mouse_chain):
+    with pytest.raises(MoveTargetOutOfBoundsException):
+        mouse_chain \
+            .pointer_move(-50, -50, origin="viewport") \
+            .perform()
+
+
+def test_pointer_inside(session, mouse_chain):
+    start_point = {"x": 50, "y": 50}
+    offset = {"x": 10, "y": 5}
+
+    session.url = origin_doc("width: 100px; height: 50px; background: green;")
+    mouse_chain \
+        .pointer_move(start_point["x"], start_point["y"]) \
+        .pointer_move(offset["x"], offset["y"], origin="pointer") \
+        .perform()
+
+    click_coords = session.execute_script("return window.coords;")
+    assert pytest.approx(click_coords["x"], start_point["x"] + offset["x"])
+    assert pytest.approx(click_coords["y"], start_point["y"] + offset["y"])
+
+
+def test_pointer_outside(session, mouse_chain):
+    with pytest.raises(MoveTargetOutOfBoundsException):
+        mouse_chain \
+            .pointer_move(-50, -50, origin="pointer") \
+            .perform()
+
+
+def test_element_center_point(session, mouse_chain):
+    session.url = origin_doc("width: 100px; height: 50px; background: green;")
+    elem = session.find.css("#inner", all=False)
+    center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+    mouse_chain \
+        .pointer_move(0, 0, origin=elem) \
+        .perform()
+
+    click_coords = get_click_coordinates(session)
+    assert pytest.approx(click_coords["x"], center["x"])
+    assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_center_point_with_offset(session, mouse_chain):
+    session.url = origin_doc("width: 100px; height: 50px; background: green;")
+    elem = session.find.css("#inner", all=False)
+    center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+    mouse_chain \
+        .pointer_move(10, 15, origin=elem) \
+        .perform()
+
+    click_coords = get_click_coordinates(session)
+    assert pytest.approx(click_coords["x"], center["x"] + 10)
+    assert pytest.approx(click_coords["y"], center["y"] + 15)
+
+
+def test_element_in_view_center_point_partly_visible(session, mouse_chain):
+    session.url = origin_doc("""width: 100px; height: 50px; background: green;
+                                position: relative; left: -50px; top: -25px;""")
+    elem = session.find.css("#inner", all=False)
+    center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+    mouse_chain \
+        .pointer_move(0, 0, origin=elem) \
+        .perform()
+
+    click_coords = get_click_coordinates(session)
+    assert pytest.approx(click_coords["x"], center["x"])
+    assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_larger_than_viewport(session, mouse_chain):
+    session.url = origin_doc("width: 300vw; height: 300vh; background: green;")
+    elem = session.find.css("#inner", all=False)
+    center = get_inview_center(elem.rect, get_viewport_rect(session))
+
+    mouse_chain \
+        .pointer_move(0, 0, origin=elem) \
+        .perform()
+
+    click_coords = get_click_coordinates(session)
+    assert pytest.approx(click_coords["x"], center["x"])
+    assert pytest.approx(click_coords["y"], center["y"])
+
+
+def test_element_outside_of_view_port(session, mouse_chain):
+    session.url = origin_doc("""width: 100px; height: 50px; background: green;
+                                position: relative; left: -200px; top: -100px;""")
+    elem = session.find.css("#inner", all=False)
+
+    with pytest.raises(MoveTargetOutOfBoundsException):
+        mouse_chain \
+            .pointer_move(0, 0, origin=elem) \
+            .perform()
index d627ebb..b3672eb 100644 (file)
@@ -1,5 +1,26 @@
-def get_center(rect):
+def get_viewport_rect(session):
+    return session.execute_script("""
+        return {
+          height: window.innerHeight || document.documentElement.clientHeight,
+          width: window.innerWidth || document.documentElement.clientWidth,
+        };
+    """)
+
+
+def get_inview_center(elem_rect, viewport_rect):
+    x = {
+        "left": max(0, min(elem_rect["x"], elem_rect["x"] + elem_rect["width"])),
+        "right": min(viewport_rect["width"], max(elem_rect["x"],
+                                                 elem_rect["x"] + elem_rect["width"])),
+    }
+
+    y = {
+        "top": max(0, min(elem_rect["y"], elem_rect["y"] + elem_rect["height"])),
+        "bottom": min(viewport_rect["height"], max(elem_rect["y"],
+                                                   elem_rect["y"] + elem_rect["height"])),
+    }
+
     return {
-        "x": rect["width"] / 2 + rect["x"],
-        "y": rect["height"] / 2 + rect["y"],
+        "x": (x["left"] + x["right"]) / 2,
+        "y": (y["top"] + y["bottom"]) / 2,
     }
index 1cfb2ef..7bf405c 100644 (file)
@@ -1,7 +1,6 @@
 from tests.support.asserts import assert_success
 from tests.support.inline import inline
 
-
 def click(session, element):
     return session.transport.send(
         "POST", "/session/{session_id}/element/{element_id}/click".format(
@@ -28,9 +27,10 @@ def test_click_event_bubbles_to_parents(session):
         <script>
         window.clicks = [];
 
-        for (let level of document.querySelectorAll("div")) {
-          level.addEventListener("click", ({currentTarget}) => {
-            window.clicks.push(currentTarget);
+        var elements = document.querySelectorAll("div");
+        for (var level = 0; level < elements.length; level++) {
+          elements[level].addEventListener("click", function(clickEvent) {
+            window.clicks.push(clickEvent.currentTarget);
           });
         }
         </script>
@@ -67,9 +67,11 @@ def test_spin_event_loop(session):
         <script>
         window.delayedClicks = [];
 
-        for (let level of document.querySelectorAll("div")) {
-          level.addEventListener("click", ({currentTarget}) => {
-            setTimeout(() => window.delayedClicks.push(currentTarget), 100);
+        var elements = document.querySelectorAll("div");
+        for (var level = 0; level < elements.length; level++) {
+          elements[level].addEventListener("click", function(clickEvent) {
+            var target = clickEvent.currentTarget;
+            setTimeout(function() { window.delayedClicks.push(target); }, 100);
           });
         }
         </script>
index ca5e498..dcf92e6 100644 (file)
@@ -217,6 +217,7 @@ def test_option_disabled(session):
     session.url = inline("""
         <select>
           <option disabled>foo
+          <option>bar
         </select>""")
     option = session.find.css("option", all=False)
     assert not option.selected
index ee6269e..855d662 100644 (file)
@@ -1,6 +1,11 @@
 import pytest
 
-from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.asserts import (
+    assert_element_has_focus,
+    assert_error,
+    assert_same_element,
+    assert_success,
+)
 from tests.support.inline import inline
 
 
@@ -17,7 +22,7 @@ def add_event_listeners(element):
     element.session.execute_script("""
         let [target] = arguments;
         window.events = [];
-        for (let expected of ["focus", "blur", "change", "keypress", "keydown", "keyup", "input"]) {
+        for (let expected of ["focus", "change", "keypress", "keydown", "keyup", "input"]) {
           target.addEventListener(expected, ({type}) => window.events.push(type));
         }
         """, args=(element,))
@@ -34,6 +39,7 @@ def test_input(session):
 
     element_send_keys(session, element, "foo")
     assert element.property("value") == "foo"
+    assert_element_has_focus(element)
 
 
 def test_textarea(session):
@@ -43,6 +49,7 @@ def test_textarea(session):
 
     element_send_keys(session, element, "foo")
     assert element.property("value") == "foo"
+    assert_element_has_focus(element)
 
 
 def test_input_append(session):
@@ -89,6 +96,13 @@ def test_events(session, tag):
                                    "keydown",
                                    "keypress",
                                    "input",
-                                   "keyup",
-                                   "change",
-                                   "blur"]
+                                   "keyup"]
+
+
+@pytest.mark.parametrize("tag", ["input", "textarea"])
+def test_not_blurred(session, tag):
+    session.url = inline("<%s>" % tag)
+    element = session.find.css(tag, all=False)
+
+    element_send_keys(session, element, "")
+    assert_element_has_focus(element)
index bf1959f..f0746e4 100644 (file)
@@ -1,4 +1,4 @@
-from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.asserts import assert_error, assert_success
 from tests.support.inline import iframe, inline
 
 
@@ -13,8 +13,8 @@ def send_keys_to_element(session, element, text):
 
 def test_body_is_interactable(session):
     session.url = inline("""
-        <body onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <body onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </body>
     """)
 
@@ -22,18 +22,18 @@ def test_body_is_interactable(session):
     result = session.find.css("input", all=False)
 
     # By default body is the active element
-    assert_same_element(session, element, session.active_element)
+    assert session.active_element is element
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
-    assert_same_element(session, element, session.active_element)
+    assert session.active_element is element
     assert result.property("value") == "foo"
 
 
 def test_document_element_is_interactable(session):
     session.url = inline("""
-        <html onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <html onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </html>
     """)
 
@@ -42,18 +42,18 @@ def test_document_element_is_interactable(session):
     result = session.find.css("input", all=False)
 
     # By default body is the active element
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is body
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is element
     assert result.property("value") == "foo"
 
 
 def test_iframe_is_interactable(session):
     session.url = inline(iframe("""
-        <body onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <body onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </body>
     """))
 
@@ -61,11 +61,11 @@ def test_iframe_is_interactable(session):
     frame = session.find.css("iframe", all=False)
 
     # By default the body has the focus
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is body
 
     response = send_keys_to_element(session, frame, "foo")
     assert_success(response)
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is frame
 
     # Any key events are immediately routed to the nested
     # browsing context's active document.
@@ -75,7 +75,7 @@ def test_iframe_is_interactable(session):
 
 
 def test_transparent_element(session):
-    session.url = inline("<input style=\"opacity: 0;\">")
+    session.url = inline("""<input style="opacity: 0">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
@@ -94,8 +94,8 @@ def test_readonly_element(session):
 
 def test_obscured_element(session):
     session.url = inline("""
-      <input type="text" />
-      <div style="position: relative; top: -3em; height: 5em; background-color: blue"></div>
+      <input>
+      <div style="position: relative; top: -3em; height: 5em; background: blue;"></div>
     """)
     element = session.find.css("input", all=False)
 
@@ -113,7 +113,7 @@ def test_not_a_focusable_element(session):
 
 
 def test_not_displayed_element(session):
-    session.url = inline("<input style=\"display: none\">")
+    session.url = inline("""<input style="display: none">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
@@ -121,7 +121,7 @@ def test_not_displayed_element(session):
 
 
 def test_hidden_element(session):
-    session.url = inline("<input style=\"visibility: hidden\">")
+    session.url = inline("""<input style="visibility: hidden">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
@@ -129,7 +129,7 @@ def test_hidden_element(session):
 
 
 def test_disabled_element(session):
-    session.url = inline("<input disabled=\"false\">")
+    session.url = inline("""<input disabled>""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
index ae9d2f5..4df9c41 100644 (file)
@@ -34,7 +34,7 @@ def test_array_in_object(session):
     response = execute_script(session, """
         let arr = [];
         arr.push(arr);
-        return {arr};
+        return {'arrayValue': arr};
         """)
     assert_error(response, "javascript error")
 
index 9b42ad3..43eecc5 100644 (file)
@@ -67,10 +67,8 @@ def test_handle_prompt_accept(new_session, add_browser_capabilites):
     session.url = inline("<title>WD doc title</title>")
     create_dialog(session)("alert", text="accept #1", result_var="accept1")
 
-    expected_title = read_global(session, "document.title")
     response = fullscreen(session)
 
-    assert_success(response, expected_title)
     assert_dialog_handled(session, "accept #1")
     assert read_global(session, "accept1") == None
 
@@ -79,18 +77,15 @@ def test_handle_prompt_accept(new_session, add_browser_capabilites):
 
     response = fullscreen(session)
 
-    assert_success(response, expected_title)
     assert_dialog_handled(session, "accept #2")
     assert read_global(session, "accept2"), True
 
-    expected_title = read_global(session, "document.title")
     create_dialog(session)("prompt", text="accept #3", result_var="accept3")
 
     response = fullscreen(session)
 
-    assert_success(response, expected_title)
     assert_dialog_handled(session, "accept #3")
-    assert read_global(session, "accept3") == ""
+    assert read_global(session, "accept3") == "" or read_global(session, "accept3") == "undefined"
 
 
 def test_handle_prompt_missing_value(session, create_dialog):
@@ -121,7 +116,7 @@ def test_handle_prompt_missing_value(session, create_dialog):
 
     assert_error(response, "unexpected alert open")
     assert_dialog_handled(session, "dismiss #1")
-    assert read_global(session, "accept1") == None
+    assert read_global(session, "dismiss1") == None
 
     create_dialog("confirm", text="dismiss #2", result_var="dismiss2")
 
@@ -140,6 +135,11 @@ def test_handle_prompt_missing_value(session, create_dialog):
     assert read_global(session, "dismiss3") == None
 
 
+def is_fullscreen(session):
+    # At the time of writing, WebKit does not conform to the Fullscreen API specification.
+    # Remove the prefixed fallback when https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
+    return session.execute_script("return !!(window.fullScreen || document.webkitIsFullScreen)")
+
 def test_fullscreen(session):
     """
     4. Call fullscreen an element with the current top-level browsing
@@ -148,7 +148,8 @@ def test_fullscreen(session):
     """
     response = fullscreen(session)
     assert_success(response)
-    assert session.execute_script("return window.fullScreen") is True
+
+    assert is_fullscreen(session) is True
 
 
 def test_payload(session):
@@ -197,12 +198,12 @@ def test_payload(session):
 
 
 def test_fullscreen_twice_is_idempotent(session):
-    assert session.execute_script("return window.fullScreen") is False
+    assert is_fullscreen(session) is False
 
     first_response = fullscreen(session)
     assert_success(first_response)
-    assert session.execute_script("return window.fullScreen") is True
+    assert is_fullscreen(session) is True
 
     second_response = fullscreen(session)
     assert_success(second_response)
-    assert session.execute_script("return window.fullScreen") is True
+    assert is_fullscreen(session) is True
index 3163728..d54aaaf 100644 (file)
@@ -1,38 +1,49 @@
-<!DOCTYPE html>
-<body>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
+<!doctype html>
+<meta charset=utf-8>
+
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
 <script src=/resources/WebIDLParser.js></script>
 <script src=/resources/idlharness.js></script>
+
 <script type=text/plain class=untested>
 [Exposed=Window]
 interface Navigator {
   // objects implementing this interface also implement the interfaces given below
 };
 </script>
+
 <script type=text/plain>
 Navigator includes NavigatorAutomationInformation;
 
 interface mixin NavigatorAutomationInformation {
-    readonly attribute boolean webdriver;
-    // always returns true
+  readonly attribute boolean webdriver;
 };
 </script>
+
 <script>
 "use strict";
 
-if ("webdriver" in navigator) {
-  test(() => assert_true(navigator.webdriver), "navigator.webdriver is always true");
-  var idlArray = new IdlArray();
-  [].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
-    if (node.className == "untested") {
-      idlArray.add_untested_idls(node.textContent);
-    } else {
-      idlArray.add_idls(node.textContent);
-    }
-  });
-  idlArray.test();
-} else {
-  done();
+test(() => assert_idl_attribute(navigator, "webdriver"), "navigator.webdriver is present");
+
+// When test is run in automation navigator.webdriver is likely to
+// be true because WebDriver controls the browser instance.  To that
+// extent, this test is a bit special.  It should also be possible to
+// run the test manually, when WebDriver is not active, and so either
+// true/false outcome is OK.
+if (navigator.webdriver) {
+  test(() => assert_true(navigator.webdriver), "navigator.webdriver is true when webdriver-active is set");
+}¬†else {
+  test(() => assert_false(navigator.webdriver), "navigator.webdriver is false when webdriver-active is not set");
 }
+
+var idls = new IdlArray();
+for (let node of [...document.scripts].filter(({type}) => type == "text/plain")) {
+  if (node.className == "untested") {
+    idls.add_untested_idls(node.textContent);
+  } else {
+    idls.add_idls(node.textContent);
+  }
+};
+idls.test();
 </script>
index e4da98e..e0d7801 100644 (file)
@@ -161,9 +161,8 @@ def test_element(session):
     session.url = inline("<input type=checkbox>")
     element = session.find.css("input", all=False)
     element.click()
-    assert None == session.execute_script("return arguments[0].hasAttribute('checked')",
-                                          args=[element])
-    result = session.transport.send("GET", "session/{session_id}/element/{element_id}/property/id"
+    assert session.execute_script("return arguments[0].hasAttribute('checked')", args=(element,)) is False
+    result = session.transport.send("GET", "session/{session_id}/element/{element_id}/property/checked"
                                     .format(session_id=session.session_id,
                                             element_id=element.id))
     assert_success(result, True)