From 8b2de413ae7be7ee8e8bed79059637f3dc8e337b Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Thu, 6 Feb 2025 11:14:55 +0000 Subject: [PATCH] LibWeb: Ensure selected options collection is created prior to access --- Libraries/LibWeb/HTML/HTMLSelectElement.cpp | 3 +- Libraries/LibWeb/HTML/HTMLSelectElement.h | 1 + .../wpt-import/dom/nodes/Element-closest.txt | 35 +++++++++ .../wpt-import/dom/nodes/Element-closest.html | 73 +++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Element-closest.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/dom/nodes/Element-closest.html diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index 58c61634277..a334f574c5b 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -718,7 +718,8 @@ bool HTMLSelectElement::suffering_from_being_missing() const // If the element has its required attribute specified, and either none of the option elements in the select element's list of options have their selectedness // set to true, or the only option element in the select element's list of options with its selectedness set to true is the placeholder label option, then the element is suffering from being // missing. - return has_attribute(HTML::AttributeNames::required) && (m_selected_options->length() == 0 || (m_selected_options->length() == 1 && m_selected_options->item(0) == placeholder_label_option())); + auto selected_options = this->selected_options(); + return has_attribute(HTML::AttributeNames::required) && (selected_options->length() == 0 || (selected_options->length() == 1 && selected_options->item(0) == placeholder_label_option())); } } diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.h b/Libraries/LibWeb/HTML/HTMLSelectElement.h index b34925578d4..ce1884c1c3c 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.h +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.h @@ -43,6 +43,7 @@ public: void remove(WebIDL::Long); GC::Ref selected_options(); + GC::Ref selected_options() const { return const_cast(this)->selected_options(); } WebIDL::Long selected_index() const; void set_selected_index(WebIDL::Long); diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Element-closest.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Element-closest.txt new file mode 100644 index 00000000000..9a72f3cf559 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Element-closest.txt @@ -0,0 +1,35 @@ +Harness status: OK + +Found 29 tests + +28 Pass +1 Fail +Pass Element.closest with context node 'test12' and selector 'select' +Pass Element.closest with context node 'test13' and selector 'fieldset' +Pass Element.closest with context node 'test13' and selector 'div' +Pass Element.closest with context node 'test3' and selector 'body' +Pass Element.closest with context node 'test4' and selector '[default]' +Pass Element.closest with context node 'test4' and selector '[selected]' +Pass Element.closest with context node 'test11' and selector '[selected]' +Pass Element.closest with context node 'test12' and selector '[name="form-a"]' +Pass Element.closest with context node 'test13' and selector 'form[name="form-a"]' +Pass Element.closest with context node 'test9' and selector 'input[required]' +Pass Element.closest with context node 'test9' and selector 'select[required]' +Pass Element.closest with context node 'test13' and selector 'div:not(.div1)' +Pass Element.closest with context node 'test6' and selector 'div.div3' +Pass Element.closest with context node 'test1' and selector 'div#test7' +Pass Element.closest with context node 'test12' and selector '.div3 > .div2' +Pass Element.closest with context node 'test12' and selector '.div3 > .div1' +Pass Element.closest with context node 'test9' and selector 'form > input[required]' +Pass Element.closest with context node 'test12' and selector 'fieldset > select[required]' +Pass Element.closest with context node 'test6' and selector 'input + fieldset' +Pass Element.closest with context node 'test3' and selector 'form + form' +Pass Element.closest with context node 'test5' and selector 'form + form' +Pass Element.closest with context node 'test10' and selector ':empty' +Pass Element.closest with context node 'test11' and selector ':last-child' +Pass Element.closest with context node 'test12' and selector ':first-child' +Pass Element.closest with context node 'test11' and selector ':invalid' +Pass Element.closest with context node 'test4' and selector ':scope' +Pass Element.closest with context node 'test4' and selector 'select > :scope' +Pass Element.closest with context node 'test4' and selector 'div > :scope' +Fail Element.closest with context node 'test4' and selector ':has(> :scope)' \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Element-closest.html b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Element-closest.html new file mode 100644 index 00000000000..fdc0ffd9627 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Element-closest.html @@ -0,0 +1,73 @@ + + +Test for Element.closest + + + + +
+