diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index de35116ddb2..8d54331be8c 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -92,6 +92,36 @@ fn is_stale(element: &Element) -> bool { !element.owner_document().is_active() || !element.is_connected() } +/// +fn is_disabled(element: &Element) -> bool { + // Step 1. If element is an option element or element is an optgroup element + if element.is::() || element.is::() { + // Step 1.1. For each inclusive ancestor `ancestor` of element + let disabled = element + .upcast::() + .inclusive_ancestors(ShadowIncluding::No) + .any(|node| { + if node.is::() || node.is::() { + // Step 1.1.1. If `ancestor` is an optgroup element or `ancestor` is a select element, + // and `ancestor` is actually disabled, return true. + node.downcast::().unwrap().is_actually_disabled() + } else { + false + } + }); + + // Step 1.2 + // The spec suggests that we immediately return false if the above is not true. + // However, it causes disabled option element to not be considered as disabled. + // Hence, here we also check if the element itself is actually disabled. + if disabled { + return true; + } + } + // Step 2. Return element is actually disabled. + element.is_actually_disabled() +} + /// fn get_known_shadow_root( documents: &DocumentCollection, @@ -1881,7 +1911,7 @@ pub(crate) fn handle_element_click( } // Step 8.6 - if !option_element.Disabled() { + if !is_disabled(&element) { // Step 8.6.1 event_target.fire_event(atom!("input"), can_gc); @@ -1960,6 +1990,7 @@ fn get_element_pointer_interactable_paint_tree( }) } +/// pub(crate) fn handle_is_enabled( documents: &DocumentCollection, pipeline: PipelineId, @@ -1968,8 +1999,22 @@ pub(crate) fn handle_is_enabled( ) { reply .send( - get_known_element(documents, pipeline, element_id) - .map(|element| element.enabled_state()), + // Step 3. Let element be the result of trying to get a known element + get_known_element(documents, pipeline, element_id).map(|element| { + // In `get_known_element`, we confirmed that document exists + let document = documents.find_document(pipeline).unwrap(); + + // Step 4 + // Let enabled be a boolean initially set to true if session's + // current browsing context's active document's type is not "xml". + // Otherwise, let enabled to false and jump to the last step of this algorithm. + // Step 5. Set enabled to false if a form control is disabled. + if document.is_html_document() || document.is_xhtml_document() { + !is_disabled(&element) + } else { + false + } + }), ) .unwrap(); } diff --git a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini index 1fc6b68dc9f..a60d2c7debc 100644 --- a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini @@ -2,8 +2,5 @@ [test_no_browsing_context] expected: FAIL - [test_option_with_select[disabled\]] - expected: FAIL - - [test_optgroup_with_select[disabled\]] + [test_option_with_optgroup[disabled\]] expected: FAIL