diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index d0683607609..14629f60d7a 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -617,7 +617,7 @@ impl HTMLElementMethods for HTMLElement {
// Note: the element can pass this check without yet being a custom
// element, as long as there is a registered definition
// that could upgrade it to one later.
- let registry = self.owner_document().window().CustomElements();
+ let registry = self.owner_window().CustomElements();
let definition = registry.lookup_definition(self.as_element().local_name(), None);
// Step 3: If definition is null, then throw an "NotSupportedError" DOMException
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index e4d36023d9b..a0cbe563780 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -1282,7 +1282,7 @@ impl Node {
pub(crate) fn summarize(&self, can_gc: CanGc) -> NodeInfo {
let USVString(base_uri) = self.BaseURI();
let node_type = self.NodeType();
- let pipeline = self.owner_document().window().pipeline_id();
+ let pipeline = self.owner_window().pipeline_id();
let maybe_shadow_root = self.downcast::();
let shadow_root_mode = maybe_shadow_root
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 49f6a66b61b..b97fcba4700 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -95,6 +95,13 @@ fn is_stale(element: &Element) -> bool {
!element.owner_document().is_active() || !element.is_connected()
}
+///
+fn is_detached(shadow_root: &ShadowRoot) -> bool {
+ // A shadow root is detached if its node document is not the active document
+ // or if the element node referred to as its host is stale.
+ !shadow_root.owner_document().is_active() || is_stale(&shadow_root.Host())
+}
+
///
fn is_disabled(element: &Element) -> bool {
// Step 1. If element is an option element or element is an optgroup element
@@ -173,12 +180,7 @@ fn get_known_shadow_root(
// A shadow root is detached if its node document is not the active document
// or if the element node referred to as its host is stale.
let shadow_root = DomRoot::downcast::(node).unwrap();
- if !shadow_root.owner_document().is_active() {
- return Err(ErrorStatus::DetachedShadowRoot);
- }
-
- let host = shadow_root.Host();
- if is_stale(&host) {
+ if is_detached(&shadow_root) {
return Err(ErrorStatus::DetachedShadowRoot);
}
// Step 5. Return success with data node.
@@ -396,15 +398,27 @@ unsafe fn jsval_to_webdriver_inner(
});
let _ac = JSAutoRealm::new(cx, *object);
- // TODO: special handling for ShadowRoot
if let Ok(element) = root_from_object::(*object, cx) {
// If the element is stale, return error with error code stale element reference.
if is_stale(&element) {
Err(WebDriverJSError::StaleElementReference)
} else {
- Ok(JSValue::Element(element.upcast::().unique_id(
- element.owner_document().window().pipeline_id(),
- )))
+ Ok(JSValue::Element(
+ element
+ .upcast::()
+ .unique_id(element.owner_window().pipeline_id()),
+ ))
+ }
+ } else if let Ok(shadow_root) = root_from_object::(*object, cx) {
+ // If the shadow root is detached, return error with error code detached shadow root.
+ if is_detached(&shadow_root) {
+ Err(WebDriverJSError::DetachedShadowRoot)
+ } else {
+ Ok(JSValue::ShadowRoot(
+ shadow_root
+ .upcast::()
+ .unique_id(shadow_root.owner_window().pipeline_id()),
+ ))
}
} else if let Ok(window) = root_from_object::(*object, cx) {
let window_proxy = window.window_proxy();
diff --git a/components/servo/tests/webview.rs b/components/servo/tests/webview.rs
index 5457946f7cf..84f44c34ad8 100644
--- a/components/servo/tests/webview.rs
+++ b/components/servo/tests/webview.rs
@@ -80,6 +80,16 @@ fn test_evaluate_javascript_basic(servo_test: &ServoTest) -> Result<(), anyhow::
let result = evaluate_javascript(servo_test, webview.clone(), "document.body");
ensure!(matches!(result, Ok(JSValue::Element(..))));
+ let result = evaluate_javascript(
+ servo_test,
+ webview.clone(),
+ "document.body.attachShadow({mode: 'open'})",
+ );
+ ensure!(matches!(result, Ok(JSValue::ShadowRoot(..))));
+
+ let result = evaluate_javascript(servo_test, webview.clone(), "document.body.shadowRoot");
+ ensure!(matches!(result, Ok(JSValue::ShadowRoot(..))));
+
let result = evaluate_javascript(
servo_test,
webview.clone(),
diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs
index ac500519768..2042f8d4eaa 100644
--- a/components/shared/embedder/lib.rs
+++ b/components/shared/embedder/lib.rs
@@ -1047,6 +1047,7 @@ pub enum JSValue {
Number(f64),
String(String),
Element(String),
+ ShadowRoot(String),
Frame(String),
Window(String),
Array(Vec),
diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs
index f40af46d039..da0f73f2e7b 100644
--- a/components/shared/embedder/webdriver.rs
+++ b/components/shared/embedder/webdriver.rs
@@ -256,6 +256,7 @@ pub enum WebDriverJSError {
/// Occurs when handler received an event message for a layout channel that is not
/// associated with the current script thread
BrowsingContextNotFound,
+ DetachedShadowRoot,
JSException(JSValue),
JSError,
StaleElementReference,
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index 1090fcf982b..b99c7c1b878 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -260,6 +260,7 @@ impl Serialize for SendableJSValue {
JSValue::Number(x) => serializer.serialize_f64(x),
JSValue::String(ref x) => serializer.serialize_str(x),
JSValue::Element(ref x) => WebElement(x.clone()).serialize(serializer),
+ JSValue::ShadowRoot(ref x) => ShadowRoot(x.clone()).serialize(serializer),
JSValue::Frame(ref x) => WebFrame(x.clone()).serialize(serializer),
JSValue::Window(ref x) => WebWindow(x.clone()).serialize(serializer),
JSValue::Array(ref x) => x
@@ -2066,6 +2067,10 @@ impl Handler {
ErrorStatus::StaleElementReference,
"Stale element",
)),
+ Err(WebDriverJSError::DetachedShadowRoot) => Err(WebDriverError::new(
+ ErrorStatus::DetachedShadowRoot,
+ "Detached shadow root",
+ )),
Err(WebDriverJSError::Timeout) => {
Err(WebDriverError::new(ErrorStatus::ScriptTimeout, ""))
},
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini
index aac667cc691..5f1d34e6018 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/arguments.py.ini
@@ -35,8 +35,5 @@
[test_element_reference[frame\]]
expected: FAIL
- [test_element_reference[shadow-root\]]
- expected: FAIL
-
[test_element_reference[window\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/node.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/node.py.ini
index 0d4bc418417..847fea98bbf 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_async_script/node.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_async_script/node.py.ini
@@ -1,13 +1,4 @@
[node.py]
- [test_detached_shadow_root[top_context\]]
- expected: FAIL
-
- [test_detached_shadow_root[child_context\]]
- expected: FAIL
-
- [test_element_reference[shadow-root\]]
- expected: FAIL
-
[test_not_supported_nodes[attribute\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini
index aac667cc691..5f1d34e6018 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_script/arguments.py.ini
@@ -35,8 +35,5 @@
[test_element_reference[frame\]]
expected: FAIL
- [test_element_reference[shadow-root\]]
- expected: FAIL
-
[test_element_reference[window\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/execute_script/node.py.ini b/tests/wpt/meta/webdriver/tests/classic/execute_script/node.py.ini
index 67480399962..847fea98bbf 100644
--- a/tests/wpt/meta/webdriver/tests/classic/execute_script/node.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/execute_script/node.py.ini
@@ -1,13 +1,4 @@
[node.py]
- [test_detached_shadow_root[top_context\]]
- expected: FAIL
-
- [test_detached_shadow_root[child_context\]]
- expected: FAIL
-
- [test_web_reference[shadow-root\]]
- expected: FAIL
-
[test_not_supported_nodes[attribute\]]
expected: FAIL
diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini
index 4844164d09c..bb9de0071f4 100644
--- a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini
+++ b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini
@@ -1,6 +1,3 @@
[get.py]
[test_no_browsing_context]
expected: FAIL
-
- [test_web_reference[shadowRoot-ShadowRoot\]]
- expected: FAIL