")
+ outer_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = outer_element.shadow_root
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = find_element(session, shadow_root.id, "css selector", "p")
+ assert_error(response, "unexpected alert open")
+
+ assert session.alert.text == dialog_type
+ session.alert.dismiss()
+
+ return check_user_prompt_not_closed_but_exception
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
+@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
+def test_ignore(check_user_prompt_not_closed_but_exception, dialog_type):
+ check_user_prompt_not_closed_but_exception(dialog_type)
+
+
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_default(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
diff --git a/webdriver/tests/find_elements_from_shadow_root/conftest.py b/webdriver/tests/find_elements_from_shadow_root/conftest.py
new file mode 100644
index 00000000000000..b8fc93319f43a9
--- /dev/null
+++ b/webdriver/tests/find_elements_from_shadow_root/conftest.py
@@ -0,0 +1,19 @@
+import pytest
+
+@pytest.fixture
+def get_shadow_page(inline):
+ def get_shadow_page(shadow_content):
+ return inline("""
+
+ """.format(shadow_content))
+ return get_shadow_page
diff --git a/webdriver/tests/find_elements_from_shadow_root/find.py b/webdriver/tests/find_elements_from_shadow_root/find.py
new file mode 100644
index 00000000000000..f70a4b45aadb05
--- /dev/null
+++ b/webdriver/tests/find_elements_from_shadow_root/find.py
@@ -0,0 +1,144 @@
+import pytest
+
+from webdriver.transport import Response
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+
+
+def find_elements(session, shadow_id, using, value):
+ return session.transport.send(
+ "POST", "session/{session_id}/shadow/{shadow_id}/elements".format(
+ session_id=session.session_id,
+ shadow_id=shadow_id),
+ {"using": using, "value": value})
+
+
+def test_null_parameter_value(session, http, inline):
+ session.url = inline("
")
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+
+ path = "/session/{session_id}/shadow/{shadow_id}/elements".format(
+ session_id=session.session_id, shadow_id=shadow_root.id)
+ with http.post(path, None) as response:
+ assert_error(Response.from_http(response), "invalid argument")
+
+
+def test_no_top_browsing_context(session, closed_window):
+ response = find_elements(session, "notReal", "css selector", "foo")
+ assert_error(response, "no such window")
+
+
+def test_no_browsing_context(session, closed_frame):
+ response = find_elements(session, "notReal", "css selector", "foo")
+ assert_error(response, "no such window")
+
+
+@pytest.mark.parametrize("using", [("a"), (True), (None), (1), ([]), ({})])
+def test_invalid_using_argument(session, using):
+ # Step 1 - 2
+ response = find_elements(session, "notReal", using, "value")
+ assert_error(response, "invalid argument")
+
+
+@pytest.mark.parametrize("value", [None, [], {}])
+def test_invalid_selector_argument(session, value):
+ # Step 3 - 4
+ response = find_elements(session, "notReal", "css selector", value)
+ assert_error(response, "invalid argument")
+
+
+def test_detached_shadow_root(session, get_shadow_page):
+ session.url = get_shadow_page("
")
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ session.refresh()
+
+ response = find_elements(session, shadow_root.id, "css", "input")
+ assert_error(response, "detached shadow root")
+
+
+def test_find_elements_equivalence(session, get_shadow_page):
+ session.url = get_shadow_page("
")
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ response = find_elements(session, shadow_root.id, "css", "input")
+ assert_success(response)
+
+
+@pytest.mark.parametrize("using,value",
+ [("css selector", "#linkText"),
+ ("link text", "full link text"),
+ ("partial link text", "link text"),
+ ("tag name", "a"),
+ ("xpath", "//a")])
+def test_find_elements(session, get_shadow_page, using, value):
+ # Step 8 - 9
+ session.url = get_shadow_page("
")
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ response = find_elements(session, shadow_root.id, using, value)
+ assert_success(response)
+
+
+@pytest.mark.parametrize("document,value", [
+ ("
link text", "link text"),
+ ("
link text ", "link text"),
+ ("
link
text", "link\ntext"),
+ ("
link&text", "link&text"),
+ ("
LINK TEXT", "LINK TEXT"),
+ ("
link text", "LINK TEXT"),
+])
+def test_find_elements_link_text(session, get_shadow_page, document, value):
+ # Step 8 - 9
+ session.url = get_shadow_page("
".format(document))
+ element = session.find.css("div", all=False)
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ expected = session.execute_script("return arguments[0].shadowRoot.querySelectorAll('a')[1]",
+ args=(custom_element,))
+
+ response = find_elements(session, shadow_root.id, "link text", value)
+ value = assert_success(response)
+ assert isinstance(value, list)
+ assert len(value) == 1
+
+ found_element = value[0]
+ assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("document,value", [
+ ("
partial link text", "link"),
+ ("
partial link text ", "link"),
+ ("
partial link text", "k t"),
+ ("
partial link
text", "k\nt"),
+ ("
partial link&text", "k&t"),
+ ("
PARTIAL LINK TEXT", "LINK"),
+ ("
partial link text", "LINK"),
+])
+def test_find_elements_partial_link_text(session, get_shadow_page, document, value):
+ # Step 8 - 9
+ session.url = get_shadow_page("
".format(document))
+ element = session.find.css("div", all=False)
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ expected = session.execute_script("return arguments[0].shadowRoot.querySelectorAll('a')[1]",
+ args=(custom_element,))
+
+ response = find_elements(session, shadow_root.id, "partial link text", value)
+ value = assert_success(response)
+ assert isinstance(value, list)
+ assert len(value) == 1
+
+ found_element = value[0]
+ assert_same_element(session, found_element, expected)
+
+
+@pytest.mark.parametrize("using,value", [("css selector", "#wontExist")])
+def test_no_element(session, get_shadow_page, using, value):
+ # Step 8 - 9
+ session.url = get_shadow_page("
")
+ custom_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = custom_element.shadow_root
+ response = find_elements(session, shadow_root.id, using, value)
+ assert response.body["value"] == []
diff --git a/webdriver/tests/find_elements_from_shadow_root/user_prompts.py b/webdriver/tests/find_elements_from_shadow_root/user_prompts.py
new file mode 100644
index 00000000000000..c4b903c836ef8e
--- /dev/null
+++ b/webdriver/tests/find_elements_from_shadow_root/user_prompts.py
@@ -0,0 +1,131 @@
+# META: timeout=long
+
+import pytest
+
+from tests.support.asserts import (
+ assert_error,
+ assert_same_element,
+ assert_success,
+ assert_dialog_handled,
+)
+
+
+def find_elements(session, shadow_id, using, value):
+ return session.transport.send(
+ "POST", "session/{session_id}/shadow/{shadow_id}/elements".format(
+ session_id=session.session_id,
+ element_id=shadow_id),
+ {"using": using, "value": value})
+
+
+@pytest.fixture
+def check_user_prompt_closed_without_exception(session, create_dialog, get_shadow_page):
+ def check_user_prompt_closed_without_exception(dialog_type, retval):
+ session.url = get_shadow_page("
bar
")
+ outer_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = outer_element.shadow_root
+ inner_element = session.execute_script("return arguments[0].shadowRoot.querySelector('p')",
+ args=(outer_element,))
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = find_elements(session, shadow_root.id, "css selector", "p")
+ value = assert_success(response)
+ assert isinstance(value, list)
+ assert len(value) == 1
+
+ assert_dialog_handled(session, expected_text=dialog_type, expected_retval=retval)
+
+ assert_same_element(session, value[0], inner_element)
+
+ return check_user_prompt_closed_without_exception
+
+
+@pytest.fixture
+def check_user_prompt_closed_with_exception(session, create_dialog, get_shadow_page):
+ def check_user_prompt_closed_with_exception(dialog_type, retval):
+ session.url = get_shadow_page("
bar
")
+ outer_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = outer_element.shadow_root
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = find_elements(session, shadow_root.id, "css selector", "p")
+ assert_error(response, "unexpected alert open")
+
+ assert_dialog_handled(session, expected_text=dialog_type, expected_retval=retval)
+
+ return check_user_prompt_closed_with_exception
+
+
+@pytest.fixture
+def check_user_prompt_not_closed_but_exception(session, create_dialog, get_shadow_page):
+ def check_user_prompt_not_closed_but_exception(dialog_type):
+ session.url = get_shadow_page("
bar
")
+ outer_element = session.find.css("custom-shadow-element", all=False)
+ shadow_root = outer_element.shadow_root
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = find_elements(session, shadow_root.id, "css selector", "p")
+ assert_error(response, "unexpected alert open")
+
+ assert session.alert.text == dialog_type
+ session.alert.dismiss()
+
+ return check_user_prompt_not_closed_but_exception
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
+@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
+def test_ignore(check_user_prompt_not_closed_but_exception, dialog_type):
+ check_user_prompt_not_closed_but_exception(dialog_type)
+
+
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_default(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
diff --git a/webdriver/tests/get_element_shadow_root/conftest.py b/webdriver/tests/get_element_shadow_root/conftest.py
new file mode 100644
index 00000000000000..afc0c91c3d3f2f
--- /dev/null
+++ b/webdriver/tests/get_element_shadow_root/conftest.py
@@ -0,0 +1,22 @@
+import pytest
+
+@pytest.fixture
+def checkbox_dom(inline):
+ return inline("""
+
+
+ """)
diff --git a/webdriver/tests/get_element_shadow_root/get.py b/webdriver/tests/get_element_shadow_root/get.py
new file mode 100644
index 00000000000000..27c1e4a44ee07a
--- /dev/null
+++ b/webdriver/tests/get_element_shadow_root/get.py
@@ -0,0 +1,58 @@
+import pytest
+
+from tests.support.asserts import assert_error, assert_same_element, assert_success
+
+
+def get_shadow_root(session, element_id):
+ return session.transport.send(
+ "GET", "session/{session_id}/element/{element_id}/shadow".format(
+ session_id=session.session_id,
+ element_id=element_id))
+
+
+def test_no_top_browsing_context(session, closed_window):
+ original_handle, element = closed_window
+ response = get_shadow_root(session, element.id)
+ assert_error(response, "no such window")
+ response = get_shadow_root(session, "foo")
+ assert_error(response, "no such window")
+
+ session.window_handle = original_handle
+ response = get_shadow_root(session, element.id)
+ assert_error(response, "no such element")
+
+
+def test_no_browsing_context(session, closed_frame):
+ response = get_shadow_root(session, "foo")
+ assert_error(response, "no such window")
+
+
+def test_element_not_found(session):
+ result = get_shadow_root(session, "foo")
+ assert_error(result, "no such element")
+
+
+def test_element_stale(session, checkbox_dom):
+ session.url = checkbox_dom
+ element = session.find.css("custom-checkbox-element", all=False)
+ session.refresh()
+
+ result = get_shadow_root(session, element.id)
+ assert_error(result, "stale element reference")
+
+
+def test_get_shadow_root(session, checkbox_dom):
+ session.url = checkbox_dom
+ expected = session.execute_script(
+ "return document.querySelector('custom-checkbox-element').shadowRoot.host")
+ custom_element = session.find.css("custom-checkbox-element", all=False)
+ response = get_shadow_root(session, custom_element.id)
+ assert_success(response)
+ assert_same_element(session, custom_element, expected)
+
+
+def test_no_shadow_root(session, inline):
+ session.url = inline("
")
+ element = session.find.css("div", all=False)
+ response = get_shadow_root(session, element.id)
+ assert_error(response, "no such shadow root")
diff --git a/webdriver/tests/get_element_shadow_root/user_prompts.py b/webdriver/tests/get_element_shadow_root/user_prompts.py
new file mode 100644
index 00000000000000..55b50f0d9c937b
--- /dev/null
+++ b/webdriver/tests/get_element_shadow_root/user_prompts.py
@@ -0,0 +1,118 @@
+# META: timeout=long
+
+import pytest
+
+from tests.support.asserts import assert_error, assert_success, assert_dialog_handled
+
+
+def get_shadow_root(session, element_id):
+ return session.transport.send(
+ "GET", "session/{session_id}/element/{element_id}/shadow".format(
+ session_id=session.session_id,
+ element_id=element_id))
+
+
+@pytest.fixture
+def check_user_prompt_closed_without_exception(session, create_dialog, checkbox_dom):
+ def check_user_prompt_closed_without_exception(dialog_type, retval):
+ session.url = checkbox_dom
+ element = session.find.css("custom-checkbox-element", all=False)
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = get_shadow_root(session, element.id)
+ value = assert_success(response)
+ assert isinstance(value, dict)
+ assert "shadow-075b-4da1-b6ba-e579c2d3230a" in dict
+
+ assert_dialog_handled(session, expected_text=dialog_type, expected_retval=retval)
+
+ return check_user_prompt_closed_without_exception
+
+
+@pytest.fixture
+def check_user_prompt_closed_with_exception(session, create_dialog, checkbox_dom):
+ def check_user_prompt_closed_with_exception(dialog_type, retval):
+ session.url = checkbox_dom
+ element = session.find.css("custom-checkbox-element", all=False)
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = get_shadow_root(session, element.id)
+ assert_error(response, "unexpected alert open")
+
+ assert_dialog_handled(session, expected_text=dialog_type, expected_retval=retval)
+
+ return check_user_prompt_closed_with_exception
+
+
+@pytest.fixture
+def check_user_prompt_not_closed_but_exception(session, create_dialog, checkbox_dom):
+ def check_user_prompt_not_closed_but_exception(dialog_type):
+ session.url = checkbox_dom
+ element = session.find.css("custom-checkbox-element", all=False)
+
+ create_dialog(dialog_type, text=dialog_type)
+
+ response = get_shadow_root(session, element.id)
+ assert_error(response, "unexpected alert open")
+
+ assert session.alert.text == dialog_type
+ session.alert.dismiss()
+
+ return check_user_prompt_not_closed_but_exception
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", True),
+ ("prompt", ""),
+])
+def test_accept_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss(check_user_prompt_closed_without_exception, dialog_type, retval):
+ check_user_prompt_closed_without_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_dismiss_and_notify(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)
+
+
+@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
+@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
+def test_ignore(check_user_prompt_not_closed_but_exception, dialog_type):
+ check_user_prompt_not_closed_but_exception(dialog_type)
+
+
+@pytest.mark.parametrize("dialog_type, retval", [
+ ("alert", None),
+ ("confirm", False),
+ ("prompt", None),
+])
+def test_default(check_user_prompt_closed_with_exception, dialog_type, retval):
+ check_user_prompt_closed_with_exception(dialog_type, retval)