tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

scope-nesting.html (20726B)


      1 <!DOCTYPE html>
      2 <title>@scope - nesting (&)</title>
      3 <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule">
      4 <link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nest-selector">
      5 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9740">
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <main id=main></main>
      9 
     10 <template id=test_nest_scope_end>
     11  <div>
     12    <style>
     13      /* (& > .b) behaves like (:where(:scope) > .b), due & mapping to :where(:scope).*/
     14      @scope (.a) to (& > .b) {
     15        :scope { z-index:1; }
     16      }
     17 
     18      /* Should not match, since <scope-end> refers to the scope itself. */
     19      @scope (.a) to (.b&) {
     20        :scope { z-index:42; }
     21      }
     22    </style>
     23    <div class="a b">
     24      <div class=b>
     25        <div id=below></div>
     26      </div>
     27    </div>
     28  </div>
     29  <div id=outside></div>
     30 </template>
     31 <script>
     32 test((t) => {
     33  t.add_cleanup(() => main.replaceChildren());
     34  main.append(test_nest_scope_end.content.cloneNode(true));
     35  let a = document.querySelector('.a');
     36  let b = document.querySelector('.a > .b');
     37  assert_equals(getComputedStyle(a).zIndex, '1');
     38  assert_equals(getComputedStyle(b).zIndex, 'auto');
     39  assert_equals(getComputedStyle(below).zIndex, 'auto');
     40  assert_equals(getComputedStyle(outside).zIndex, 'auto');
     41 }, 'Nesting-selector in <scope-end>');
     42 </script>
     43 
     44 <template id=test_nest_scope_end_implicit_scope>
     45  <div>
     46    <style>
     47      /* (.b) behaves like (:scope .b), due :scope being prepended
     48          implicitly. */
     49      @scope (.a) to (.b) {
     50        :scope { z-index:1; }
     51      }
     52 
     53      /* Should not match, since <scope-end> refers to the scope itself. */
     54      @scope (.a) to (.b:scope) {
     55        :scope { z-index:42; }
     56      }
     57    </style>
     58    <div class="a b">
     59      <div class=b>
     60        <div id=below></div>
     61      </div>
     62    </div>
     63  </div>
     64  <div id=outside></div>
     65 </template>
     66 <script>
     67 test((t) => {
     68  t.add_cleanup(() => main.replaceChildren());
     69  main.append(test_nest_scope_end_implicit_scope.content.cloneNode(true));
     70  let a = document.querySelector('.a');
     71  let b = document.querySelector('.a > .b');
     72  assert_equals(getComputedStyle(a).zIndex, '1');
     73  assert_equals(getComputedStyle(b).zIndex, 'auto');
     74  assert_equals(getComputedStyle(below).zIndex, 'auto');
     75  assert_equals(getComputedStyle(outside).zIndex, 'auto');
     76 }, 'Implicit :scope in <scope-end>');
     77 </script>
     78 
     79 <template id=test_relative_selector_scope_end>
     80  <div>
     81    <style>
     82      @scope (.a) to (> .b) {
     83        *, :scope { z-index:1; }
     84      }
     85    </style>
     86    <div class="a b">
     87      <div class=b>
     88        <div id=below></div>
     89      </div>
     90    </div>
     91  </div>
     92  <div id=outside></div>
     93 </template>
     94 <script>
     95 test((t) => {
     96  t.add_cleanup(() => main.replaceChildren());
     97  main.append(test_relative_selector_scope_end.content.cloneNode(true));
     98  let a = document.querySelector('.a');
     99  let b = document.querySelector('.a > .b');
    100  assert_equals(getComputedStyle(a).zIndex, '1');
    101  assert_equals(getComputedStyle(b).zIndex, 'auto');
    102  assert_equals(getComputedStyle(below).zIndex, 'auto');
    103  assert_equals(getComputedStyle(outside).zIndex, 'auto');
    104 }, 'Relative selectors in <scope-end>');
    105 </script>
    106 
    107 <template id=test_inner_nest>
    108  <div>
    109    <style>
    110      @scope (#div) {
    111        & {
    112          z-index: 1;
    113          & {
    114            z-index: 2;
    115          }
    116        }
    117      }
    118    </style>
    119    <div id=div></div>
    120  </div>
    121 </template>
    122 <script>
    123 test((t) => {
    124  t.add_cleanup(() => main.replaceChildren());
    125  main.append(test_inner_nest.content.cloneNode(true));
    126 
    127  assert_equals(getComputedStyle(div).zIndex, '2');
    128 }, 'Nested nesting-selectors within scope\'s <stylesheet> select inclusive descendants of the scope root');
    129 </script>
    130 
    131 <template id=test_parent_in_pseudo_scope>
    132  <div>
    133    <style>
    134      @scope (#div) {
    135        :scope {
    136          z-index: 1;
    137          & {
    138            z-index: 2;
    139          }
    140        }
    141      }
    142    </style>
    143    <div id=div></div>
    144  </div>
    145 </template>
    146 <script>
    147 test((t) => {
    148  t.add_cleanup(() => main.replaceChildren());
    149  main.append(test_parent_in_pseudo_scope.content.cloneNode(true));
    150 
    151  assert_equals(getComputedStyle(div).zIndex, '2');
    152 }, 'Nesting-selector within :scope rule');
    153 </script>
    154 
    155 <template id=test_parent_in_pseudo_scope_double>
    156  <div>
    157    <style>
    158      @scope (#div) {
    159        :scope {
    160          z-index: 1;
    161          & {
    162            & {
    163              z-index: 2;
    164            }
    165          }
    166        }
    167      }
    168    </style>
    169    <div id=div></div>
    170  </div>
    171 </template>
    172 <script>
    173 test((t) => {
    174  t.add_cleanup(() => main.replaceChildren());
    175  main.append(test_parent_in_pseudo_scope_double.content.cloneNode(true));
    176 
    177  assert_equals(getComputedStyle(div).zIndex, '2');
    178 }, 'Nesting-selector within :scope rule (double nested)');
    179 </script>
    180 
    181 <template id=test_scope_within_style_rule>
    182  <div>
    183    <style>
    184      .a {
    185        @scope (.b) {
    186          .c { z-index: 1; }
    187        }
    188      }
    189    </style>
    190    <div class=a>
    191      <div class=b>
    192        <div class=c>
    193        </div>
    194      </div>
    195      <div id=out_of_scope class=c>
    196      </div>
    197    </div>
    198  </div>
    199 </template>
    200 <script>
    201 test((t) => {
    202  t.add_cleanup(() => main.replaceChildren());
    203  main.append(test_scope_within_style_rule.content.cloneNode(true));
    204 
    205  let c = document.querySelector('.c');
    206  assert_equals(getComputedStyle(c).zIndex, '1');
    207  assert_equals(getComputedStyle(out_of_scope).zIndex, 'auto');
    208 }, '@scope nested within style rule');
    209 </script>
    210 
    211 <template id=test_parent_pseudo_in_nested_scope_start>
    212  <div>
    213    <style>
    214      .a {
    215        @scope (&.b) {
    216          :scope { z-index: 1; }
    217        }
    218      }
    219    </style>
    220    <div class=a></div>
    221    <div class=b></div>
    222    <div class="a b"></div>
    223  </div>
    224 </template>
    225 <script>
    226 test((t) => {
    227  t.add_cleanup(() => main.replaceChildren());
    228  main.append(test_parent_pseudo_in_nested_scope_start.content.cloneNode(true));
    229 
    230  let a = document.querySelector('.a:not(.b)');
    231  let b = document.querySelector('.b:not(.a)');
    232  let ab = document.querySelector('.a.b');
    233  assert_equals(getComputedStyle(a).zIndex, 'auto');
    234  assert_equals(getComputedStyle(b).zIndex, 'auto');
    235  assert_equals(getComputedStyle(ab).zIndex, '1');
    236 }, 'Parent pseudo class within scope-start');
    237 </script>
    238 
    239 
    240 <template id=test_parent_pseudo_in_nested_scope_body>
    241  <div>
    242    <style>
    243      .a {
    244        @scope (.b) {
    245           /* The & points to <scope-start>, which contains an implicit &
    246              which points to .a. */
    247           &.c { z-index: 1; }
    248        }
    249      }
    250    </style>
    251    <div class=a>
    252      <div class=b>
    253        <div class="c"></div>
    254        <div class="a c"></div>
    255        <div class="a b c" matching></div>
    256      </div>
    257    </div>
    258    <div>
    259      <div class=a></div>
    260      <div class=b></div>
    261      <div class=c></div>
    262      <div class="a b"></div>
    263      <div class="a c"></div>
    264      <div class="b c"></div>
    265    </div>
    266  </div>
    267 </template>
    268 <script>
    269 test((t) => {
    270  t.add_cleanup(() => main.replaceChildren());
    271  main.append(test_parent_pseudo_in_nested_scope_body.content.cloneNode(true));
    272 
    273  let matching = main.querySelectorAll("div[matching]");
    274  let non_matching = main.querySelectorAll("div:not([matching])");
    275 
    276  for (let m of matching) {
    277    assert_equals(getComputedStyle(m).zIndex, '1', `matching: ${m.nodeName}${m.className}`);
    278  }
    279  for (let m of non_matching) {
    280    assert_equals(getComputedStyle(m).zIndex, 'auto', `non-matching: ${m.nodeName}${m.className}`);
    281  }
    282 }, 'Parent pseudo class within body of nested @scope');
    283 </script>
    284 
    285 <template id=test_direct_declarations_in_nested_scope>
    286  <div>
    287    <style>
    288      .a {
    289        @scope (.b) {
    290          z-index: 1;
    291        }
    292      }
    293    </style>
    294    <div class=a>
    295      <div class=b>
    296        <div class="c"></div>
    297      </div>
    298    </div>
    299  </div>
    300 </template>
    301 <script>
    302 test((t) => {
    303  t.add_cleanup(() => main.replaceChildren());
    304  main.append(test_direct_declarations_in_nested_scope.content.cloneNode(true));
    305 
    306  let a = document.querySelector('.a');
    307  let b = document.querySelector('.b');
    308  let c = document.querySelector('.c');
    309  assert_equals(getComputedStyle(a).zIndex, 'auto');
    310  assert_equals(getComputedStyle(b).zIndex, '1');
    311  assert_equals(getComputedStyle(c).zIndex, 'auto');
    312 }, 'Implicit rule within nested @scope ');
    313 </script>
    314 
    315 <template id=test_direct_declarations_in_nested_scope_proximity>
    316  <div>
    317    <style>
    318      .a {
    319        /* The '& .b' selector is wrapped in :where() to prevent a false
    320           positive when the implementation incorrectly wraps
    321           the z-index declaration in a rule with &-behavior
    322           rather than :where(:scope)-behavior. */
    323        @scope (:where(& .b)) {
    324          z-index: 1; /* Should win due to proximity */
    325        }
    326      }
    327      :where(.b) { z-index: 2; }
    328    </style>
    329    <div class=a>
    330      <div class="b x">
    331        <div class=c>
    332        </div>
    333      </div>
    334    </div>
    335  </div>
    336 </template>
    337 <script>
    338 test((t) => {
    339  t.add_cleanup(() => main.replaceChildren());
    340  main.append(test_direct_declarations_in_nested_scope_proximity.content.cloneNode(true));
    341 
    342  let a = document.querySelector('.a');
    343  let b = document.querySelector('.b');
    344  let c = document.querySelector('.c');
    345  assert_equals(getComputedStyle(a).zIndex, 'auto');
    346  assert_equals(getComputedStyle(b).zIndex, '1');
    347  assert_equals(getComputedStyle(c).zIndex, 'auto');
    348 }, 'Implicit rule within nested @scope (proximity)');
    349 </script>
    350 
    351 <template id=test_nested_scope_inside_an_is>
    352  <div>
    353    <style>
    354      @scope (.a) {
    355        .b {
    356          /* When nesting, because we’re  inside a defined scope,
    357             the `:scope` should reference the scoping root node properly, and
    358             check for the presence of an extra class on it, essentially
    359             being equal to `:scope.x .b { z-index: 1 }`. */
    360          &:is(:scope.x *) {
    361            z-index: 1;
    362          }
    363          /* This should not match, as we have a defined scope, and should
    364             not skip to the root. */
    365          &:is(:root:scope *) {
    366            z-index: 2;
    367          }
    368        }
    369        /* The nested case can be though of the following when expanded: */
    370        .c:is(:scope.x *) {
    371          z-index: 3;
    372        }
    373      }
    374    </style>
    375    <div class="b">
    376    </div>
    377    <div class="a x">
    378      <div class="b">
    379      </div>
    380      <div class="c">
    381      </div>
    382    </div>
    383 </div>
    384 </template>
    385 <script>
    386 test((t) => {
    387  t.add_cleanup(() => main.replaceChildren());
    388  main.append(test_nested_scope_inside_an_is.content.cloneNode(true));
    389 
    390  let b_outside = document.querySelector('.b');
    391  let b_inside = document.querySelector('.a .b');
    392  let c = document.querySelector('.c');
    393  assert_equals(getComputedStyle(b_outside).zIndex, 'auto');
    394  assert_equals(getComputedStyle(b_inside).zIndex, '1');
    395  assert_equals(getComputedStyle(c).zIndex, '3');
    396 }, 'Nested :scope inside an :is');
    397 </script>
    398 
    399 <template id=test_nested_scope_pseudo>
    400  <div>
    401    <style>
    402      @scope (.b) {
    403        .a:not(:scope) {
    404          & :scope {
    405            z-index: 1;
    406          }
    407        }
    408      }
    409    </style>
    410    <div class="b">
    411    </div>
    412    <div class="a">
    413      <div class="b">
    414      </div>
    415    </div>
    416 </div>
    417 </template>
    418 <script>
    419 test((t) => {
    420  t.add_cleanup(() => main.replaceChildren());
    421  main.append(test_nested_scope_pseudo.content.cloneNode(true));
    422 
    423  let b_outside = document.querySelector('.b');
    424  let b_inside = document.querySelector('.a .b');
    425  assert_equals(getComputedStyle(b_outside).zIndex, 'auto');
    426  assert_equals(getComputedStyle(b_inside).zIndex, '1');
    427 }, ':scope within nested and scoped rule');
    428 </script>
    429 
    430 <template id=test_nested_scope_pseudo_implied>
    431  <div>
    432    <style>
    433      @scope (.b) {
    434        .a:not(:scope) {
    435          :scope { /* & implied */
    436            z-index: 1;
    437          }
    438        }
    439      }
    440    </style>
    441    <div class="b">
    442    </div>
    443    <div class="a">
    444      <div class="b">
    445      </div>
    446    </div>
    447 </div>
    448 </template>
    449 <script>
    450 test((t) => {
    451  t.add_cleanup(() => main.replaceChildren());
    452  main.append(test_nested_scope_pseudo_implied.content.cloneNode(true));
    453 
    454  let b_outside = document.querySelector('.b');
    455  let b_inside = document.querySelector('.a .b');
    456  assert_equals(getComputedStyle(b_outside).zIndex, 'auto');
    457  assert_equals(getComputedStyle(b_inside).zIndex, '1');
    458 }, ':scope within nested and scoped rule (implied &)');
    459 </script>
    460 
    461 <template id=test_nested_scope_pseudo_relative>
    462  <div>
    463    <style>
    464      @scope (.b) {
    465        .a:not(:scope) {
    466          > :scope { /* & implied */
    467            z-index: 1;
    468          }
    469        }
    470      }
    471    </style>
    472    <div class="b">
    473    </div>
    474    <div class="a">
    475      <div class="b">
    476      </div>
    477    </div>
    478 </div>
    479 </template>
    480 <script>
    481 test((t) => {
    482  t.add_cleanup(() => main.replaceChildren());
    483  main.append(test_nested_scope_pseudo_relative.content.cloneNode(true));
    484 
    485  let b_outside = document.querySelector('.b');
    486  let b_inside = document.querySelector('.a .b');
    487  assert_equals(getComputedStyle(b_outside).zIndex, 'auto');
    488  assert_equals(getComputedStyle(b_inside).zIndex, '1');
    489 }, ':scope within nested and scoped rule (relative)');
    490 </script>
    491 
    492 <template id=test_scoped_nested_group_rule>
    493  <div>
    494    <style>
    495      @scope (.a) {
    496        .b:not(:scope) {
    497          @media (width) {
    498            z-index: 1;
    499          }
    500        }
    501      }
    502    </style>
    503    <div class="b">
    504    </div>
    505    <div class="a">
    506      <div class="b">
    507      </div>
    508    </div>
    509 </div>
    510 </template>
    511 <script>
    512 test((t) => {
    513  t.add_cleanup(() => main.replaceChildren());
    514  main.append(test_scoped_nested_group_rule.content.cloneNode(true));
    515 
    516  let b_outside = document.querySelector('.b');
    517  let b_inside = document.querySelector('.a .b');
    518  assert_equals(getComputedStyle(b_outside).zIndex, 'auto');
    519  assert_equals(getComputedStyle(b_inside).zIndex, '1');
    520 }, 'Scoped nested group rule');
    521 </script>
    522 
    523 <template id=test_scoped_within_scoped>
    524  <div>
    525    <style>
    526      @scope (.a) {
    527        @scope(#descendant) {
    528          :scope {
    529            z-index: 1;
    530          }
    531        }
    532        @scope (> #child) {
    533          :scope {
    534            z-index: 1;
    535          }
    536        }
    537      }
    538    </style>
    539    <div class="a">
    540      <div id="descendant">
    541      </div>
    542      <div id="child">
    543      </div>
    544    </div>
    545 </div>
    546 </template>
    547 <script>
    548 test((t) => {
    549  t.add_cleanup(() => main.replaceChildren());
    550  main.append(test_scoped_within_scoped.content.cloneNode(true));
    551 
    552  assert_equals(getComputedStyle(descendant).zIndex, '1');
    553  assert_equals(getComputedStyle(child).zIndex, '1');
    554 }, 'Scoped nested within another scope');
    555 </script>
    556 
    557 <template id=test_implicit_scope_nested_group_rule>
    558  <div class=nest>
    559    <style>
    560      .nest {
    561        @scope {
    562          #child {
    563            color: green;
    564          }
    565        }
    566      }
    567    </style>
    568    <div id=child>Foo</div>
    569 </div>
    570 </template>
    571 <script>
    572 test((t) => {
    573  t.add_cleanup(() => main.replaceChildren());
    574  main.append(test_implicit_scope_nested_group_rule.content.cloneNode(true));
    575  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
    576 }, 'Implicit (prelude-less) @scope as a nested group rule');
    577 </script>
    578 
    579 <template id=test_insert_ampersand_rule_within_scope>
    580 <style>
    581  .a {
    582    @scope (.b) {
    583      #child {
    584        color: red;
    585      }
    586    }
    587  }
    588 </style>
    589 <div class=a>
    590  <div class=b>
    591    <div id=child>Foo</div>
    592  </div>
    593 </div>
    594 </template>
    595 <script>
    596 test((t) => {
    597  t.add_cleanup(() => main.replaceChildren());
    598  main.append(test_insert_ampersand_rule_within_scope.content.cloneNode(true));
    599  assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
    600  let scope_rule = main.querySelector('style').sheet.cssRules[0].cssRules[0];
    601  // & does not add specificity - inserting it up front does nothing...
    602  scope_rule.insertRule('& #child { color: green; }', 0);
    603  assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
    604  scope_rule.deleteRule(0);
    605  // ... But inserting it at the end makes it win by order of appearance.
    606  scope_rule.insertRule('& #child { color: green; }', scope_rule.cssRules.length);
    607  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
    608 }, 'Insert a nested style rule within @scope, &');
    609 </script>
    610 
    611 <template id=test_insert_pseudo_scope_rule_within_scope>
    612 <style>
    613  .a {
    614    @scope (.b) {
    615      #child {
    616        color: red;
    617      }
    618    }
    619  }
    620 </style>
    621 <div class=a>
    622  <div class=b>
    623    <div id=child>Foo</div>
    624  </div>
    625 </div>
    626 </template>
    627 <script>
    628 test((t) => {
    629  t.add_cleanup(() => main.replaceChildren());
    630  main.append(test_insert_pseudo_scope_rule_within_scope.content.cloneNode(true));
    631  assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
    632  let scope_rule = main.querySelector('style').sheet.cssRules[0].cssRules[0];
    633  scope_rule.insertRule(':scope #child { color: green; }');
    634  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
    635 }, 'Insert a nested style rule within @scope, :scope');
    636 </script>
    637 
    638 <template id=test_insert_nested_declarations_directly>
    639 <style>
    640  :where(.a) {
    641    color: red;
    642  }
    643  @scope (.a) {
    644  }
    645 </style>
    646 <div class=a>
    647  <div id=child>Foo</div>
    648 </div>
    649 </template>
    650 <script>
    651 test((t) => {
    652  t.add_cleanup(() => main.replaceChildren());
    653  main.append(test_insert_nested_declarations_directly.content.cloneNode(true));
    654  assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
    655  let scope_rule = main.querySelector('style').sheet.cssRules[1];
    656  assert_true(scope_rule instanceof CSSScopeRule);
    657  scope_rule.insertRule('color: green');
    658  assert_true(scope_rule.cssRules[0] instanceof CSSNestedDeclarations);
    659  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
    660 }, 'Insert a CSSNestedDeclarations rule directly in top-level @scope');
    661 </script>
    662 
    663 <template id=test_mutate_outer_selector_text_nested_declaration>
    664 <style>
    665  #child {
    666    color: green; /* Specificity: (1, 0, 0) */
    667  }
    668  .b {
    669    #child {
    670      @scope (&) {
    671        --x: 1;
    672        color: red; /* Specificity: (0, 0, 0), effectively :where(:scope) */
    673      }
    674    }
    675  }
    676 </style>
    677 <div class=a>
    678  <div id=child>Foo</div>
    679 </div>
    680 </template>
    681 <script>
    682 test((t) => {
    683  t.add_cleanup(() => main.replaceChildren());
    684  main.append(test_mutate_outer_selector_text_nested_declaration.content.cloneNode(true));
    685  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
    686  assert_equals(getComputedStyle(child).getPropertyValue('--x'), '');
    687 
    688  let outer_rule = main.querySelector('style').sheet.cssRules[1];
    689  assert_equals(outer_rule.selectorText, '.b');
    690  outer_rule.selectorText = '.a';
    691 
    692  assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)'); // Unchanged.
    693  assert_equals(getComputedStyle(child).getPropertyValue('--x'), '1'); // Changed.
    694 }, 'Mutating selectorText on outer style rule causes correct inner specificity');
    695 </script>
    696 
    697 <template id=test_set_selector_text>
    698  <style id=style>
    699    :where(.x) {
    700      background-color: black;
    701    }
    702    .a {
    703      @scope (&) {
    704        :scope .x { background-color: green; }
    705      }
    706    }
    707  </style>
    708  <div class=a>
    709    <div class=x>
    710    </div>
    711  </div>
    712  <div class=b>
    713    <div class=x>
    714    </div>
    715  </div>
    716 </template>
    717 <script>
    718 test((t) => {
    719  t.add_cleanup(() => main.replaceChildren());
    720  main.append(test_set_selector_text.content.cloneNode(true));
    721  let ax = main.querySelector('.a > .x');
    722  let bx = main.querySelector('.b > .x');
    723  assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)');
    724  assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)');
    725  style.sheet.cssRules[1].selectorText = '.b'; // .a -> .
    726  assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)');
    727  assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)');
    728 }, 'Modifying selectorText invalidates inner scoped rules');
    729 </script>
    730 
    731 <template id=test_set_selector_text_nested_declarations>
    732  <style id=style>
    733    :where(.x) {
    734      background-color: black;
    735    }
    736    .a {
    737      @scope (&) {
    738        :scope .x {
    739          .unused {}
    740          /* CSSNestedDeclarations { */
    741          background-color: green;
    742          /* } { */
    743        }
    744      }
    745    }
    746  </style>
    747  <div class=a>
    748    <div class=x>
    749    </div>
    750  </div>
    751  <div class=b>
    752    <div class=x>
    753    </div>
    754  </div>
    755 </template>
    756 <script>
    757 test((t) => {
    758  t.add_cleanup(() => main.replaceChildren());
    759  main.append(test_set_selector_text_nested_declarations.content.cloneNode(true));
    760  let ax = main.querySelector('.a > .x');
    761  let bx = main.querySelector('.b > .x');
    762  assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 128, 0)');
    763  assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 0, 0)');
    764  style.sheet.cssRules[1].selectorText = '.b'; // .a -> .
    765  assert_equals(getComputedStyle(ax).backgroundColor, 'rgb(0, 0, 0)');
    766  assert_equals(getComputedStyle(bx).backgroundColor, 'rgb(0, 128, 0)');
    767 }, 'Modifying selectorText invalidates inner scoped rules (nested declarations)');
    768 </script>