diff --git a/py/selenium/common/__init__.py b/py/selenium/common/__init__.py index 2ef6204d37070..88269940125d9 100644 --- a/py/selenium/common/__init__.py +++ b/py/selenium/common/__init__.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +from .exceptions import DetachedShadowRootException from .exceptions import ElementClickInterceptedException from .exceptions import ElementNotInteractableException from .exceptions import ElementNotSelectableException @@ -83,4 +84,5 @@ "InvalidSessionIdException", "SessionNotCreatedException", "UnknownMethodException", + "DetachedShadowRootException", ] diff --git a/py/selenium/common/exceptions.py b/py/selenium/common/exceptions.py index 931eb307f809f..d1d7efdd1f0bd 100644 --- a/py/selenium/common/exceptions.py +++ b/py/selenium/common/exceptions.py @@ -285,3 +285,7 @@ def __init__( with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}/driver_location" super().__init__(with_support, screen, stacktrace) + + +class DetachedShadowRootException(WebDriverException): + """Raised when referenced shadow root is no longer attached to the DOM.""" diff --git a/py/selenium/webdriver/remote/errorhandler.py b/py/selenium/webdriver/remote/errorhandler.py index e9b30fe51dd3f..d2df3b1b8e241 100644 --- a/py/selenium/webdriver/remote/errorhandler.py +++ b/py/selenium/webdriver/remote/errorhandler.py @@ -19,6 +19,7 @@ from typing import Dict from typing import Type +from selenium.common.exceptions import DetachedShadowRootException from selenium.common.exceptions import ElementClickInterceptedException from selenium.common.exceptions import ElementNotInteractableException from selenium.common.exceptions import ElementNotSelectableException @@ -88,6 +89,7 @@ class ExceptionMapping: UNABLE_TO_CAPTURE_SCREEN = ScreenshotException ELEMENT_CLICK_INTERCEPTED = ElementClickInterceptedException UNKNOWN_METHOD = UnknownMethodException + DETACHED_SHADOW_ROOT = DetachedShadowRootException class ErrorCode: @@ -131,6 +133,7 @@ class ErrorCode: UNABLE_TO_CAPTURE_SCREEN = [63, "unable to capture screen"] ELEMENT_CLICK_INTERCEPTED = [64, "element click intercepted"] UNKNOWN_METHOD = ["unknown method exception"] + DETACHED_SHADOW_ROOT = [65, "detached shadow root"] METHOD_NOT_ALLOWED = [405, "unsupported operation"] diff --git a/py/test/unit/selenium/webdriver/remote/error_handler_tests.py b/py/test/unit/selenium/webdriver/remote/error_handler_tests.py index 809d64193387a..9f3098550efc8 100644 --- a/py/test/unit/selenium/webdriver/remote/error_handler_tests.py +++ b/py/test/unit/selenium/webdriver/remote/error_handler_tests.py @@ -242,6 +242,12 @@ def test_raises_exception_for_method_not_allowed(handler, code): handler.check_response({"status": code, "value": "foo"}) +@pytest.mark.parametrize("code", ErrorCode.DETACHED_SHADOW_ROOT) +def test_raises_exception_for_detached_shadow_root(handler, code): + with pytest.raises(exceptions.DetachedShadowRootException): + handler.check_response({"status": code, "value": "foo"}) + + @pytest.mark.parametrize("key", ["stackTrace", "stacktrace"]) def test_relays_exception_stacktrace(handler, key): import json