Status: FAIL | Duration: 74ms | Subtests: 0/24 | Open test on wpt.live | wpt.fyi
Data from commit:
a50cb89 wpt: run reference-named files which are themselves tests (#836) (2026-09-03)
| Subtest | Status | Message |
|---|---|---|
| Nesting-selector in <scope-end> | FAIL | assert_equals: expected "1" but got "2" |
| Implicit :scope in <scope-end> | FAIL | assert_equals: expected "1" but got "2" |
| Relative selectors in <scope-end> | FAIL | assert_equals: expected "1" but got "2" |
| Nested nesting-selectors within scope's <stylesheet> select inclusive descendants of the scope root | FAIL | div is not defined |
| Nesting-selector within :scope rule | FAIL | div is not defined |
| Nesting-selector within :scope rule (double nested) | FAIL | div is not defined |
| @scope nested within style rule | FAIL | assert_equals: expected "1" but got "auto" |
| Parent pseudo class within scope-start | FAIL | assert_equals: expected "auto" but got "2" |
| Parent pseudo class within body of nested @scope | FAIL | assert_equals: matching: DIVa b c expected "1" but got "2" |
| Implicit rule within nested @scope | FAIL | assert_equals: expected "1" but got "2" |
| Implicit rule within nested @scope (proximity) | FAIL | assert_equals: expected "1" but got "2" |
| Nested :scope inside an :is | FAIL | assert_equals: expected "1" but got "auto" |
| :scope within nested and scoped rule | FAIL | assert_equals: expected "1" but got "auto" |
| :scope within nested and scoped rule (implied &) | FAIL | assert_equals: expected "1" but got "auto" |
| :scope within nested and scoped rule (relative) | FAIL | assert_equals: expected "1" but got "auto" |
| Scoped nested group rule | FAIL | assert_equals: expected "1" but got "auto" |
| Scoped nested within another scope | FAIL | descendant is not defined |
| Implicit (prelude-less) @scope as a nested group rule | FAIL | child is not defined |
| Insert a nested style rule within @scope, & | FAIL | child is not defined |
| Insert a nested style rule within @scope, :scope | FAIL | child is not defined |
| Insert a CSSNestedDeclarations rule directly in top-level @scope | FAIL | child is not defined |
| Mutating selectorText on outer style rule causes correct inner specificity | FAIL | child is not defined |
| Modifying selectorText invalidates inner scoped rules | FAIL | assert_equals: expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)" |
| Modifying selectorText invalidates inner scoped rules (nested declarations) | FAIL | assert_equals: expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)" |
/css/css-cascade/scope-nesting.html
<!DOCTYPE html> <title>@scope - nesting (&)</title> <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule"> <link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nest-selector"> <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9740"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <main id=main></main> <template id=test_nest_scope_end> <div> <style> /* (& > .b) behaves like (:where(:scope) > .b), due & mapping to :where(:scope).*/ @scope (.a) to (& > .b) { :scope { z-index:1; } } /* Should not match, since <scope-end> refers to the scope itself. */ @scope (.a) to (.b&) { :scope { z-index:42; } } </style> <div class="a b"> <div class=b> <div id=below></div> </div> </div> </div> <div id=outside></div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nest_scope_end.content.cloneNode(true)); let a = document.querySelector('.a'); let b = document.querySelector('.a > .b'); assert_equals(getComputedStyle(a).zIndex, '1'); assert_equals(getComputedStyle(b).zIndex, 'auto'); assert_equals(getComputedStyle(below).zIndex, 'auto'); assert_equals(getComputedStyle(outside).zIndex, 'auto'); }, 'Nesting-selector in <scope-end>'); </script> <template id=test_nest_scope_end_implicit_scope> <div> <style> /* (.b) behaves like (:scope .b), due :scope being prepended implicitly. */ @scope (.a) to (.b) { :scope { z-index:1; } } /* Should not match, since <scope-end> refers to the scope itself. */ @scope (.a) to (.b:scope) { :scope { z-index:42; } } </style> <div class="a b"> <div class=b> <div id=below></div> </div> </div> </div> <div id=outside></div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nest_scope_end_implicit_scope.content.cloneNode(true)); let a = document.querySelector('.a'); let b = document.querySelector('.a > .b'); assert_equals(getComputedStyle(a).zIndex, '1'); assert_equals(getComputedStyle(b).zIndex, 'auto'); assert_equals(getComputedStyle(below).zIndex, 'auto'); assert_equals(getComputedStyle(outside).zIndex, 'auto'); }, 'Implicit :scope in <scope-end>'); </script> <template id=test_relative_selector_scope_end> <div> <style> @scope (.a) to (> .b) { *, :scope { z-index:1; } } </style> <div class="a b"> <div class=b> <div id=below></div> </div> </div> </div> <div id=outside></div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_relative_selector_scope_end.content.cloneNode(true)); let a = document.querySelector('.a'); let b = document.querySelector('.a > .b'); assert_equals(getComputedStyle(a).zIndex, '1'); assert_equals(getComputedStyle(b).zIndex, 'auto'); assert_equals(getComputedStyle(below).zIndex, 'auto'); assert_equals(getComputedStyle(outside).zIndex, 'auto'); }, 'Relative selectors in <scope-end>'); </script> <template id=test_inner_nest> <div> <style> @scope (#div) { & { z-index: 1; & { z-index: 2; } } } </style> <div id=div></div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_inner_nest.content.cloneNode(true)); assert_equals(getComputedStyle(div).zIndex, '2'); }, 'Nested nesting-selectors within scope\'s <stylesheet> select inclusive descendants of the scope root'); </script> <template id=test_parent_in_pseudo_scope> <div> <style> @scope (#div) { :scope { z-index: 1; & { z-index: 2; } } } </style> <div id=div></div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_parent_in_pseudo_scope.content.cloneNode(true)); assert_equals(getComputedStyle(div).zIndex, '2'); }, 'Nesting-selector within :scope rule'); </script> <template id=test_parent_in_pseudo_scope_double> <div> <style> @scope (#div) { :scope { z-index: 1; & { & { z-index: 2; } } } } </style> <div id=div></div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_parent_in_pseudo_scope_double.content.cloneNode(true)); assert_equals(getComputedStyle(div).zIndex, '2'); }, 'Nesting-selector within :scope rule (double nested)'); </script> <template id=test_scope_within_style_rule> <div> <style> .a { @scope (.b) { .c { z-index: 1; } } } </style> <div class=a> <div class=b> <div class=c> </div> </div> <div id=out_of_scope class=c> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_scope_within_style_rule.content.cloneNode(true)); let c = document.querySelector('.c'); assert_equals(getComputedStyle(c).zIndex, '1'); assert_equals(getComputedStyle(out_of_scope).zIndex, 'auto'); }, '@scope nested within style rule'); </script> <template id=test_parent_pseudo_in_nested_scope_start> <div> <style> .a { @scope (&.b) { :scope { z-index: 1; } } } </style> <div class=a></div> <div class=b></div> <div class="a b"></div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_parent_pseudo_in_nested_scope_start.content.cloneNode(true)); let a = document.querySelector('.a:not(.b)'); let b = document.querySelector('.b:not(.a)'); let ab = document.querySelector('.a.b'); assert_equals(getComputedStyle(a).zIndex, 'auto'); assert_equals(getComputedStyle(b).zIndex, 'auto'); assert_equals(getComputedStyle(ab).zIndex, '1'); }, 'Parent pseudo class within scope-start'); </script> <template id=test_parent_pseudo_in_nested_scope_body> <div> <style> .a { @scope (.b) { /* The & points to <scope-start>, which contains an implicit & which points to .a. */ &.c { z-index: 1; } } } </style> <div class=a> <div class=b> <div class="c"></div> <div class="a c"></div> <div class="a b c" matching></div> </div> </div> <div> <div class=a></div> <div class=b></div> <div class=c></div> <div class="a b"></div> <div class="a c"></div> <div class="b c"></div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_parent_pseudo_in_nested_scope_body.content.cloneNode(true)); let matching = main.querySelectorAll("div[matching]"); let non_matching = main.querySelectorAll("div:not([matching])"); for (let m of matching) { assert_equals(getComputedStyle(m).zIndex, '1', `matching: ${m.nodeName}${m.className}`); } for (let m of non_matching) { assert_equals(getComputedStyle(m).zIndex, 'auto', `non-matching: ${m.nodeName}${m.className}`); } }, 'Parent pseudo class within body of nested @scope'); </script> <template id=test_direct_declarations_in_nested_scope> <div> <style> .a { @scope (.b) { z-index: 1; } } </style> <div class=a> <div class=b> <div class="c"></div> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_direct_declarations_in_nested_scope.content.cloneNode(true)); let a = document.querySelector('.a'); let b = document.querySelector('.b'); let c = document.querySelector('.c'); assert_equals(getComputedStyle(a).zIndex, 'auto'); assert_equals(getComputedStyle(b).zIndex, '1'); assert_equals(getComputedStyle(c).zIndex, 'auto'); }, 'Implicit rule within nested @scope '); </script> <template id=test_direct_declarations_in_nested_scope_proximity> <div> <style> .a { /* The '& .b' selector is wrapped in :where() to prevent a false positive when the implementation incorrectly wraps the z-index declaration in a rule with &-behavior rather than :where(:scope)-behavior. */ @scope (:where(& .b)) { z-index: 1; /* Should win due to proximity */ } } :where(.b) { z-index: 2; } </style> <div class=a> <div class="b x"> <div class=c> </div> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_direct_declarations_in_nested_scope_proximity.content.cloneNode(true)); let a = document.querySelector('.a'); let b = document.querySelector('.b'); let c = document.querySelector('.c'); assert_equals(getComputedStyle(a).zIndex, 'auto'); assert_equals(getComputedStyle(b).zIndex, '1'); assert_equals(getComputedStyle(c).zIndex, 'auto'); }, 'Implicit rule within nested @scope (proximity)'); </script> <template id=test_nested_scope_inside_an_is> <div> <style> @scope (.a) { .b { /* When nesting, because we’re inside a defined scope, the `:scope` should reference the scoping root node properly, and check for the presence of an extra class on it, essentially being equal to `:scope.x .b { z-index: 1 }`. */ &:is(:scope.x *) { z-index: 1; } /* This should not match, as we have a defined scope, and should not skip to the root. */ &:is(:root:scope *) { z-index: 2; } } /* The nested case can be though of the following when expanded: */ .c:is(:scope.x *) { z-index: 3; } } </style> <div class="b"> </div> <div class="a x"> <div class="b"> </div> <div class="c"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nested_scope_inside_an_is.content.cloneNode(true)); let b_outside = document.querySelector('.b'); let b_inside = document.querySelector('.a .b'); let c = document.querySelector('.c'); assert_equals(getComputedStyle(b_outside).zIndex, 'auto'); assert_equals(getComputedStyle(b_inside).zIndex, '1'); assert_equals(getComputedStyle(c).zIndex, '3'); }, 'Nested :scope inside an :is'); </script> <template id=test_nested_scope_pseudo> <div> <style> @scope (.b) { .a:not(:scope) { & :scope { z-index: 1; } } } </style> <div class="b"> </div> <div class="a"> <div class="b"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nested_scope_pseudo.content.cloneNode(true)); let b_outside = document.querySelector('.b'); let b_inside = document.querySelector('.a .b'); assert_equals(getComputedStyle(b_outside).zIndex, 'auto'); assert_equals(getComputedStyle(b_inside).zIndex, '1'); }, ':scope within nested and scoped rule'); </script> <template id=test_nested_scope_pseudo_implied> <div> <style> @scope (.b) { .a:not(:scope) { :scope { /* & implied */ z-index: 1; } } } </style> <div class="b"> </div> <div class="a"> <div class="b"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nested_scope_pseudo_implied.content.cloneNode(true)); let b_outside = document.querySelector('.b'); let b_inside = document.querySelector('.a .b'); assert_equals(getComputedStyle(b_outside).zIndex, 'auto'); assert_equals(getComputedStyle(b_inside).zIndex, '1'); }, ':scope within nested and scoped rule (implied &)'); </script> <template id=test_nested_scope_pseudo_relative> <div> <style> @scope (.b) { .a:not(:scope) { > :scope { /* & implied */ z-index: 1; } } } </style> <div class="b"> </div> <div class="a"> <div class="b"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_nested_scope_pseudo_relative.content.cloneNode(true)); let b_outside = document.querySelector('.b'); let b_inside = document.querySelector('.a .b'); assert_equals(getComputedStyle(b_outside).zIndex, 'auto'); assert_equals(getComputedStyle(b_inside).zIndex, '1'); }, ':scope within nested and scoped rule (relative)'); </script> <template id=test_scoped_nested_group_rule> <div> <style> @scope (.a) { .b:not(:scope) { @media (width) { z-index: 1; } } } </style> <div class="b"> </div> <div class="a"> <div class="b"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_scoped_nested_group_rule.content.cloneNode(true)); let b_outside = document.querySelector('.b'); let b_inside = document.querySelector('.a .b'); assert_equals(getComputedStyle(b_outside).zIndex, 'auto'); assert_equals(getComputedStyle(b_inside).zIndex, '1'); }, 'Scoped nested group rule'); </script> <template id=test_scoped_within_scoped> <div> <style> @scope (.a) { @scope(#descendant) { :scope { z-index: 1; } } @scope (> #child) { :scope { z-index: 1; } } } </style> <div class="a"> <div id="descendant"> </div> <div id="child"> </div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_scoped_within_scoped.content.cloneNode(true)); assert_equals(getComputedStyle(descendant).zIndex, '1'); assert_equals(getComputedStyle(child).zIndex, '1'); }, 'Scoped nested within another scope'); </script> <template id=test_implicit_scope_nested_group_rule> <div class=nest> <style> .nest { @scope { #child { color: green; } } } </style> <div id=child>Foo</div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_implicit_scope_nested_group_rule.content.cloneNode(true)); assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); }, 'Implicit (prelude-less) @scope as a nested group rule'); </script> <template id=test_insert_ampersand_rule_within_scope> <style> .a { @scope (.b) { #child { color: red; } } } </style> <div class=a> <div class=b> <div id=child>Foo</div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_insert_ampersand_rule_within_scope.content.cloneNode(true)); assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)'); let scope_rule = main.querySelector('style').sheet.cssRules[0].cssRules[0]; // & does not add specificity - inserting it up front does nothing... scope_rule.insertRule('& #child { color: green; }', 0); assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)'); scope_rule.deleteRule(0); // ... But inserting it at the end makes it win by order of appearance. scope_rule.insertRule('& #child { color: green; }', scope_rule.cssRules.length); assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); }, 'Insert a nested style rule within @scope, &'); </script> <template id=test_insert_pseudo_scope_rule_within_scope> <style> .a { @scope (.b) { #child { color: red; } } } </style> <div class=a> <div class=b> <div id=child>Foo</div> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_insert_pseudo_scope_rule_within_scope.content.cloneNode(true)); assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)'); let scope_rule = main.querySelector('style').sheet.cssRules[0].cssRules[0]; scope_rule.insertRule(':scope #child { color: green; }'); assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); }, 'Insert a nested style rule within @scope, :scope'); </script> <template id=test_insert_nested_declarations_directly> <style> :where(.a) { color: red; } @scope (.a) { } </style> <div class=a> <div id=child>Foo</div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_insert_nested_declarations_directly.content.cloneNode(true)); assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)'); let scope_rule = main.querySelector('style').sheet.cssRules[1]; assert_true(scope_rule instanceof CSSScopeRule); scope_rule.insertRule('color: green'); assert_true(scope_rule.cssRules[0] instanceof CSSNestedDeclarations); assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); }, 'Insert a CSSNestedDeclarations rule directly in top-level @scope'); </script> <template id=test_mutate_outer_selector_text_nested_declaration> <style> #child { color: green; /* Specificity: (1, 0, 0) */ } .b { #child { @scope (&) { --x: 1; color: red; /* Specificity: (0, 0, 0), effectively :where(:scope) */ } } } </style> <div class=a> <div id=child>Foo</div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_mutate_outer_selector_text_nested_declaration.content.cloneNode(true)); assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); assert_equals(getComputedStyle(child).getPropertyValue('--x'), ''); let outer_rule = main.querySelector('style').sheet.cssRules[1]; assert_equals(outer_rule.selectorText, '.b'); outer_rule.selectorText = '.a'; assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); // Unchanged. assert_equals(getComputedStyle(child).getPropertyValue('--x'), '1'); // Changed. }, 'Mutating selectorText on outer style rule causes correct inner specificity'); </script> <template id=test_set_selector_text> <style id=style> :where(.x) { background-color: black; } .a { @scope (&) { :scope .x { background-color: green; } } } </style> <div class=a> <div class=x> </div> </div> <div class=b> <div class=x> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_set_selector_text.content.cloneNode(true)); let ax = main.querySelector('.a > .x'); let bx = main.querySelector('.b > .x'); assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)'); assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)'); style.sheet.cssRules[1].selectorText = '.b'; // .a -> . assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)'); assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)'); }, 'Modifying selectorText invalidates inner scoped rules'); </script> <template id=test_set_selector_text_nested_declarations> <style id=style> :where(.x) { background-color: black; } .a { @scope (&) { :scope .x { .unused {} /* CSSNestedDeclarations { */ background-color: green; /* } { */ } } } </style> <div class=a> <div class=x> </div> </div> <div class=b> <div class=x> </div> </div> </template> <script> test((t) => { t.add_cleanup(() => main.replaceChildren()); main.append(test_set_selector_text_nested_declarations.content.cloneNode(true)); let ax = main.querySelector('.a > .x'); let bx = main.querySelector('.b > .x'); assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)'); assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)'); style.sheet.cssRules[1].selectorText = '.b'; // .a -> . assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)'); assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)'); }, 'Modifying selectorText invalidates inner scoped rules (nested declarations)'); </script>