summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/mozilla/tests/webdriver/classic
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/mozilla/tests/webdriver/classic')
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/scroll_into_view.py50
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/send_keys.py44
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/execute_async.py71
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/chrome.py25
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/chrome.py43
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/bidi_disabled.py33
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/binary.py33
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/conftest.py58
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/create.py11
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/invalid.py53
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/new_session/profile_root.py43
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/perform_actions/wheel.py37
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/protocol/__init__.py0
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_hosts.py53
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_origins.py56
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/protocol/marionette_port.py41
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/protocol/request.py72
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/send_alert_text.py22
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/__init__.py12
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/iframe.py47
-rw-r--r--testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/screenshot.py51
26 files changed, 855 insertions, 0 deletions
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/scroll_into_view.py b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/scroll_into_view.py
new file mode 100644
index 0000000000..080195d345
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/scroll_into_view.py
@@ -0,0 +1,50 @@
+from tests.support.asserts import assert_success
+from tests.support.helpers import is_element_in_viewport
+
+
+def element_send_keys(session, element, text):
+ return session.transport.send(
+ "POST",
+ "/session/{session_id}/element/{element_id}/value".format(
+ session_id=session.session_id, element_id=element.id
+ ),
+ {"text": text},
+ )
+
+
+def test_option_select_container_outside_of_scrollable_viewport(session, inline):
+ session.url = inline(
+ """
+ <select style="margin-top: 102vh;">
+ <option value="foo">foo</option>
+ <option value="bar" id="bar">bar</option>
+ </select>
+ """
+ )
+ element = session.find.css("option#bar", all=False)
+ select = session.find.css("select", all=False)
+
+ response = element_send_keys(session, element, "bar")
+ assert_success(response)
+
+ assert is_element_in_viewport(session, select)
+ assert is_element_in_viewport(session, element)
+
+
+def test_option_stays_outside_of_scrollable_viewport(session, inline):
+ session.url = inline(
+ """
+ <select multiple style="height: 105vh; margin-top: 100vh;">
+ <option value="foo" id="foo" style="height: 100vh;">foo</option>
+ <option value="bar" id="bar" style="background-color: yellow;">bar</option>
+ </select>
+ """
+ )
+ select = session.find.css("select", all=False)
+ option_bar = session.find.css("option#bar", all=False)
+
+ response = element_send_keys(session, option_bar, "bar")
+ assert_success(response)
+
+ assert is_element_in_viewport(session, select)
+ assert is_element_in_viewport(session, option_bar)
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/send_keys.py b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/send_keys.py
new file mode 100644
index 0000000000..acdcaae74d
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/element_send_keys/send_keys.py
@@ -0,0 +1,44 @@
+import pytest
+from tests.support.asserts import assert_success
+from tests.support.keys import Keys
+
+
+def element_send_keys(session, element, text):
+ return session.transport.send(
+ "POST",
+ "/session/{session_id}/element/{element_id}/value".format(
+ session_id=session.session_id, element_id=element.id
+ ),
+ {"text": text},
+ )
+
+
+def test_modifier_key_toggles(session, inline, modifier_key):
+ session.url = inline("<input type=text value=foo>")
+ element = session.find.css("input", all=False)
+
+ response = element_send_keys(
+ session, element, f"{modifier_key}a{modifier_key}{Keys.DELETE}cheese"
+ )
+ assert_success(response)
+
+ assert element.property("value") == "cheese"
+
+
+@pytest.mark.parametrize("dispatch_once_per_surrogate_pair", [False, True])
+def test_dispatch_once_per_surrogate_pair(
+ session, use_pref, inline, dispatch_once_per_surrogate_pair
+):
+ use_pref(
+ "dom.event.keypress.dispatch_once_per_surrogate_pair",
+ dispatch_once_per_surrogate_pair,
+ )
+
+ session.url = inline("<input>")
+ element = session.find.css("input", all=False)
+
+ text = "🦥🍄"
+ response = element_send_keys(session, element, text)
+ assert_success(response)
+
+ assert element.property("value") == text
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/execute_async.py b/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/execute_async.py
new file mode 100644
index 0000000000..fe42e44ce7
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/execute_async_script/execute_async.py
@@ -0,0 +1,71 @@
+import pytest
+from tests.support.asserts import assert_success
+from tests.support.sync import Poll
+from webdriver.error import NoSuchAlertException
+
+
+def execute_async_script(session, script, args=None):
+ if args is None:
+ args = []
+ body = {"script": script, "args": args}
+
+ return session.transport.send(
+ "POST", "/session/{session_id}/execute/async".format(**vars(session)), body
+ )
+
+
+@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
+def test_no_abort_by_user_prompt_in_other_tab(session, inline, dialog_type):
+ original_handle = session.window_handle
+ original_handles = session.handles
+
+ session.url = inline(
+ """
+ <a onclick="window.open();">open window</a>
+ <script>
+ window.addEventListener("message", function (event) {{
+ {}("foo");
+ }});
+ </script>
+ """.format(
+ dialog_type
+ )
+ )
+
+ session.find.css("a", all=False).click()
+ wait = Poll(session, timeout=5, message="No new window has been opened")
+ new_handles = wait.until(lambda s: set(s.handles) - set(original_handles))
+ assert len(new_handles) == 1
+
+ session.window_handle = new_handles.pop()
+
+ response = execute_async_script(
+ session,
+ """
+ const resolve = arguments[0];
+
+ // Trigger opening a user prompt in the other window.
+ window.opener.postMessage("foo", "*");
+
+ // Delay resolving the Promise to ensure a user prompt has been opened.
+ setTimeout(() => resolve(42), 500);
+ """,
+ )
+
+ assert_success(response, 42)
+
+ session.window.close()
+
+ session.window_handle = original_handle
+
+ # Opening the alert in a different window is async here and can cause
+ # delays in slow builds like CCOV or TSAN.
+ wait = Poll(
+ session,
+ timeout=15,
+ ignored_exceptions=NoSuchAlertException,
+ message="No user prompt with text 'foo' detected",
+ )
+ wait.until(lambda s: s.alert.text == "foo")
+
+ session.alert.accept()
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/chrome.py b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/chrome.py
new file mode 100644
index 0000000000..af24be4b9e
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handle/chrome.py
@@ -0,0 +1,25 @@
+from support.context import using_context
+from tests.support.asserts import assert_success
+
+
+def get_window_handle(session):
+ return session.transport.send(
+ "GET", "session/{session_id}/window".format(**vars(session))
+ )
+
+
+def test_basic(session):
+ with using_context(session, "chrome"):
+ response = get_window_handle(session)
+ assert_success(response, session.window_handle)
+
+
+def test_different_handle_than_content_scope(session):
+ response = get_window_handle(session)
+ content_handle = assert_success(response)
+
+ with using_context(session, "chrome"):
+ response = get_window_handle(session)
+ chrome_handle = assert_success(response)
+
+ assert chrome_handle != content_handle
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/chrome.py b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/chrome.py
new file mode 100644
index 0000000000..091ac01e6c
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/get_window_handles/chrome.py
@@ -0,0 +1,43 @@
+from support.context import using_context
+from tests.support.asserts import assert_success
+
+
+def get_window_handles(session):
+ return session.transport.send(
+ "GET", "session/{session_id}/window/handles".format(**vars(session))
+ )
+
+
+def test_basic(session):
+ with using_context(session, "chrome"):
+ response = get_window_handles(session)
+ assert_success(response, session.handles)
+
+
+def test_different_handles_than_content_scope(session):
+ response = get_window_handles(session)
+ content_handles = assert_success(response)
+
+ with using_context(session, "chrome"):
+ response = get_window_handles(session)
+ chrome_handles = assert_success(response)
+
+ assert chrome_handles != content_handles
+ assert len(chrome_handles) == 1
+ assert len(content_handles) == 1
+
+
+def test_multiple_windows_and_tabs(session):
+ session.new_window(type_hint="window")
+ session.new_window(type_hint="tab")
+
+ response = get_window_handles(session)
+ content_handles = assert_success(response)
+
+ with using_context(session, "chrome"):
+ response = get_window_handles(session)
+ chrome_handles = assert_success(response)
+
+ assert chrome_handles != content_handles
+ assert len(chrome_handles) == 2
+ assert len(content_handles) == 3
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/bidi_disabled.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/bidi_disabled.py
new file mode 100644
index 0000000000..eeb5a18740
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/bidi_disabled.py
@@ -0,0 +1,33 @@
+from copy import deepcopy
+
+
+def test_marionette_fallback_webdriver_session(configuration, geckodriver):
+ config = deepcopy(configuration)
+ config["capabilities"]["webSocketUrl"] = True
+
+ prefs = config["capabilities"]["moz:firefoxOptions"].get("prefs", {})
+ prefs.update({"remote.active-protocols": 2})
+ config["capabilities"]["moz:firefoxOptions"]["prefs"] = prefs
+
+ try:
+ driver = geckodriver(config=config)
+ driver.new_session()
+
+ assert driver.session.capabilities.get("webSocketUrl") is None
+
+ # Sanity check that Marionette works as expected and by default returns
+ # at least one window handle
+ assert len(driver.session.handles) >= 1
+
+ finally:
+ driver.stop()
+
+ # WebDriver BiDi has to be re-enabled. Because we cannot easily
+ # get rid of the value let geckodriver overwrite it with the current
+ # default.
+ prefs.update({"remote.active-protocols": 3})
+
+ driver = geckodriver(config=config)
+ driver.new_session()
+
+ assert driver.session.capabilities.get("webSocketUrl") is not None
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/binary.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/binary.py
new file mode 100644
index 0000000000..79d1f842ed
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/binary.py
@@ -0,0 +1,33 @@
+import os
+
+from tests.support.asserts import assert_error, assert_success
+
+
+def test_bad_binary(new_session, configuration):
+ # skipif annotations are forbidden in wpt
+ if os.path.exists("/bin/echo"):
+ capabilities = configuration["capabilities"].copy()
+ capabilities["moz:firefoxOptions"]["binary"] = "/bin/echo"
+
+ response, _ = new_session({"capabilities": {"alwaysMatch": capabilities}})
+ assert_error(response, "invalid argument")
+
+
+def test_shell_script_binary(new_session, configuration):
+ # skipif annotations are forbidden in wpt
+ if os.path.exists("/bin/bash"):
+ capabilities = configuration["capabilities"].copy()
+ binary = configuration["browser"]["binary"]
+
+ path = os.path.abspath("firefox.sh")
+ assert not os.path.exists(path)
+ try:
+ script = f"""#!/bin/bash\n\n"{binary}" $@\n"""
+ with open("firefox.sh", "w") as f:
+ f.write(script)
+ os.chmod(path, 0o744)
+ capabilities["moz:firefoxOptions"]["binary"] = path
+ response, _ = new_session({"capabilities": {"alwaysMatch": capabilities}})
+ assert_success(response)
+ finally:
+ os.unlink(path)
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/conftest.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/conftest.py
new file mode 100644
index 0000000000..1cab6784c2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/conftest.py
@@ -0,0 +1,58 @@
+import pytest
+from webdriver.transport import HTTPWireProtocol
+
+
+@pytest.fixture(name="configuration")
+def fixture_configuration(configuration):
+ """Remove "acceptInsecureCerts" from capabilities if it exists.
+
+ Some browser configurations add acceptInsecureCerts capability by default.
+ Remove it during new_session tests to avoid interference.
+ """
+ if "acceptInsecureCerts" in configuration["capabilities"]:
+ configuration = dict(configuration)
+ del configuration["capabilities"]["acceptInsecureCerts"]
+ return configuration
+
+
+@pytest.fixture(name="new_session")
+def fixture_new_session(request, configuration, current_session):
+ """Start a new session for tests which themselves test creating new sessions.
+
+ :param body: The content of the body for the new session POST request.
+
+ :param delete_existing_session: Allows the fixture to delete an already
+ created custom session before the new session is getting created. This
+ is useful for tests which call this fixture multiple times within the
+ same test.
+ """
+ custom_session = {}
+
+ transport = HTTPWireProtocol(
+ configuration["host"],
+ configuration["port"],
+ url_prefix="/",
+ )
+
+ def _delete_session(session_id):
+ transport.send("DELETE", "session/{}".format(session_id))
+
+ def new_session(body, delete_existing_session=False, headers=None):
+ # If there is an active session from the global session fixture,
+ # delete that one first
+ if current_session is not None:
+ current_session.end()
+
+ if delete_existing_session:
+ _delete_session(custom_session["session"]["sessionId"])
+
+ response = transport.send("POST", "session", body, headers=headers)
+ if response.status == 200:
+ custom_session["session"] = response.body["value"]
+ return response, custom_session.get("session", None)
+
+ yield new_session
+
+ if custom_session.get("session") is not None:
+ _delete_session(custom_session["session"]["sessionId"])
+ custom_session = None
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/create.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/create.py
new file mode 100644
index 0000000000..9649b938ad
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/create.py
@@ -0,0 +1,11 @@
+# META: timeout=long
+from tests.support.asserts import assert_success
+
+
+def test_valid_content_type(new_session, configuration):
+ headers = {"content-type": "application/json"}
+ response, _ = new_session(
+ {"capabilities": {"alwaysMatch": dict(configuration["capabilities"])}},
+ headers=headers,
+ )
+ assert_success(response)
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/invalid.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/invalid.py
new file mode 100644
index 0000000000..dc7a0caee9
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/invalid.py
@@ -0,0 +1,53 @@
+from copy import deepcopy
+
+import pytest
+from tests.support.asserts import assert_error
+
+
+@pytest.mark.parametrize(
+ "headers",
+ [
+ {"origin": "http://localhost"},
+ {"origin": "http://localhost:8000"},
+ {"origin": "http://127.0.0.1"},
+ {"origin": "http://127.0.0.1:8000"},
+ {"origin": "null"},
+ {"ORIGIN": "https://example.org"},
+ {"host": "example.org:4444"},
+ {"Host": "example.org"},
+ {"host": "localhost:80"},
+ {"host": "localhost"},
+ {"content-type": "application/x-www-form-urlencoded"},
+ {"content-type": "multipart/form-data"},
+ {"content-type": "text/plain"},
+ {"Content-TYPE": "APPLICATION/x-www-form-urlencoded"},
+ {"content-type": "MULTIPART/FORM-DATA"},
+ {"CONTENT-TYPE": "TEXT/PLAIN"},
+ {"content-type": "text/plain ; charset=utf-8"},
+ {"content-type": "text/plain;foo"},
+ {"content-type": "text/PLAIN ; foo;charset=utf8"},
+ ],
+)
+def test_invalid(new_session, configuration, headers):
+ response, _ = new_session(
+ {"capabilities": {"alwaysMatch": dict(configuration["capabilities"])}},
+ headers=headers,
+ )
+ assert_error(response, "unknown error")
+
+
+@pytest.mark.parametrize(
+ "argument",
+ [
+ "--marionette",
+ "--remote-debugging-port",
+ "--remote-allow-hosts",
+ "--remote-allow-origins",
+ ],
+)
+def test_forbidden_arguments(configuration, new_session, argument):
+ capabilities = deepcopy(configuration["capabilities"])
+ capabilities["moz:firefoxOptions"]["args"] = [argument]
+
+ response, _ = new_session({"capabilities": {"alwaysMatch": capabilities}})
+ assert_error(response, "invalid argument")
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/new_session/profile_root.py b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/profile_root.py
new file mode 100644
index 0000000000..fc3607bed9
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/new_session/profile_root.py
@@ -0,0 +1,43 @@
+import copy
+import os
+
+import pytest
+
+
+def test_profile_root(tmp_path, configuration, geckodriver, user_prefs):
+ profile_path = os.path.join(tmp_path, "geckodriver-test")
+ os.makedirs(profile_path)
+
+ config = copy.deepcopy(configuration)
+
+ # Pass all the wpt preferences from the default profile's user.js via
+ # capabilities to allow geckodriver to create a new valid profile itself.
+ config["capabilities"]["moz:firefoxOptions"]["prefs"] = user_prefs
+
+ # Ensure we don't set a profile in command line arguments
+ del config["capabilities"]["moz:firefoxOptions"]["args"]
+
+ extra_args = ["--profile-root", profile_path]
+
+ assert os.listdir(profile_path) == []
+
+ driver = geckodriver(config=config, extra_args=extra_args)
+ driver.new_session()
+ assert len(os.listdir(profile_path)) == 1
+ driver.delete_session()
+ assert os.listdir(profile_path) == []
+
+
+def test_profile_root_missing(tmp_path, configuration, geckodriver):
+ profile_path = os.path.join(tmp_path, "missing-path")
+ assert not os.path.exists(profile_path)
+
+ config = copy.deepcopy(configuration)
+ # Ensure we don't set a profile in command line arguments
+ del config["capabilities"]["moz:firefoxOptions"]["args"]
+
+ extra_args = ["--profile-root", profile_path]
+
+ with pytest.raises(ChildProcessError) as exc_info:
+ geckodriver(config=config, extra_args=extra_args)
+ assert str(exc_info.value) == "geckodriver terminated with code 64"
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/perform_actions/wheel.py b/testing/web-platform/mozilla/tests/webdriver/classic/perform_actions/wheel.py
new file mode 100644
index 0000000000..6ca328f33b
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/perform_actions/wheel.py
@@ -0,0 +1,37 @@
+from copy import deepcopy
+
+import pytest
+from tests.classic.perform_actions.support.refine import get_events
+
+
+@pytest.mark.parametrize("device_pixel_ratio", ["1.0", "2.0", "0.5"])
+def test_scroll_delta_device_pixel(configuration, url, geckodriver, device_pixel_ratio):
+ config = deepcopy(configuration)
+
+ prefs = config["capabilities"]["moz:firefoxOptions"].get("prefs", {})
+ prefs.update({"layout.css.devPixelsPerPx": device_pixel_ratio})
+ config["capabilities"]["moz:firefoxOptions"]["prefs"] = prefs
+
+ try:
+ driver = geckodriver(config=config)
+ driver.new_session()
+
+ driver.session.url = url(
+ "/webdriver/tests/support/html/test_actions_scroll.html"
+ )
+
+ target = driver.session.find.css("#scrollable", all=False)
+
+ chain = driver.session.actions.sequence("wheel", "wheel_id")
+ chain.scroll(0, 0, 5, 10, origin=target).perform()
+
+ events = get_events(driver.session)
+ assert len(events) == 1
+ assert events[0]["type"] == "wheel"
+ assert events[0]["deltaX"] == 5
+ assert events[0]["deltaY"] == 10
+ assert events[0]["deltaZ"] == 0
+ assert events[0]["target"] == "scrollable-content"
+
+ finally:
+ driver.stop()
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/protocol/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/__init__.py
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_hosts.py b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_hosts.py
new file mode 100644
index 0000000000..17ae2c2c68
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_hosts.py
@@ -0,0 +1,53 @@
+from copy import deepcopy
+
+import pytest
+from support.network import get_host, http_request, websocket_request
+
+
+@pytest.mark.parametrize(
+ "allow_hosts, hostname, port_type, status",
+ [
+ # Valid hosts
+ (["localhost.localdomain", "localhost"], "localhost", "server_port", 200),
+ (["localhost.localdomain", "localhost"], "127.0.0.1", "server_port", 200),
+ # Invalid hosts
+ (["localhost.localdomain"], "localhost", "server_port", 500),
+ (["localhost"], "localhost", "wrong_port", 500),
+ (["www.localhost"], "localhost", "server_port", 500),
+ ],
+)
+def test_allow_hosts(geckodriver, allow_hosts, hostname, port_type, status):
+ extra_args = ["--allow-hosts"] + allow_hosts
+
+ driver = geckodriver(hostname=hostname, extra_args=extra_args)
+ host = get_host(port_type, hostname, driver.port)
+ response = http_request(driver.hostname, driver.port, host=host)
+
+ assert response.status == status
+
+
+@pytest.mark.parametrize(
+ "allow_hosts, hostname, status",
+ [
+ (["mozilla.org", "testhost"], "testhost", 101),
+ (["mozilla.org"], "testhost", 400),
+ ],
+ ids=["allowed", "not allowed"],
+)
+def test_allow_hosts_passed_to_remote_agent(
+ configuration, geckodriver, allow_hosts, hostname, status
+):
+ config = deepcopy(configuration)
+ config["capabilities"]["webSocketUrl"] = True
+
+ extra_args = ["--allow-hosts"] + allow_hosts
+
+ driver = geckodriver(config=config, extra_args=extra_args)
+
+ driver.new_session()
+
+ host = get_host("default_port", hostname, driver.remote_agent_port)
+ response = websocket_request("127.0.0.1", driver.remote_agent_port, host=host)
+ assert response.status == status
+
+ driver.delete_session()
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_origins.py b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_origins.py
new file mode 100644
index 0000000000..72b6fba482
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/allow_origins.py
@@ -0,0 +1,56 @@
+from copy import deepcopy
+
+import pytest
+from support.network import http_request, websocket_request
+
+
+@pytest.mark.parametrize(
+ "allow_origins, origin, status",
+ [
+ # Valid origins
+ (["http://web-platform.test"], "http://web-platform.test", 200),
+ (["http://web-platform.test"], "http://web-platform.test:80", 200),
+ (["https://web-platform.test"], "https://web-platform.test:443", 200),
+ # Invalid origins
+ (["https://web-platform.test"], "http://web-platform.test", 500),
+ (["http://web-platform.test:8000"], "http://web-platform.test", 500),
+ (["http://web-platform.test"], "http://www.web-platform.test", 500),
+ ],
+)
+def test_allow_hosts(configuration, geckodriver, allow_origins, origin, status):
+ extra_args = ["--allow-origins"] + allow_origins
+
+ driver = geckodriver(extra_args=extra_args)
+ response = http_request(driver.hostname, driver.port, origin=origin)
+
+ assert response.status == status
+
+
+@pytest.mark.parametrize(
+ "allow_origins, origin, status",
+ [
+ (
+ ["https://web-platform.test", "http://web-platform.test"],
+ "http://web-platform.test",
+ 101,
+ ),
+ (["https://web-platform.test"], "http://web-platform.test", 400),
+ ],
+ ids=["allowed", "not allowed"],
+)
+def test_allow_origins_passed_to_remote_agent(
+ configuration, geckodriver, allow_origins, origin, status
+):
+ config = deepcopy(configuration)
+ config["capabilities"]["webSocketUrl"] = True
+
+ extra_args = ["--allow-origins"] + allow_origins
+
+ driver = geckodriver(config=config, extra_args=extra_args)
+
+ driver.new_session()
+
+ response = websocket_request("127.0.0.1", driver.remote_agent_port, origin=origin)
+ assert response.status == status
+
+ driver.delete_session()
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/protocol/marionette_port.py b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/marionette_port.py
new file mode 100644
index 0000000000..09951abc43
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/marionette_port.py
@@ -0,0 +1,41 @@
+import os
+from copy import deepcopy
+
+import pytest
+
+
+@pytest.mark.parametrize("port", ["0", "2828"], ids=["system allocated", "fixed"])
+def test_marionette_port(geckodriver, port):
+ extra_args = ["--marionette-port", port]
+
+ driver = geckodriver(extra_args=extra_args)
+ driver.new_session()
+ driver.delete_session()
+
+
+def test_marionette_port_outdated_active_port_file(
+ configuration, geckodriver, custom_profile
+):
+ config = deepcopy(configuration)
+ extra_args = ["--marionette-port", "0"]
+
+ # Prepare a Marionette active port file that contains a port which will
+ # never be used when requesting a system allocated port.
+ active_port_file = os.path.join(custom_profile.profile, "MarionetteActivePort")
+ with open(active_port_file, "wb") as f:
+ f.write(b"53")
+
+ config["capabilities"]["moz:firefoxOptions"]["args"] = [
+ "--profile",
+ custom_profile.profile,
+ ]
+
+ driver = geckodriver(config=config, extra_args=extra_args)
+
+ driver.new_session()
+ with open(active_port_file, "rb") as f:
+ assert f.readline() != b"53"
+
+ driver.delete_session()
+ with pytest.raises(FileNotFoundError):
+ open(active_port_file, "rb")
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/protocol/request.py b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/request.py
new file mode 100644
index 0000000000..ad99d6964d
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/protocol/request.py
@@ -0,0 +1,72 @@
+import pytest
+from support.network import get_host, http_request
+
+
+@pytest.mark.parametrize(
+ "hostname, port_type, status",
+ [
+ # Valid hosts
+ ("localhost", "server_port", 200),
+ ("127.0.0.1", "server_port", 200),
+ ("[::1]", "server_port", 200),
+ ("192.168.8.1", "server_port", 200),
+ ("[fdf8:f535:82e4::53]", "server_port", 200),
+ # Invalid hosts
+ ("localhost", "default_port", 500),
+ ("127.0.0.1", "default_port", 500),
+ ("[::1]", "default_port", 500),
+ ("192.168.8.1", "default_port", 500),
+ ("[fdf8:f535:82e4::53]", "default_port", 500),
+ ("example.org", "server_port", 500),
+ ("example.org", "wrong_port", 500),
+ ("example.org", "default_port", 500),
+ ("localhost", "wrong_port", 500),
+ ("127.0.0.1", "wrong_port", 500),
+ ("[::1]", "wrong_port", 500),
+ ("192.168.8.1", "wrong_port", 500),
+ ("[fdf8:f535:82e4::53]", "wrong_port", 500),
+ ],
+ ids=[
+ # Valid hosts
+ "localhost with same port as server",
+ "127.0.0.1 (loopback) with same port as server",
+ "[::1] (ipv6 loopback) with same port as server",
+ "ipv4 address with same port as server",
+ "ipv6 address with same port as server",
+ # Invalid hosts
+ "localhost with default port",
+ "127.0.0.1 (loopback) with default port",
+ "[::1] (ipv6 loopback) with default port",
+ "ipv4 address with default port",
+ "ipv6 address with default port",
+ "random hostname with the same port as server",
+ "random hostname with a different port than server",
+ "random hostname with default port",
+ "localhost with a different port than server",
+ "127.0.0.1 (loopback) with a different port than server",
+ "[::1] (ipv6 loopback) with a different port than server",
+ "ipv4 address with a different port than server",
+ "ipv6 address with a different port than server",
+ ],
+)
+def test_host_header(configuration, hostname, port_type, status):
+ host = get_host(port_type, hostname, configuration["port"])
+ response = http_request(configuration["host"], configuration["port"], host=host)
+
+ assert response.status == status
+
+
+@pytest.mark.parametrize(
+ "origin, add_port, status",
+ [
+ (None, False, 200),
+ ("", False, 500),
+ ("sometext", False, 500),
+ ("http://localhost", True, 500),
+ ],
+)
+def test_origin_header(configuration, origin, add_port, status):
+ if add_port:
+ origin = f"{origin}:{configuration['port']}"
+ response = http_request(configuration["host"], configuration["port"], origin=origin)
+ assert response.status == status
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/send_alert_text.py b/testing/web-platform/mozilla/tests/webdriver/classic/send_alert_text.py
new file mode 100644
index 0000000000..60d6a02af0
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/send_alert_text.py
@@ -0,0 +1,22 @@
+from tests.support.asserts import assert_error
+from tests.support.http_handlers.authentication import basic_authentication
+
+
+def send_alert_text(session, text=None):
+ return session.transport.send(
+ "POST",
+ "session/{session_id}/alert/text".format(**vars(session)),
+ {"text": text},
+ )
+
+
+def test_basic_auth_unsupported_operation(url, session):
+ """
+ Basic auth dialogues are not included in HTML's definition of
+ 'user prompts': those are limited to the 'simple dialogues'
+ such as window.alert(), window.prompt() et al. and the print
+ dialogue.
+ """
+ session.url = basic_authentication(url)
+ response = send_alert_text(session, "Federer")
+ assert_error(response, "unsupported operation")
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/__init__.py b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/__init__.py
new file mode 100644
index 0000000000..11a8a58a0f
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/__init__.py
@@ -0,0 +1,12 @@
+def document_dimensions(session):
+ return tuple(
+ session.execute_script(
+ """
+ const {devicePixelRatio} = window;
+ const width = document.documentElement.scrollWidth;
+ const height = document.documentElement.scrollHeight;
+
+ return [Math.floor(width * devicePixelRatio), Math.floor(height * devicePixelRatio)];
+ """
+ )
+ )
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/iframe.py b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/iframe.py
new file mode 100644
index 0000000000..fc231f2e11
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/iframe.py
@@ -0,0 +1,47 @@
+import pytest
+from tests.support.asserts import assert_success
+from tests.support.image import png_dimensions
+
+from . import document_dimensions
+
+DEFAULT_CSS_STYLE = """
+ <style>
+ div, iframe {
+ display: block;
+ border: 1px solid blue;
+ width: 10em;
+ height: 10em;
+ }
+ </style>
+"""
+
+DEFAULT_CONTENT = "<div>Lorem ipsum dolor sit amet.</div>"
+
+
+def take_full_screenshot(session):
+ return session.transport.send(
+ "GET",
+ "/session/{session_id}/moz/screenshot/full".format(
+ session_id=session.session_id
+ ),
+ )
+
+
+@pytest.mark.parametrize("domain", ["", "alt"], ids=["same_origin", "cross_origin"])
+def test_source_origin(session, url, domain, inline, iframe):
+ session.url = inline("""{0}{1}""".format(DEFAULT_CSS_STYLE, DEFAULT_CONTENT))
+
+ response = take_full_screenshot(session)
+ reference_screenshot = assert_success(response)
+ assert png_dimensions(reference_screenshot) == document_dimensions(session)
+
+ iframe_content = "<style>body {{ margin: 0; }}</style>{}".format(DEFAULT_CONTENT)
+ session.url = inline(
+ """{0}{1}""".format(DEFAULT_CSS_STYLE, iframe(iframe_content, domain=domain))
+ )
+
+ response = take_full_screenshot(session)
+ screenshot = assert_success(response)
+ assert png_dimensions(screenshot) == document_dimensions(session)
+
+ assert screenshot == reference_screenshot
diff --git a/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/screenshot.py b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/screenshot.py
new file mode 100644
index 0000000000..02373afd57
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/webdriver/classic/take_full_screenshot/screenshot.py
@@ -0,0 +1,51 @@
+from tests.support.asserts import assert_error, assert_png, assert_success
+from tests.support.image import png_dimensions
+
+from . import document_dimensions
+
+
+def take_full_screenshot(session):
+ return session.transport.send(
+ "GET",
+ "/session/{session_id}/moz/screenshot/full".format(
+ session_id=session.session_id
+ ),
+ )
+
+
+def test_no_browsing_context(session, closed_window):
+ response = take_full_screenshot(session)
+ assert_error(response, "no such window")
+
+
+def test_html_document(session, inline):
+ session.url = inline("<input>")
+
+ response = take_full_screenshot(session)
+ value = assert_success(response)
+ assert_png(value)
+ assert png_dimensions(value) == document_dimensions(session)
+
+
+def test_xhtml_document(session, inline):
+ session.url = inline('<input type="text" />', doctype="xhtml")
+
+ response = take_full_screenshot(session)
+ value = assert_success(response)
+ assert_png(value)
+ assert png_dimensions(value) == document_dimensions(session)
+
+
+def test_document_extends_beyond_viewport(session, inline):
+ session.url = inline(
+ """
+ <style>
+ body { min-height: 200vh }
+ </style>
+ """
+ )
+
+ response = take_full_screenshot(session)
+ value = assert_success(response)
+ assert_png(value)
+ assert png_dimensions(value) == document_dimensions(session)