tor-browser

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

scope-invalidation.html (21480B)


      1 <!DOCTYPE html>
      2 <title>@scope - invalidation</title>
      3 <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule">
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script>
      7 
      8 function test_scope_invalidation(script_element, callback_fn, description) {
      9  test((t) => {
     10    // The provided <script> element must be an immedate subsequent sibling of
     11    // a <template> element.
     12    let template_element = script_element.previousElementSibling;
     13    assert_equals(template_element.tagName, 'TEMPLATE');
     14 
     15    t.add_cleanup(() => {
     16      while (main.firstChild)
     17        main.firstChild.remove()
     18    });
     19 
     20    main.append(template_element.content.cloneNode(true));
     21 
     22    callback_fn();
     23  }, description);
     24 }
     25 
     26 function assert_green(element) {
     27  assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 128, 0)');
     28 }
     29 function assert_red(element) {
     30  assert_equals(getComputedStyle(element).backgroundColor, 'rgb(255, 0, 0)');
     31 }
     32 function assert_not_green(element) {
     33  assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 0, 0)');
     34 }
     35 </script>
     36 <style>
     37  main * {
     38    background-color: black;
     39  }
     40 </style>
     41 <main id=main>
     42 </main>
     43 
     44 <!-- Tests follow -->
     45 
     46 <template>
     47  <style>
     48    @scope (.a) {
     49      span { background-color: green; }
     50    }
     51  </style>
     52  <div>
     53    <span></span>
     54  </div>
     55 </template>
     56 <script>
     57 test_scope_invalidation(document.currentScript, () => {
     58  let div = main.querySelector('div');
     59  let span = main.querySelector('div > span');
     60  assert_not_green(span);
     61  div.classList.add('a');
     62  assert_green(span);
     63  div.classList.remove('a');
     64  assert_not_green(span);
     65 }, 'Element becoming scope root');
     66 </script>
     67 
     68 <template>
     69  <style>
     70    @scope (.a, .b) {
     71      span { background-color: green; }
     72    }
     73  </style>
     74  <div>
     75    <span></span>
     76  </div>
     77 </template>
     78 <script>
     79 test_scope_invalidation(document.currentScript, () => {
     80  let div = main.querySelector('div');
     81  let span = main.querySelector('div > span');
     82 
     83  // .a
     84  assert_not_green(span);
     85  div.classList.add('a');
     86  assert_green(span);
     87  div.classList.remove('a');
     88  assert_not_green(span);
     89 
     90  // .b
     91  assert_not_green(span);
     92  div.classList.add('b');
     93  assert_green(span);
     94  div.classList.remove('b');
     95  assert_not_green(span);
     96 }, 'Element becoming scope root (selector list)');
     97 </script>
     98 
     99 <template>
    100  <style>
    101    @scope (.a) {
    102      :scope { background-color: green; }
    103    }
    104  </style>
    105  <div class=b></div>
    106 </template>
    107 <script>
    108 test_scope_invalidation(document.currentScript, () => {
    109  let b = main.querySelector('.b');
    110  assert_not_green(b);
    111  b.classList.add('a');
    112  assert_green(b);
    113  b.classList.remove('a');
    114  assert_not_green(b);
    115 }, 'Element becoming scope root, with inner :scope rule');
    116 </script>
    117 
    118 <template>
    119  <style>
    120    @scope (.a) to (.b) {
    121      span { background-color: green; }
    122    }
    123  </style>
    124  <div class=a>
    125    <div>
    126      <span></span>
    127    </div>
    128  </div>
    129 </template>
    130 <script>
    131 test_scope_invalidation(document.currentScript, () => {
    132  let inner_div = main.querySelector('.a > div');
    133  let span = main.querySelector('.a > div > span');
    134  assert_green(span);
    135  inner_div.classList.add('b');
    136  assert_not_green(span);
    137  inner_div.classList.remove('b');
    138  assert_green(span);
    139 }, 'Parent element becoming scope limit');
    140 </script>
    141 
    142 <template>
    143  <style>
    144    @scope (.a) to (.b, .c) {
    145      span { background-color: green; }
    146    }
    147  </style>
    148  <div class=a>
    149    <div>
    150      <span></span>
    151    </div>
    152  </div>
    153 </template>
    154 <script>
    155 test_scope_invalidation(document.currentScript, () => {
    156  let inner_div = main.querySelector('.a > div');
    157  let span = main.querySelector('.a > div > span');
    158 
    159  // .b
    160  assert_green(span);
    161  inner_div.classList.add('b');
    162  assert_not_green(span);
    163  inner_div.classList.remove('b');
    164  assert_green(span);
    165 
    166  // .c
    167  assert_green(span);
    168  inner_div.classList.add('c');
    169  assert_not_green(span);
    170  inner_div.classList.remove('c');
    171  assert_green(span);
    172 }, 'Parent element becoming scope limit (selector list)');
    173 </script>
    174 
    175 <template>
    176  <style>
    177    @scope (.a) to (.b) {
    178      span { background-color: green; }
    179    }
    180  </style>
    181  <div class=a>
    182    <div>
    183      <span></span>
    184    </div>
    185  </div>
    186 </template>
    187 <script>
    188 test_scope_invalidation(document.currentScript, () => {
    189  let span = main.querySelector('.a > div > span');
    190  assert_green(span);
    191  span.classList.add('b');
    192  assert_not_green(span);
    193  span.classList.remove('b');
    194  assert_green(span);
    195 }, 'Subject element becoming scope limit');
    196 </script>
    197 
    198 <template>
    199  <style>
    200    @scope (.a) to (.b .c) {
    201      span { background-color: green; }
    202    }
    203  </style>
    204  <div class=a>
    205    <div>
    206      <div class=c>
    207        <span></span>
    208      </div>
    209    </div>
    210  </div>
    211 </template>
    212 <script>
    213 test_scope_invalidation(document.currentScript, () => {
    214  let intermediate_div = main.querySelector('.a > div');
    215  let span = main.querySelector('span');
    216  assert_green(span);
    217  intermediate_div.classList.add('b');
    218  assert_not_green(span);
    219  intermediate_div.classList.remove('b');
    220  assert_green(span);
    221 }, 'Parent element affecting scope limit');
    222 </script>
    223 
    224 <template>
    225  <style>
    226    @scope (.a) to (.b ~ .c) {
    227      span { background-color: green; }
    228    }
    229  </style>
    230  <div class=a>
    231    <div></div>
    232    <div></div>
    233    <div></div>
    234    <div></div>
    235    <div class=c>
    236      <span></span>
    237    </div>
    238  </div>
    239 </template>
    240 <script>
    241 test_scope_invalidation(document.currentScript, () => {
    242  let sibling_div = main.querySelector('.a > div');
    243  let span = main.querySelector('span');
    244  assert_green(span);
    245  sibling_div.classList.add('b');
    246  assert_not_green(span);
    247  sibling_div.classList.remove('b');
    248  assert_green(span);
    249 }, 'Sibling element affecting scope limit');
    250 </script>
    251 
    252 <template>
    253  <style>
    254    @scope (.a) {
    255      @scope (.b) {
    256        span { background-color: green; }
    257      }
    258    }
    259  </style>
    260  <div>
    261    <div>
    262      <span></span>
    263    </div>
    264  </div>
    265 </template>
    266 <script>
    267 test_scope_invalidation(document.currentScript, () => {
    268  let outer_div = main.querySelector(':scope > div');
    269  let inner_div = main.querySelector(':scope > div > div');
    270  let span = main.querySelector('div > div > span');
    271 
    272  assert_not_green(span);
    273 
    274  outer_div.classList.add('a');
    275  assert_not_green(span);
    276 
    277  inner_div.classList.add('b');
    278  assert_green(span);
    279 
    280  // Toggle .b while .a remains.
    281  inner_div.classList.remove('b');
    282  assert_not_green(span);
    283  inner_div.classList.add('b');
    284  assert_green(span);
    285 
    286  // Toggle .a while .b remains.
    287  outer_div.classList.remove('a');
    288  assert_not_green(span);
    289  outer_div.classList.add('a');
    290  assert_green(span);
    291 }, 'Toggling inner/outer scope roots');
    292 </script>
    293 
    294 
    295 <template>
    296  <style>
    297    @scope (.a) {
    298      :scope { background-color:green; }
    299    }
    300  </style>
    301  <div></div>
    302 </template>
    303 <script>
    304 test_scope_invalidation(document.currentScript, () => {
    305  let div = main.querySelector('main > div');
    306  assert_not_green(div);
    307  div.classList.add('a');
    308  assert_green(div);
    309  div.classList.remove('a');
    310  assert_not_green(div);
    311 }, 'Element becoming root, with :scope in subject');
    312 </script>
    313 
    314 
    315 <template>
    316  <style>
    317    @scope (.a:has(.c)) {
    318      .b { background-color:green; }
    319    }
    320  </style>
    321  <div class=a>
    322    <div class=b>
    323      <div></div>
    324    </div>
    325  </div>
    326 </template>
    327 <script>
    328 test_scope_invalidation(document.currentScript, () => {
    329  let b = main.querySelector('.b');
    330  let innermost = main.querySelector('.b > div');
    331  assert_not_green(b);
    332  innermost.classList.add('c');
    333  assert_green(b);
    334  innermost.classList.remove('c');
    335  assert_not_green(b);
    336 }, 'Scope root with :has()');
    337 </script>
    338 
    339 
    340 <template>
    341  <style>
    342    @scope (.a:has(.c)) {
    343      :scope { background-color:green; }
    344    }
    345  </style>
    346  <div class=a>
    347    <div class=b>
    348      <div></div>
    349    </div>
    350  </div>
    351 </template>
    352 <script>
    353 test_scope_invalidation(document.currentScript, () => {
    354  let a = main.querySelector('.a');
    355  let innermost = main.querySelector('.b > div');
    356  assert_not_green(a);
    357  innermost.classList.add('c');
    358  assert_green(a);
    359  innermost.classList.remove('c');
    360  assert_not_green(a);
    361 }, 'Scope root with :has(), :scope subject');
    362 </script>
    363 
    364 
    365 <template>
    366  <style>
    367    @scope (.a:has(.c)) {
    368      :scope { background-color:green; }
    369      :scope .b { background-color:green; }
    370    }
    371  </style>
    372  <div class=a>
    373    <div class=b>
    374      <div></div>
    375    </div>
    376  </div>
    377 </template>
    378 <script>
    379 test_scope_invalidation(document.currentScript, () => {
    380  let a = main.querySelector('.a');
    381  let b = main.querySelector('.b');
    382  let innermost = main.querySelector('.b > div');
    383  assert_not_green(a);
    384  assert_not_green(b);
    385  innermost.classList.add('c');
    386  assert_green(a);
    387  assert_green(b);
    388  innermost.classList.remove('c');
    389  assert_not_green(a);
    390  assert_not_green(b);
    391 }, 'Scope root with :has(), :scope both subject and non-subject');
    392 </script>
    393 
    394 
    395 <template>
    396  <style>
    397    @scope (.a) to (.b:has(.c)) {
    398      .b { background-color:green; }
    399    }
    400  </style>
    401  <div class=a>
    402    <div class=b>
    403      <div></div>
    404    </div>
    405  </div>
    406 </template>
    407 <script>
    408 test_scope_invalidation(document.currentScript, () => {
    409  let b = main.querySelector('.b');
    410  let innermost = main.querySelector('.b > div');
    411  assert_green(b);
    412  innermost.classList.add('c');
    413  assert_not_green(b);
    414  innermost.classList.remove('c');
    415  assert_green(b);
    416 }, 'Scope limit with :has()');
    417 </script>
    418 
    419 <template>
    420  <style>
    421    @scope (.a) {
    422      .b ~ :scope { background-color:green; }
    423    }
    424  </style>
    425  <div></div>
    426  <div></div>
    427 </template>
    428 <script>
    429 test_scope_invalidation(document.currentScript, () => {
    430  let div1 = main.querySelector('main > div:nth-of-type(1)');
    431  let div2 = main.querySelector('main > div:nth-of-type(2)');
    432 
    433  assert_not_green(div2);
    434  div1.classList.add('b');
    435  assert_not_green(div2);
    436  div2.classList.add('a');
    437  assert_green(div2);
    438  div1.classList.remove('b');
    439  assert_not_green(div2);
    440 }, 'Element becoming root, with :scope selected by ~ combinator');
    441 </script>
    442 
    443 <template>
    444  <style>
    445    @scope (.a ~ .b) {
    446      .c { background-color:green; }
    447    }
    448  </style>
    449  <div>
    450    <div></div>
    451    <div></div>
    452    <div></div>
    453    <div class=b>
    454      <div class=c></div>
    455    </div>
    456  </div>
    457 </template>
    458 <script>
    459 test_scope_invalidation(document.currentScript, () => {
    460  let root = main.querySelector('div > div:first-child');
    461  let c = main.querySelector('.c');
    462  assert_not_green(c);
    463  root.classList.add('a');
    464  assert_green(c);
    465  root.classList.remove('a');
    466  assert_not_green(c);
    467 }, 'Element becoming root via ~ combinator');
    468 </script>
    469 
    470 <template>
    471  <style>
    472    @scope (.a + .b) {
    473      .c { background-color:green; }
    474    }
    475  </style>
    476  <div>
    477    <div></div>
    478    <div class=b>
    479      <div class=c></div>
    480    </div>
    481  </div>
    482 </template>
    483 <script>
    484 test_scope_invalidation(document.currentScript, () => {
    485  let root = main.querySelector('div > div:first-child');
    486  let c = main.querySelector('.c');
    487  assert_not_green(c);
    488  root.classList.add('a');
    489  assert_green(c);
    490  root.classList.remove('a');
    491  assert_not_green(c);
    492 }, 'Element becoming root via + combinator');
    493 </script>
    494 
    495 <template>
    496  <style>
    497    @scope (.root) {
    498      :not(:scope) { background-color:green; }
    499    }
    500  </style>
    501  <div class=root>
    502    <div class=a></div>
    503    <div class=b></div>
    504    <div class=c></div>
    505  </div>
    506  <div class=a></div>
    507 </template>
    508 <script>
    509 test_scope_invalidation(document.currentScript, () => {
    510  let root = main.querySelector('.root');
    511  let a1 = main.querySelector('.root > .a');
    512  let b = main.querySelector('.root > .b');
    513  let c = main.querySelector('.root > .c');
    514  let a2 = main.querySelector('main > .a');
    515 
    516  assert_not_green(root);
    517  assert_green(a1);
    518  assert_green(b);
    519  assert_green(c);
    520  assert_not_green(a2);
    521 
    522  root.classList.remove('root');
    523  assert_not_green(root);
    524  assert_not_green(a1);
    525  assert_not_green(b);
    526  assert_not_green(c);
    527  assert_not_green(a2);
    528 
    529  root.classList.add('root');
    530  assert_not_green(root);
    531  assert_green(a1);
    532  assert_green(b);
    533  assert_green(c);
    534  assert_not_green(a2);
    535 }, ':not(scope) in subject');
    536 </script>
    537 
    538 <template>
    539  <style>
    540    @scope (.root) {
    541      :not(:scope) > .a { background-color:green; }
    542    }
    543  </style>
    544  <div class=root>
    545    <div class=a></div>
    546    <div>
    547      <div class=a></div>
    548    </div>
    549  </div>
    550 </template>
    551 <script>
    552 test_scope_invalidation(document.currentScript, () => {
    553  let root = main.querySelector('.root');
    554  let outer_a = main.querySelector('.root > .a');
    555  let inner_a = main.querySelector('.root > div > .a');
    556 
    557  assert_not_green(outer_a);
    558  assert_green(inner_a);
    559 
    560  root.classList.remove('root');
    561  assert_not_green(outer_a);
    562  assert_not_green(inner_a);
    563 
    564  root.classList.add('root');
    565  assert_not_green(outer_a);
    566  assert_green(inner_a);
    567 }, ':not(scope) in ancestor');
    568 </script>
    569 
    570 <template>
    571  <style>
    572    @scope (.root) to (:not(:scope)) {
    573      :is(div, :scope) { background-color: green; }
    574    }
    575  </style>
    576  <div class=root>
    577    <div class=a></div>
    578  </div>
    579 </template>
    580 <script>
    581 test_scope_invalidation(document.currentScript, () => {
    582  let root = main.querySelector('.root');
    583  let a = main.querySelector('.root > .a');
    584 
    585  assert_green(root);
    586  assert_not_green(a);
    587 
    588  root.classList.remove('root');
    589  assert_not_green(root);
    590  assert_not_green(a);
    591 
    592  root.classList.add('root');
    593  assert_green(root);
    594  assert_not_green(a);
    595 }, ':not(scope) in limit subject');
    596 </script>
    597 
    598 <template>
    599  <style>
    600    @scope (.root) to (:not(:scope) > .a) {
    601      :is(div, :scope) { background-color: green; }
    602    }
    603  </style>
    604  <div class=root>
    605    <div class=a>
    606      <div class=a></div>
    607    </div>
    608  </div>
    609 </template>
    610 <script>
    611 test_scope_invalidation(document.currentScript, () => {
    612  let root = main.querySelector('.root');
    613  let outer_a = main.querySelector('.root > .a');
    614  let inner_a = main.querySelector('.root > .a > .a');
    615 
    616  assert_green(root);
    617  assert_green(outer_a);
    618  assert_not_green(inner_a);
    619 
    620  root.classList.remove('root');
    621  assert_not_green(root);
    622  assert_not_green(outer_a);
    623  assert_not_green(inner_a);
    624 
    625  root.classList.add('root');
    626  assert_green(root);
    627  assert_green(outer_a);
    628  assert_not_green(inner_a);
    629 }, ':not(scope) in limit ancestor');
    630 </script>
    631 
    632 <template>
    633  <style>
    634    @scope (:nth-child(2n of .a)) {
    635      :scope { background-color: green; }
    636    }
    637  </style>
    638  <div id=wrapper>
    639    <div class=a></div>
    640    <div></div>
    641    <div class=a></div>
    642    <div></div>
    643    <div class=a></div>
    644    <div></div>
    645    <div class=a></div>
    646    <div></div>
    647  </div>
    648 </template>
    649 <script>
    650 test_scope_invalidation(document.currentScript, () => {
    651  let e = main.querySelectorAll('#wrapper > div');
    652  assert_equals(e.length, 8);
    653 
    654  // <div class=a></div>
    655  // <div></div>
    656  // <div class=a></div>
    657  // <div></div>
    658  // <div class=a></div>
    659  // <div></div>
    660  // <div class=a></div>
    661  // <div></div>
    662  assert_not_green(e[0]);
    663  assert_not_green(e[1]);
    664  assert_green(e[2]);
    665  assert_not_green(e[3]);
    666  assert_not_green(e[4]);
    667  assert_not_green(e[5]);
    668  assert_green(e[6]);
    669  assert_not_green(e[7]);
    670 
    671  e[1].classList.add('a');
    672  // <div class=a></div>
    673  // <div class=a></div>
    674  // <div class=a></div>
    675  // <div></div>
    676  // <div class=a></div>
    677  // <div></div>
    678  // <div class=a></div>
    679  // <div></div>
    680  assert_not_green(e[0]);
    681  assert_green(e[1]);
    682  assert_not_green(e[2]);
    683  assert_not_green(e[3]);
    684  assert_green(e[4]);
    685  assert_not_green(e[5]);
    686  assert_not_green(e[6]);
    687  assert_not_green(e[7]);
    688 
    689  e[1].classList.remove('a');
    690  // <div class=a></div>
    691  // <div></div>
    692  // <div class=a></div>
    693  // <div></div>
    694  // <div class=a></div>
    695  // <div></div>
    696  // <div class=a></div>
    697  // <div></div>
    698  assert_not_green(e[0]);
    699  assert_not_green(e[1]);
    700  assert_green(e[2]);
    701  assert_not_green(e[3]);
    702  assert_not_green(e[4]);
    703  assert_not_green(e[5]);
    704  assert_green(e[6]);
    705  assert_not_green(e[7]);
    706 }, ':nth-child() in scope root');
    707 </script>
    708 
    709 <template>
    710  <style>
    711    @scope (#wrapper) to (:nth-child(4n of .a)) {
    712      div { background-color: green; }
    713    }
    714  </style>
    715  <div id=wrapper>
    716    <div class=a></div>
    717    <div></div>
    718    <div class=a></div>
    719    <div></div>
    720    <div class=a></div>
    721    <div></div>
    722    <div class=a></div>
    723    <div></div>
    724  </div>
    725 </template>
    726 <script>
    727 test_scope_invalidation(document.currentScript, () => {
    728  let e = main.querySelectorAll('#wrapper > div');
    729  assert_equals(e.length, 8);
    730 
    731  // <div class=a></div>
    732  // <div></div>
    733  // <div class=a></div>
    734  // <div></div>
    735  // <div class=a></div>
    736  // <div></div>
    737  // <div class=a></div>  <= limit
    738  // <div></div>
    739  assert_green(e[0]);
    740  assert_green(e[1]);
    741  assert_green(e[2]);
    742  assert_green(e[3]);
    743  assert_green(e[4]);
    744  assert_green(e[5]);
    745  assert_not_green(e[6]);
    746  assert_green(e[7]);
    747 
    748  e[1].classList.add('a');
    749  // <div class=a></div>
    750  // <div class=a></div>
    751  // <div class=a></div>
    752  // <div></div>
    753  // <div class=a></div>  <= limit
    754  // <div></div>
    755  // <div class=a></div>
    756  // <div></div>
    757  assert_green(e[0]);
    758  assert_green(e[1]);
    759  assert_green(e[2]);
    760  assert_green(e[3]);
    761  assert_not_green(e[4]);
    762  assert_green(e[5]);
    763  assert_green(e[6]);
    764  assert_green(e[7]);
    765 
    766  e[1].classList.remove('a');
    767  // <div class=a></div>
    768  // <div></div>
    769  // <div class=a></div>
    770  // <div></div>
    771  // <div class=a></div>
    772  // <div></div>
    773  // <div class=a></div>  <= limit
    774  // <div></div>
    775  assert_green(e[0]);
    776  assert_green(e[1]);
    777  assert_green(e[2]);
    778  assert_green(e[3]);
    779  assert_green(e[4]);
    780  assert_green(e[5]);
    781  assert_not_green(e[6]);
    782  assert_green(e[7]);
    783 }, ':nth-child() in scope limit');
    784 
    785 </script>
    786 
    787 <template>
    788  <style>
    789    @scope (.a) {
    790      .nomatch { background-color: green; }
    791    }
    792  </style>
    793  <div id=wrapper>
    794    <div class=a>
    795      <div class=b></div>
    796    </div>
    797  </div>
    798 </template>
    799 <script>
    800 test_scope_invalidation(document.currentScript, () => {
    801  let b = main.querySelector('.b');
    802  assert_not_green(b);
    803  let scope_rule = main.querySelector('style').sheet.cssRules[0];
    804  assert_true(scope_rule instanceof CSSScopeRule);
    805  scope_rule.cssRules[0].selectorText = '.b';
    806  assert_green(b);
    807 }, 'Modifying selectorText invalidates affected elements');
    808 </script>
    809 
    810 <template>
    811  <style>
    812    @scope (.a) {
    813      .nomatch { background-color: green; }
    814    }
    815  </style>
    816  <div id=wrapper>
    817    <div class=a>
    818      <div class=b></div>
    819    </div>
    820  </div>
    821 </template>
    822 <script>
    823 test_scope_invalidation(document.currentScript, () => {
    824  let b = main.querySelector('.b');
    825  assert_not_green(b);
    826  let scope_rule = main.querySelector('style').sheet.cssRules[0];
    827  assert_true(scope_rule instanceof CSSScopeRule);
    828  scope_rule.cssRules[0].selectorText = '> .b';
    829  assert_green(b);
    830 }, 'Modifying selectorText invalidates affected elements (>)');
    831 </script>
    832 
    833 <template>
    834  <style>
    835    .a {
    836      > .b, > .c {
    837        background-color: green; /* Specificity: (0, 2, 0) */
    838      }
    839    }
    840    @scope (.a.a) {
    841      .nomatch1 {
    842        background-color: red; /* Specificity: (0, 1, 0) */
    843      }
    844      .nomatch2 {
    845        background-color: red; /* Specificity: (0, 1, 0) */
    846      }
    847    }
    848  </style>
    849  <div id=wrapper>
    850    <div class=a>
    851      <div class=b></div>
    852      <div class=c></div>
    853    </div>
    854  </div>
    855 </template>
    856 <script>
    857 test_scope_invalidation(document.currentScript, () => {
    858  let b = main.querySelector('.b');
    859  let c = main.querySelector('.c');
    860  assert_green(b);
    861  assert_green(c);
    862  let scope_rule = main.querySelector('style').sheet.cssRules[1];
    863  assert_true(scope_rule instanceof CSSScopeRule);
    864  scope_rule.cssRules[0].selectorText = '> .b'; /* Still (0, 1, 0) */
    865  scope_rule.cssRules[1].selectorText = '& > .c'; /* Still (0, 1, 0) */
    866  assert_green(b);
    867  assert_green(c);
    868 }, 'Relative selectors set with selectorText are relative to :scope and &');
    869 </script>
    870 
    871 <template>
    872  <style>
    873    @scope (.a .b) {
    874      @scope(.c .d, .e .f) {
    875        .g {
    876          background-color: green;
    877        }
    878      }
    879    }
    880  </style>
    881  <div class=a>
    882    <div class=b>
    883      <div class=e>
    884        <div class=f>
    885          <div class=g>
    886          </div>
    887        </div>
    888      </div>
    889    </div>
    890  </div>
    891 </template>
    892 <script>
    893 test_scope_invalidation(document.currentScript, () => {
    894  let a = main.querySelector('.a');
    895  let g = main.querySelector('.g');
    896  assert_green(g);
    897  a.classList.remove('a');
    898  assert_not_green(g);
    899  a.classList.add('a');
    900  assert_green(g);
    901 }, 'Ancestor element affecting nested scope root (Through latter selector in list)')
    902 </script>
    903 
    904 <template>
    905  <style>
    906    @scope (.a) to (.b .c) {
    907      :scope .d .f{
    908        background-color: green;
    909      }
    910    }
    911    </style>
    912 
    913  <div class=a>
    914    <div class=b>
    915      <div class=d>
    916        <div class=c>
    917          <div class=f>
    918          </div>
    919        </div>
    920      </div>
    921    </div>
    922  </div>
    923 </template>
    924 <script>
    925  test_scope_invalidation(document.currentScript, () => {
    926  let b = main.querySelector('.b');
    927  let f = main.querySelector('.f');
    928  assert_not_green(f);
    929  b.classList.remove('b');
    930  assert_green(f);
    931  b.classList.add('b');
    932  assert_not_green(f);
    933 }, 'Parent element of subject affecting scope limit')
    934 </script>
    935 
    936 <template>
    937  <div class=a>
    938    <div><div><div><div>
    939      <style>
    940        @scope(.a) {
    941          @scope {
    942            @scope(> .b) {
    943              :scope { background: green; }
    944            }
    945          }
    946        }
    947      </style>
    948      <div class=b></div>
    949    </div></div></div></div>
    950  </div>
    951 </template>
    952 <script>
    953 test_scope_invalidation(document.currentScript, () => {
    954  let a = main.querySelector('.a');
    955  let b = main.querySelector('.b');
    956  assert_green(b);
    957  a.classList.remove('a');
    958  assert_not_green(b);
    959  a.classList.add('a');
    960  assert_green(b);
    961 }, 'Sandwiched deep implicit scope root, :scope in subject')
    962 </script>