LibWeb/CSS: Implement the :heading/:heading() pseudo-class

Corresponds to part of
65dc095e44
This commit is contained in:
Sam Atkins 2025-08-12 11:58:17 +01:00
commit 503d41d02d
Notes: github-actions[bot] 2025-08-13 08:48:42 +00:00
4 changed files with 422 additions and 0 deletions

View file

@ -50,6 +50,9 @@
"has": { "has": {
"argument": "<relative-selector-list>" "argument": "<relative-selector-list>"
}, },
"heading": {
"argument": "<an+b>#?"
},
"high-value": { "high-value": {
"argument": "" "argument": ""
}, },

View file

@ -1032,6 +1032,45 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
return custom_state_set->has_state(pseudo_class.ident->string_value); return custom_state_set->has_state(pseudo_class.ident->string_value);
return false; return false;
} }
case CSS::PseudoClass::Heading: {
// https://html.spec.whatwg.org/multipage/semantics-other.html#selector-heading
// The :heading pseudo-class must match all h1, h2, h3, h4, h5, and h6 elements.
// https://html.spec.whatwg.org/multipage/semantics-other.html#selector-heading-functional
// The :heading(An+B#) pseudo-class must match all h1, h2, h3, h4, h5, and h6 elements that have a heading level among An+B. [CSSSYNTAX] [CSSVALUES]
// NB: We combine the "is this an h* element?" and "what is it's level?" checks together here.
if (!element.is_html_element())
return false;
auto heading_level = [](auto& local_name) -> Optional<int> {
if (local_name == HTML::TagNames::h1)
return 1;
if (local_name == HTML::TagNames::h2)
return 2;
if (local_name == HTML::TagNames::h3)
return 3;
if (local_name == HTML::TagNames::h4)
return 4;
if (local_name == HTML::TagNames::h5)
return 5;
if (local_name == HTML::TagNames::h6)
return 6;
return {};
}(element.lowercased_local_name());
if (!heading_level.has_value())
return false;
if (pseudo_class.an_plus_b_patterns.is_empty())
return true;
for (auto const& an_plus_b_pattern : pseudo_class.an_plus_b_patterns) {
if (an_plus_b_pattern.matches(heading_level.value()))
return true;
}
return false;
}
} }
return false; return false;

View file

@ -0,0 +1,313 @@
Harness status: OK
Found 308 tests
308 Pass
Pass <h1 data-expect-match="1"></h1> :heading
Pass <h1 data-expect-match="1"></h1> :heading(1)
Pass <h1 data-expect-match="1"></h1> :heading(2)
Pass <h1 data-expect-match="1"></h1> :heading(3)
Pass <h1 data-expect-match="1"></h1> :heading(4)
Pass <h1 data-expect-match="1"></h1> :heading(5)
Pass <h1 data-expect-match="1"></h1> :heading(6)
Pass <h1 data-expect-match="1"></h1> :heading(7)
Pass <h1 data-expect-match="1"></h1> :heading(8)
Pass <h1 data-expect-match="1"></h1> :heading(9)
Pass <h1 data-expect-match="1"></h1> :heading(0)
Pass <h1 data-expect-match="1"></h1> :heading(-1)
Pass <h1 data-expect-match="1"></h1> :heading(0, 1, 2)
Pass <h1 data-expect-match="1"></h1> :heading(6, 7)
Pass <h1 data-expect-match="1"></h1> :heading(n)
Pass <h1 data-expect-match="1"></h1> :heading(2n)
Pass <h1 data-expect-match="1"></h1> :heading(2n+1)
Pass <h1 data-expect-match="1"></h1> :heading(2n+2)
Pass <h1 data-expect-match="1"></h1> :heading(-n+3)
Pass <h1 data-expect-match="1"></h1> :heading(2n, 3n)
Pass <h1 data-expect-match="1"></h1> :heading(even)
Pass <h1 data-expect-match="1"></h1> :heading(odd)
Pass <h2 data-expect-match="2"></h2> :heading
Pass <h2 data-expect-match="2"></h2> :heading(1)
Pass <h2 data-expect-match="2"></h2> :heading(2)
Pass <h2 data-expect-match="2"></h2> :heading(3)
Pass <h2 data-expect-match="2"></h2> :heading(4)
Pass <h2 data-expect-match="2"></h2> :heading(5)
Pass <h2 data-expect-match="2"></h2> :heading(6)
Pass <h2 data-expect-match="2"></h2> :heading(7)
Pass <h2 data-expect-match="2"></h2> :heading(8)
Pass <h2 data-expect-match="2"></h2> :heading(9)
Pass <h2 data-expect-match="2"></h2> :heading(0)
Pass <h2 data-expect-match="2"></h2> :heading(-1)
Pass <h2 data-expect-match="2"></h2> :heading(0, 1, 2)
Pass <h2 data-expect-match="2"></h2> :heading(6, 7)
Pass <h2 data-expect-match="2"></h2> :heading(n)
Pass <h2 data-expect-match="2"></h2> :heading(2n)
Pass <h2 data-expect-match="2"></h2> :heading(2n+1)
Pass <h2 data-expect-match="2"></h2> :heading(2n+2)
Pass <h2 data-expect-match="2"></h2> :heading(-n+3)
Pass <h2 data-expect-match="2"></h2> :heading(2n, 3n)
Pass <h2 data-expect-match="2"></h2> :heading(even)
Pass <h2 data-expect-match="2"></h2> :heading(odd)
Pass <h3 data-expect-match="3"></h3> :heading
Pass <h3 data-expect-match="3"></h3> :heading(1)
Pass <h3 data-expect-match="3"></h3> :heading(2)
Pass <h3 data-expect-match="3"></h3> :heading(3)
Pass <h3 data-expect-match="3"></h3> :heading(4)
Pass <h3 data-expect-match="3"></h3> :heading(5)
Pass <h3 data-expect-match="3"></h3> :heading(6)
Pass <h3 data-expect-match="3"></h3> :heading(7)
Pass <h3 data-expect-match="3"></h3> :heading(8)
Pass <h3 data-expect-match="3"></h3> :heading(9)
Pass <h3 data-expect-match="3"></h3> :heading(0)
Pass <h3 data-expect-match="3"></h3> :heading(-1)
Pass <h3 data-expect-match="3"></h3> :heading(0, 1, 2)
Pass <h3 data-expect-match="3"></h3> :heading(6, 7)
Pass <h3 data-expect-match="3"></h3> :heading(n)
Pass <h3 data-expect-match="3"></h3> :heading(2n)
Pass <h3 data-expect-match="3"></h3> :heading(2n+1)
Pass <h3 data-expect-match="3"></h3> :heading(2n+2)
Pass <h3 data-expect-match="3"></h3> :heading(-n+3)
Pass <h3 data-expect-match="3"></h3> :heading(2n, 3n)
Pass <h3 data-expect-match="3"></h3> :heading(even)
Pass <h3 data-expect-match="3"></h3> :heading(odd)
Pass <h4 data-expect-match="4"></h4> :heading
Pass <h4 data-expect-match="4"></h4> :heading(1)
Pass <h4 data-expect-match="4"></h4> :heading(2)
Pass <h4 data-expect-match="4"></h4> :heading(3)
Pass <h4 data-expect-match="4"></h4> :heading(4)
Pass <h4 data-expect-match="4"></h4> :heading(5)
Pass <h4 data-expect-match="4"></h4> :heading(6)
Pass <h4 data-expect-match="4"></h4> :heading(7)
Pass <h4 data-expect-match="4"></h4> :heading(8)
Pass <h4 data-expect-match="4"></h4> :heading(9)
Pass <h4 data-expect-match="4"></h4> :heading(0)
Pass <h4 data-expect-match="4"></h4> :heading(-1)
Pass <h4 data-expect-match="4"></h4> :heading(0, 1, 2)
Pass <h4 data-expect-match="4"></h4> :heading(6, 7)
Pass <h4 data-expect-match="4"></h4> :heading(n)
Pass <h4 data-expect-match="4"></h4> :heading(2n)
Pass <h4 data-expect-match="4"></h4> :heading(2n+1)
Pass <h4 data-expect-match="4"></h4> :heading(2n+2)
Pass <h4 data-expect-match="4"></h4> :heading(-n+3)
Pass <h4 data-expect-match="4"></h4> :heading(2n, 3n)
Pass <h4 data-expect-match="4"></h4> :heading(even)
Pass <h4 data-expect-match="4"></h4> :heading(odd)
Pass <h5 data-expect-match="5"></h5> :heading
Pass <h5 data-expect-match="5"></h5> :heading(1)
Pass <h5 data-expect-match="5"></h5> :heading(2)
Pass <h5 data-expect-match="5"></h5> :heading(3)
Pass <h5 data-expect-match="5"></h5> :heading(4)
Pass <h5 data-expect-match="5"></h5> :heading(5)
Pass <h5 data-expect-match="5"></h5> :heading(6)
Pass <h5 data-expect-match="5"></h5> :heading(7)
Pass <h5 data-expect-match="5"></h5> :heading(8)
Pass <h5 data-expect-match="5"></h5> :heading(9)
Pass <h5 data-expect-match="5"></h5> :heading(0)
Pass <h5 data-expect-match="5"></h5> :heading(-1)
Pass <h5 data-expect-match="5"></h5> :heading(0, 1, 2)
Pass <h5 data-expect-match="5"></h5> :heading(6, 7)
Pass <h5 data-expect-match="5"></h5> :heading(n)
Pass <h5 data-expect-match="5"></h5> :heading(2n)
Pass <h5 data-expect-match="5"></h5> :heading(2n+1)
Pass <h5 data-expect-match="5"></h5> :heading(2n+2)
Pass <h5 data-expect-match="5"></h5> :heading(-n+3)
Pass <h5 data-expect-match="5"></h5> :heading(2n, 3n)
Pass <h5 data-expect-match="5"></h5> :heading(even)
Pass <h5 data-expect-match="5"></h5> :heading(odd)
Pass <h6 data-expect-match="6"></h6> :heading
Pass <h6 data-expect-match="6"></h6> :heading(1)
Pass <h6 data-expect-match="6"></h6> :heading(2)
Pass <h6 data-expect-match="6"></h6> :heading(3)
Pass <h6 data-expect-match="6"></h6> :heading(4)
Pass <h6 data-expect-match="6"></h6> :heading(5)
Pass <h6 data-expect-match="6"></h6> :heading(6)
Pass <h6 data-expect-match="6"></h6> :heading(7)
Pass <h6 data-expect-match="6"></h6> :heading(8)
Pass <h6 data-expect-match="6"></h6> :heading(9)
Pass <h6 data-expect-match="6"></h6> :heading(0)
Pass <h6 data-expect-match="6"></h6> :heading(-1)
Pass <h6 data-expect-match="6"></h6> :heading(0, 1, 2)
Pass <h6 data-expect-match="6"></h6> :heading(6, 7)
Pass <h6 data-expect-match="6"></h6> :heading(n)
Pass <h6 data-expect-match="6"></h6> :heading(2n)
Pass <h6 data-expect-match="6"></h6> :heading(2n+1)
Pass <h6 data-expect-match="6"></h6> :heading(2n+2)
Pass <h6 data-expect-match="6"></h6> :heading(-n+3)
Pass <h6 data-expect-match="6"></h6> :heading(2n, 3n)
Pass <h6 data-expect-match="6"></h6> :heading(even)
Pass <h6 data-expect-match="6"></h6> :heading(odd)
Pass <h7 data-expect-match=""></h7> :heading
Pass <h7 data-expect-match=""></h7> :heading(1)
Pass <h7 data-expect-match=""></h7> :heading(2)
Pass <h7 data-expect-match=""></h7> :heading(3)
Pass <h7 data-expect-match=""></h7> :heading(4)
Pass <h7 data-expect-match=""></h7> :heading(5)
Pass <h7 data-expect-match=""></h7> :heading(6)
Pass <h7 data-expect-match=""></h7> :heading(7)
Pass <h7 data-expect-match=""></h7> :heading(8)
Pass <h7 data-expect-match=""></h7> :heading(9)
Pass <h7 data-expect-match=""></h7> :heading(0)
Pass <h7 data-expect-match=""></h7> :heading(-1)
Pass <h7 data-expect-match=""></h7> :heading(0, 1, 2)
Pass <h7 data-expect-match=""></h7> :heading(6, 7)
Pass <h7 data-expect-match=""></h7> :heading(n)
Pass <h7 data-expect-match=""></h7> :heading(2n)
Pass <h7 data-expect-match=""></h7> :heading(2n+1)
Pass <h7 data-expect-match=""></h7> :heading(2n+2)
Pass <h7 data-expect-match=""></h7> :heading(-n+3)
Pass <h7 data-expect-match=""></h7> :heading(2n, 3n)
Pass <h7 data-expect-match=""></h7> :heading(even)
Pass <h7 data-expect-match=""></h7> :heading(odd)
Pass <h8 data-expect-match=""></h8> :heading
Pass <h8 data-expect-match=""></h8> :heading(1)
Pass <h8 data-expect-match=""></h8> :heading(2)
Pass <h8 data-expect-match=""></h8> :heading(3)
Pass <h8 data-expect-match=""></h8> :heading(4)
Pass <h8 data-expect-match=""></h8> :heading(5)
Pass <h8 data-expect-match=""></h8> :heading(6)
Pass <h8 data-expect-match=""></h8> :heading(7)
Pass <h8 data-expect-match=""></h8> :heading(8)
Pass <h8 data-expect-match=""></h8> :heading(9)
Pass <h8 data-expect-match=""></h8> :heading(0)
Pass <h8 data-expect-match=""></h8> :heading(-1)
Pass <h8 data-expect-match=""></h8> :heading(0, 1, 2)
Pass <h8 data-expect-match=""></h8> :heading(6, 7)
Pass <h8 data-expect-match=""></h8> :heading(n)
Pass <h8 data-expect-match=""></h8> :heading(2n)
Pass <h8 data-expect-match=""></h8> :heading(2n+1)
Pass <h8 data-expect-match=""></h8> :heading(2n+2)
Pass <h8 data-expect-match=""></h8> :heading(-n+3)
Pass <h8 data-expect-match=""></h8> :heading(2n, 3n)
Pass <h8 data-expect-match=""></h8> :heading(even)
Pass <h8 data-expect-match=""></h8> :heading(odd)
Pass <h9 data-expect-match=""></h9> :heading
Pass <h9 data-expect-match=""></h9> :heading(1)
Pass <h9 data-expect-match=""></h9> :heading(2)
Pass <h9 data-expect-match=""></h9> :heading(3)
Pass <h9 data-expect-match=""></h9> :heading(4)
Pass <h9 data-expect-match=""></h9> :heading(5)
Pass <h9 data-expect-match=""></h9> :heading(6)
Pass <h9 data-expect-match=""></h9> :heading(7)
Pass <h9 data-expect-match=""></h9> :heading(8)
Pass <h9 data-expect-match=""></h9> :heading(9)
Pass <h9 data-expect-match=""></h9> :heading(0)
Pass <h9 data-expect-match=""></h9> :heading(-1)
Pass <h9 data-expect-match=""></h9> :heading(0, 1, 2)
Pass <h9 data-expect-match=""></h9> :heading(6, 7)
Pass <h9 data-expect-match=""></h9> :heading(n)
Pass <h9 data-expect-match=""></h9> :heading(2n)
Pass <h9 data-expect-match=""></h9> :heading(2n+1)
Pass <h9 data-expect-match=""></h9> :heading(2n+2)
Pass <h9 data-expect-match=""></h9> :heading(-n+3)
Pass <h9 data-expect-match=""></h9> :heading(2n, 3n)
Pass <h9 data-expect-match=""></h9> :heading(even)
Pass <h9 data-expect-match=""></h9> :heading(odd)
Pass <h0 data-expect-match=""></h0> :heading
Pass <h0 data-expect-match=""></h0> :heading(1)
Pass <h0 data-expect-match=""></h0> :heading(2)
Pass <h0 data-expect-match=""></h0> :heading(3)
Pass <h0 data-expect-match=""></h0> :heading(4)
Pass <h0 data-expect-match=""></h0> :heading(5)
Pass <h0 data-expect-match=""></h0> :heading(6)
Pass <h0 data-expect-match=""></h0> :heading(7)
Pass <h0 data-expect-match=""></h0> :heading(8)
Pass <h0 data-expect-match=""></h0> :heading(9)
Pass <h0 data-expect-match=""></h0> :heading(0)
Pass <h0 data-expect-match=""></h0> :heading(-1)
Pass <h0 data-expect-match=""></h0> :heading(0, 1, 2)
Pass <h0 data-expect-match=""></h0> :heading(6, 7)
Pass <h0 data-expect-match=""></h0> :heading(n)
Pass <h0 data-expect-match=""></h0> :heading(2n)
Pass <h0 data-expect-match=""></h0> :heading(2n+1)
Pass <h0 data-expect-match=""></h0> :heading(2n+2)
Pass <h0 data-expect-match=""></h0> :heading(-n+3)
Pass <h0 data-expect-match=""></h0> :heading(2n, 3n)
Pass <h0 data-expect-match=""></h0> :heading(even)
Pass <h0 data-expect-match=""></h0> :heading(odd)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(1)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(2)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(3)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(4)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(5)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(6)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(7)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(8)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(9)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(0)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(-1)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(0, 1, 2)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(6, 7)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(n)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(2n)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(2n+1)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(2n+2)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(-n+3)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(2n, 3n)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(even)
Pass <h1 data-expect-match="1" aria-level="2"></h1> :heading(odd)
Pass <h1 data-expect-match="1"></h1> in section :heading
Pass <h1 data-expect-match="1"></h1> in section :heading(1)
Pass <h1 data-expect-match="1"></h1> in section :heading(2)
Pass <h1 data-expect-match="1"></h1> in section :heading(3)
Pass <h1 data-expect-match="1"></h1> in section :heading(4)
Pass <h1 data-expect-match="1"></h1> in section :heading(5)
Pass <h1 data-expect-match="1"></h1> in section :heading(6)
Pass <h1 data-expect-match="1"></h1> in section :heading(7)
Pass <h1 data-expect-match="1"></h1> in section :heading(8)
Pass <h1 data-expect-match="1"></h1> in section :heading(9)
Pass <h1 data-expect-match="1"></h1> in section :heading(0)
Pass <h1 data-expect-match="1"></h1> in section :heading(-1)
Pass <h1 data-expect-match="1"></h1> in section :heading(0, 1, 2)
Pass <h1 data-expect-match="1"></h1> in section :heading(6, 7)
Pass <h1 data-expect-match="1"></h1> in section :heading(n)
Pass <h1 data-expect-match="1"></h1> in section :heading(2n)
Pass <h1 data-expect-match="1"></h1> in section :heading(2n+1)
Pass <h1 data-expect-match="1"></h1> in section :heading(2n+2)
Pass <h1 data-expect-match="1"></h1> in section :heading(-n+3)
Pass <h1 data-expect-match="1"></h1> in section :heading(2n, 3n)
Pass <h1 data-expect-match="1"></h1> in section :heading(even)
Pass <h1 data-expect-match="1"></h1> in section :heading(odd)
Pass <hgroup data-expect-match=""></hgroup> :heading
Pass <hgroup data-expect-match=""></hgroup> :heading(1)
Pass <hgroup data-expect-match=""></hgroup> :heading(2)
Pass <hgroup data-expect-match=""></hgroup> :heading(3)
Pass <hgroup data-expect-match=""></hgroup> :heading(4)
Pass <hgroup data-expect-match=""></hgroup> :heading(5)
Pass <hgroup data-expect-match=""></hgroup> :heading(6)
Pass <hgroup data-expect-match=""></hgroup> :heading(7)
Pass <hgroup data-expect-match=""></hgroup> :heading(8)
Pass <hgroup data-expect-match=""></hgroup> :heading(9)
Pass <hgroup data-expect-match=""></hgroup> :heading(0)
Pass <hgroup data-expect-match=""></hgroup> :heading(-1)
Pass <hgroup data-expect-match=""></hgroup> :heading(0, 1, 2)
Pass <hgroup data-expect-match=""></hgroup> :heading(6, 7)
Pass <hgroup data-expect-match=""></hgroup> :heading(n)
Pass <hgroup data-expect-match=""></hgroup> :heading(2n)
Pass <hgroup data-expect-match=""></hgroup> :heading(2n+1)
Pass <hgroup data-expect-match=""></hgroup> :heading(2n+2)
Pass <hgroup data-expect-match=""></hgroup> :heading(-n+3)
Pass <hgroup data-expect-match=""></hgroup> :heading(2n, 3n)
Pass <hgroup data-expect-match=""></hgroup> :heading(even)
Pass <hgroup data-expect-match=""></hgroup> :heading(odd)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(1)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(2)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(3)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(4)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(5)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(6)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(7)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(8)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(9)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(0)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(-1)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(0, 1, 2)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(6, 7)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(n)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(2n)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(2n+1)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(2n+2)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(-n+3)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(2n, 3n)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(even)
Pass <p role="heading" aria-level="1" data-expect-match=""></p> :heading(odd)

View file

@ -0,0 +1,67 @@
<!doctype html>
<meta charset=utf-8>
<title>:heading and :heading() pseudo-classes</title>
<link rel="help" href="https://drafts.csswg.org/selectors-5/#headings">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<h1 data-expect-match="1"></h1>
<h2 data-expect-match="2"></h2>
<h3 data-expect-match="3"></h3>
<h4 data-expect-match="4"></h4>
<h5 data-expect-match="5"></h5>
<h6 data-expect-match="6"></h6>
<h7 data-expect-match=""></h7>
<h8 data-expect-match=""></h8>
<h9 data-expect-match=""></h9>
<h0 data-expect-match=""></h0>
<h1 data-expect-match="1" aria-level="2"></h1>
<section><h1 data-expect-match="1"></h1></section>
<hgroup data-expect-match=""></hgroup>
<p role="heading" aria-level="1" data-expect-match=""></p>
<script>
const els = document.querySelectorAll('[data-expect-match]');
const tests = [
{args: ['1'], match: [1]},
{args: ['2'], match: [2]},
{args: ['3'], match: [3]},
{args: ['4'], match: [4]},
{args: ['5'], match: [5]},
{args: ['6'], match: [6]},
{args: ['7'], match: []},
{args: ['8'], match: []},
{args: ['9'], match: []},
{args: ['0'], match: []},
{args: ['-1'], match: []},
{args: ['0', '1', '2'], match: [1, 2]},
{args: ['6', '7'], match: [6]},
{args: ['n'], match: [1, 2, 3, 4, 5, 6]},
{args: ['2n'], match: [2, 4, 6]},
{args: ['2n+1'], match: [1, 3, 5]},
{args: ['2n+2'], match: [2, 4, 6]},
{args: ['-n+3'], match: [1, 2, 3]},
{args: ['2n', '3n'], match: [2, 3, 4, 6]},
{args: ['even'], match: [2, 4, 6]},
{args: ['odd'], match: [1, 3, 5]},
];
for (const el of els) {
const testName = el.outerHTML + (el.parentNode === document.body ? '' : ' in ' + el.parentNode.localName);
test(() => {
const matches = el.matches(':heading');
const shouldMatch = el.dataset.expectMatch !== "";
assert_equals(matches, shouldMatch);
}, testName + ' :heading');
for (const t of tests) {
const selector = `:heading(${t.args.join(', ')})`;
test(() => {
const matches = el.matches(selector);
const expectMatchLevel = parseInt(el.dataset.expectMatch, 10);
const shouldMatch = t.match.includes(expectMatchLevel);
assert_equals(matches, shouldMatch, selector);
}, testName + ' ' + selector);
}
}
</script>