webdriver: consider boolean attribute when get element attribute (#38401)

The function handle_get_attribute should act differently when the
attribute is a boolean attribute.

The full list of attributes can be found in [1]. All attributes marked
as "Boolean attribute" in the "Value" column are boolean attributes.
Note that "hidden" is effectively treated as a boolean attribute,
according to WPT test "test_global_boolean_attributes" in
webdriver/tests/classic/get_element_attribute/get.py

[1] https://html.spec.whatwg.org/multipage/#attributes-3

Testing: Updated WPT test expectation
Fixes: #38353

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
Kingsley Yung 2025-08-01 16:44:26 +08:00 committed by GitHub
parent 05ad9026f5
commit 5e8754bb1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 57 additions and 60 deletions

View file

@ -289,3 +289,47 @@ pub(crate) fn is_relevant_attribute(namespace: &Namespace, local_name: &LocalNam
// <https://svgwg.org/svg2-draft/linking.html#XLinkHrefAttribute>
namespace == &ns!() || (namespace == &ns!(xlink) && local_name == &local_name!("href"))
}
/// A help function to check if an attribute is a boolean attribute.
pub(crate) fn is_boolean_attribute(name: &str) -> bool {
// The full list of attributes can be found in [1]. All attributes marked as "Boolean
// attribute" in the "Value" column are boolean attributes. Note that "hidden" is effectively
// treated as a boolean attribute, according to WPT test "test_global_boolean_attributes" in
// webdriver/tests/classic/get_element_attribute/get.py
//
// [1] <https://html.spec.whatwg.org/multipage/#attributes-3>
[
"allowfullscreen",
"alpha",
"async",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"defer",
"disabled",
"formnovalidate",
"hidden",
"inert",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"playsinline",
"readonly",
"required",
"reversed",
"selected",
"shadowrootclonable",
"shadowrootcustomelementregistry",
"shadowrootdelegatesfocus",
"shadowrootserializable",
]
.iter()
.any(|&boolean_attr| boolean_attr.eq_ignore_ascii_case(name))
}

View file

@ -34,6 +34,7 @@ use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus;
use crate::document_collection::DocumentCollection;
use crate::dom::attr::is_boolean_attribute;
use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use crate::dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
@ -1582,9 +1583,18 @@ pub(crate) fn handle_get_attribute(
reply
.send(
get_known_element(documents, pipeline, node_id).map(|element| {
element
.GetAttribute(DOMString::from(name))
.map(String::from)
if is_boolean_attribute(&name) {
// element.get_attribute_by_name(DOMString::from(name)).map(|_| String::from("true"))
if element.HasAttribute(DOMString::from(name)) {
Some(String::from("true"))
} else {
None
}
} else {
element
.GetAttribute(DOMString::from(name))
.map(String::from)
}
}),
)
.unwrap();