diff options
Diffstat (limited to 'testing/web-platform/mozilla/tests/webdriver/classic')
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) |