tor-browser

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

CSSStyleSheet-constructable.html (37727B)


      1 <!DOCTYPE html>
      2 <title>CSSStyleSheet constructor and adoptedStyleSheets</title>
      3 <link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
      4 <link rel="help" href="https://wicg.github.io/construct-stylesheets/">
      5 <script src = '/resources/testharness.js'></script>
      6 <script src = '/resources/testharnessreport.js'></script>
      7 
      8 <section id="firstSection">
      9  <div>
     10    <span class="green"></span>
     11    <span class="red"></span>
     12    <span class="blue"></span>
     13    <span class="white"></span>
     14    <span class="yellow"></span>
     15  </div>
     16 </section>
     17 <section id="shadowHost"></section>
     18 <section id="thirdSection"></section>
     19 
     20 <script>
     21 'use strict';
     22 const greenStyleText = ".green { color: green; }";
     23 const redStyleTexts = [".red { color: red; }", ".red + span + span { color: red; }"];
     24 const blueStyleTexts = [".blue { color: blue; }", ".blue + span + span { color: blue; }"];
     25 const whiteStyleText = "* { color: white; }";
     26 const yellowStyleText = ".yellow { color: yellow; }";
     27 
     28 const firstDiv = document.querySelector('#firstSection > div');
     29 const secondDiv = firstDiv.cloneNode(true);
     30 const shadowHost = document.querySelector('#shadowHost');
     31 const shadowRoot = shadowHost.attachShadow({mode: 'open'});
     32 shadowRoot.appendChild(secondDiv);
     33 
     34 const greenSpan = firstDiv.children[0];
     35 const redSpan = firstDiv.children[1];
     36 const blueSpan = firstDiv.children[2];
     37 const whiteSpan = firstDiv.children[3];
     38 const yellowSpan = firstDiv.children[4];
     39 const greenShadowSpan = secondDiv.children[0];
     40 const redShadowSpan = secondDiv.children[1];
     41 const blueShadowSpan = secondDiv.children[2];
     42 const whiteShadowSpan = secondDiv.children[3];
     43 const yellowShadowSpan = secondDiv.children[4];
     44 
     45 test(() => {
     46  assert_equals(document.adoptedStyleSheets.length, 0);
     47 }, "document.adoptedStyleSheets should initially have length 0.");
     48 
     49 test(() => {
     50  const sheet = new CSSStyleSheet({disabled: true, media: "screen, print"});
     51  assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
     52  assert_equals(sheet.ownerNode, null);
     53  assert_equals(sheet.ownerRule, null);
     54  assert_equals(sheet.media.length, 2);
     55  assert_equals(sheet.media.item(0), "screen");
     56  assert_equals(sheet.media.item(1), "print");
     57  assert_true(sheet.disabled);
     58  assert_equals(sheet.cssRules.length, 0);
     59 
     60  sheet.insertRule(redStyleTexts[0]);
     61  assert_equals(sheet.cssRules.length, 1);
     62  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
     63 
     64  sheet.insertRule(redStyleTexts[1]);
     65  assert_equals(sheet.cssRules.length, 2);
     66  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
     67 
     68  const sheet2 = new CSSStyleSheet({});
     69  assert_equals(sheet2.title, null, "The title attribute must return the title or null if title is the empty string");
     70  assert_equals(sheet2.ownerNode, null);
     71  assert_equals(sheet2.ownerRule, null);
     72  assert_equals(sheet2.media.length, 0);
     73  assert_false(sheet2.disabled);
     74  assert_equals(sheet2.cssRules.length, 0);
     75 
     76  sheet2.insertRule(redStyleTexts[1]);
     77  assert_equals(sheet2.cssRules.length, 1);
     78  assert_equals(sheet2.cssRules[0].cssText, redStyleTexts[1]);
     79 
     80  sheet2.deleteRule(0);
     81  assert_equals(sheet2.cssRules.length, 0);
     82 
     83  const sheet3 = new CSSStyleSheet();
     84  assert_equals(sheet3.title, null, "The title attribute must return the title or null if title is the empty string");
     85  assert_equals(sheet3.ownerNode, null);
     86  assert_equals(sheet3.ownerRule, null);
     87  assert_equals(sheet3.media.length, 0);
     88  assert_false(sheet3.disabled);
     89  assert_equals(sheet3.cssRules.length, 0);
     90 
     91  sheet3.insertRule(redStyleTexts[1]);
     92  assert_equals(sheet3.cssRules.length, 1);
     93  assert_equals(sheet3.cssRules[0].cssText, redStyleTexts[1]);
     94 
     95  sheet3.deleteRule(0);
     96  assert_equals(sheet3.cssRules.length, 0);
     97 }, 'new CSSStyleSheet produces empty CSSStyleSheet');
     98 
     99 test(() => {
    100  const sheet = new CSSStyleSheet({title: "something"});
    101  assert_equals(sheet.title, null, "title and alternate are not supported by the constructor. https://github.com/WICG/construct-stylesheets/issues/105");
    102 }, "title can be set in the CSSStyleSheet constructor");
    103 
    104 promise_test(() => {
    105  const sheet = new CSSStyleSheet({disabled: true, media: "screen, print"});
    106  const promise_sheet = sheet.replace(redStyleTexts[0]);
    107  return promise_sheet.then(function(sheet) {
    108    assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
    109    assert_equals(sheet.ownerNode, null);
    110    assert_equals(sheet.ownerRule, null);
    111    assert_equals(sheet.media.length, 2);
    112    assert_equals(sheet.media.item(0), "screen");
    113    assert_equals(sheet.media.item(1), "print");
    114    assert_true(sheet.disabled);
    115    assert_equals(sheet.cssRules.length, 1);
    116    assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
    117 
    118    sheet.insertRule(redStyleTexts[1]);
    119    assert_equals(sheet.cssRules.length, 2);
    120    assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
    121  });
    122 }, 'CSSStyleSheet.replace produces Promise<CSSStyleSheet>');
    123 
    124 function createAllSheetsPromise() {
    125  const greenSheet = new CSSStyleSheet();
    126  const redSheet = new CSSStyleSheet({media: "screen, print"});
    127  const blueSheet = new CSSStyleSheet({disabled: true});
    128  const whiteSheet = new CSSStyleSheet({disabled: true});
    129  const yellowSheet = new CSSStyleSheet({disabled: false});
    130 
    131  const greenPromise = greenSheet.replace(greenStyleText);
    132  const redPromise = redSheet.replace(redStyleTexts[0] + redStyleTexts[1]);
    133  const bluePromise = blueSheet.replace(blueStyleTexts[0] + blueStyleTexts[1]);
    134  const whitePromise = whiteSheet.replace(whiteStyleText);
    135  const yellowPromise = yellowSheet.replace(yellowStyleText);
    136  return [greenPromise, redPromise, bluePromise, whitePromise, yellowPromise];
    137 }
    138 
    139 promise_test(() => {
    140  return Promise.all(createAllSheetsPromise()).then(values => {
    141    const greenStyleSheet = values[0];
    142    const redStyleSheet = values[1];
    143    const blueStyleSheet = values[2];
    144    const whiteStyleSheet = values[3];
    145    const yellowStyleSheet = values[4];
    146 
    147    // Lists of style sheets can be created, assigned and read.
    148 
    149    // disabled stylesheets aren't applied
    150    document.adoptedStyleSheets = [whiteStyleSheet];
    151    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    152    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    153    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    154    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    155    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    156 
    157    // disable dsheets don't block other styles from applying
    158    document.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
    159    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
    160    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    161    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    162    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    163    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    164 
    165    document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];
    166 
    167    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    168    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    169    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    170    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    171    assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");
    172 
    173    document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
    174    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
    175    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    176    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    177    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    178    assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");
    179    document.adoptedStyleSheets = [];
    180  });
    181 }, 'Constructed style sheets can be applied on document');
    182 
    183 promise_test(() => {
    184  return Promise.all(createAllSheetsPromise()).then(values => {
    185    const greenStyleSheet = values[0];
    186    const redStyleSheet = values[1];
    187    const blueStyleSheet = values[2];
    188    const whiteStyleSheet = values[3];
    189    const yellowStyleSheet = values[4];
    190    shadowRoot.adoptedStyleSheets = [whiteStyleSheet];
    191    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    192    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
    193    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    194    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    195    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
    196 
    197    shadowRoot.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
    198    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
    199    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
    200    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    201    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    202    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
    203 
    204    shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];
    205    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    206    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    207    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    208    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    209    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");
    210 
    211    shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
    212    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
    213    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    214    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    215    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    216    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");
    217  });
    218 }, 'Constructed style sheets can be applied on shadow root');
    219 
    220 promise_test(() => {
    221  return Promise.all(createAllSheetsPromise()).then(values => {
    222    const greenStyleSheet = values[0];
    223    const redStyleSheet = values[1];
    224    shadowRoot.adoptedStyleSheets = [greenStyleSheet];
    225    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies connected");
    226    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)", "Style applies when connected");
    227    let hostParent = shadowHost.parentNode;
    228    hostParent.removeChild(shadowHost);
    229    assert_equals(getComputedStyle(greenShadowSpan).color, "", "Style doesn't apply when detached");
    230    assert_equals(getComputedStyle(redShadowSpan).color, "", "Style doesn't apply when detached");
    231    shadowRoot.adoptedStyleSheets = [redStyleSheet, greenStyleSheet];
    232    hostParent.appendChild(shadowHost);
    233    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies after reattach");
    234    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)", "Style applies after reattach");
    235  });
    236 }, 'Re-attaching shadow host with adopted stylesheets work');
    237 
    238 test(() => {
    239  const sheet = new CSSStyleSheet();
    240  sheet.replaceSync(":host { color: red; }");
    241  const host = document.createElement("div");
    242  let sr = host.attachShadow({mode: "open"});
    243  sr.adoptedStyleSheets = [sheet];
    244  document.body.appendChild(host);
    245  assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies when connected");
    246  sheet.replaceSync(":host { color: blue; }");
    247  assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Style update applies when connected");
    248 }, 'Attaching a shadow root that already has adopted stylesheets work');
    249 
    250 test(() => {
    251  const sheet = new CSSStyleSheet();
    252  sheet.replaceSync(":host([red]) { color: red; } :host(.blue) { color: blue; }");
    253  const host = document.createElement("div");
    254  host.toggleAttribute("red");
    255  document.body.appendChild(host);
    256  assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "No style applies yet");
    257 
    258  let sr = host.attachShadow({mode: "open"});
    259  sr.adoptedStyleSheets = [sheet];
    260 
    261  assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after adding style");
    262  document.body.removeChild(host);
    263  document.body.appendChild(host);
    264  assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after reattachment");
    265  host.toggleAttribute("red");
    266  assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "Attribute updates to the element after reattachment apply");
    267  host.classList.toggle("blue");
    268  assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Class updates to the element after reattachment apply");
    269 
    270 }, "Re-attaching shadow host and updating attributes work");
    271 
    272 promise_test(() => {
    273  const plainSheet = new CSSStyleSheet();
    274  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
    275  return redStyleSheetPromise.then(function(redStyleSheet) {
    276    document.adoptedStyleSheets = [redStyleSheet];
    277    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    278    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    279    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    280    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    281    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    282 
    283    redStyleSheet.insertRule(redStyleTexts[1]);
    284    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    285    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    286    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    287    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    288    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    289 
    290    redStyleSheet.deleteRule(1);
    291    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    292    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    293    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    294    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    295    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    296 
    297    redStyleSheet.cssRules[0].style.color = "white";
    298    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    299    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    300    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    301    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 255, 255)");
    302    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    303 });
    304 }, 'Changes to constructed stylesheets through CSSOM is reflected');
    305 
    306 promise_test(() => {
    307  const plainSheet = new CSSStyleSheet();
    308  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
    309  return redStyleSheetPromise.then(function(redStyleSheet) {
    310    document.adoptedStyleSheets = [redStyleSheet];
    311    shadowRoot.adoptedStyleSheets = [redStyleSheet];
    312    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    313    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    314    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    315    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    316    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    317 
    318    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    319    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    320    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    321    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    322    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
    323 
    324    shadowRoot.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    325    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    326    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    327    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    328    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    329    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    330 
    331    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    332    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    333    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    334    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    335    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
    336    document.adoptedStyleSheets = [];
    337  });
    338 }, 'Constructed stylesheet can be used and modified in multiple TreeScopes');
    339 
    340 promise_test(() => {
    341  const iframe = document.createElement("iframe");
    342  document.body.appendChild(iframe);
    343  const thirdDiv = firstDiv.cloneNode(true);
    344  iframe.contentDocument.body.appendChild(thirdDiv);
    345  const greenIframeSpan = thirdDiv.children[0];
    346  const redIframeSpan = thirdDiv.children[1];
    347  const blueIframeSpan = thirdDiv.children[2];
    348  const whiteIframeSpan = thirdDiv.children[3];
    349  const yellowIframeSpan = thirdDiv.children[4];
    350 
    351  const plainSheet = new CSSStyleSheet();
    352  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
    353  return redStyleSheetPromise.then(function(redStyleSheet) {
    354    assert_throws_dom(
    355      'NotAllowedError',
    356      iframe.contentWindow.DOMException,
    357      () => { iframe.contentDocument.adoptedStyleSheets = [redStyleSheet]; }
    358    );
    359    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    360    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
    361    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    362    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
    363    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
    364 
    365    document.adoptedStyleSheets = [redStyleSheet];
    366    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    367    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    368    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    369    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    370    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    371 
    372    document.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    373    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    374    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    375    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    376    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    377    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    378  });
    379 }, 'Stylesheets constructed on the main Document cannot be used in iframes');
    380 
    381 promise_test(async () => {
    382  const iframe = document.createElement("iframe");
    383  const iframeLoaded = new Promise(resolve => iframe.addEventListener("load", resolve));
    384  document.body.appendChild(iframe);
    385  await iframeLoaded;
    386  const thirdDiv = firstDiv.cloneNode(true);
    387  iframe.contentDocument.body.appendChild(thirdDiv);
    388  const greenIframeSpan = thirdDiv.children[0];
    389  const redIframeSpan = thirdDiv.children[1];
    390  const blueIframeSpan = thirdDiv.children[2];
    391  const whiteIframeSpan = thirdDiv.children[3];
    392  const yellowIframeSpan = thirdDiv.children[4];
    393 
    394  // Make sure both the main Document and the iframe are not styled
    395  const emptyStyleSheet = new CSSStyleSheet();
    396  document.adoptedStyleSheets = [emptyStyleSheet];
    397  assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    398  assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    399  assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    400  assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    401  assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    402 
    403  assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    404  assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
    405  assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    406  assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
    407  assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
    408 
    409  const iframePlainSheet = new iframe.contentWindow.CSSStyleSheet();
    410  const iframeRedStyleSheetPromise = iframePlainSheet.replace(redStyleTexts[0]);
    411  return iframeRedStyleSheetPromise.then(function(iframeRedStyleSheet) {
    412    assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [iframeRedStyleSheet]; });
    413    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    414    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    415    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    416    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    417    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
    418 
    419    iframe.contentDocument.adoptedStyleSheets = [iframeRedStyleSheet];
    420    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    421    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
    422    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    423    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
    424    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
    425 
    426    iframe.contentDocument.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    427    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    428    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
    429    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    430    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(255, 0, 0)");
    431    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
    432  });
    433 }, 'Stylesheet constructed on iframe cannot be used in the main Document');
    434 </script>
    435 
    436 <div id="divNonConstructed" class="nonConstructed">
    437 </div>
    438 
    439 <script>
    440 `use strict`;
    441 const shadowRootNonConstructed = divNonConstructed.attachShadow({mode:'open'})
    442 nonConstructedStyle = document.createElement("style");
    443 shadowRootNonConstructed.appendChild(nonConstructedStyle);
    444 nonConstructedStyle.sheet.insertRule(".nonConstructed { color: red; }", 0);
    445 const nonConstructedStyleSheet = nonConstructedStyle.sheet;
    446 
    447 test(() => {
    448  assert_equals(getComputedStyle(divNonConstructed).color, "rgb(0, 0, 0)");
    449  assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [nonConstructedStyleSheet]; });
    450 }, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet is in the same document tree as the AdoptedStyleSheets');
    451 
    452 test(() => {
    453  const iframe = document.createElement("iframe");
    454  document.body.appendChild(iframe);
    455  iframeDiv = iframe.contentDocument.createElement("div");
    456  iframeDiv.classList.add("nonConstructed");
    457  iframe.contentDocument.body.appendChild(iframeDiv);
    458 
    459  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
    460  assert_throws_dom('NotAllowedError', iframe.contentWindow.DOMException, () => {
    461    iframe.contentDocument.adoptedStyleSheets = [nonConstructedStyleSheet];
    462  });
    463  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
    464 
    465  iframeStyle = iframe.contentDocument.createElement("style");
    466  iframe.contentDocument.body.appendChild(iframeStyle);
    467  iframeStyle.sheet.insertRule(".nonConstructedSpan { color: red; }");
    468  const iframeStyleSheet = iframeStyle.sheet;
    469  nonConstructedSpan = document.createElement("span");
    470  nonConstructedSpan.classList.add(".nonConstructedSpan");
    471  divNonConstructed.appendChild(nonConstructedSpan);
    472 
    473  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
    474  assert_throws_dom('NotAllowedError', () => { document.adoptedStyleSheets = [iframeStyleSheet]; });
    475  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
    476 }, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees');
    477 
    478 function attachShadowDiv(host) {
    479  const shadowRoot = host.attachShadow({mode: 'open'});
    480  const shadowDiv = document.createElement("div");
    481  shadowRoot.appendChild(shadowDiv);
    482  return shadowDiv;
    483 }
    484 
    485 test(() => {
    486  const sheet = new CSSStyleSheet();
    487  assert_equals(sheet.cssRules.length, 0);
    488 
    489  sheet.replaceSync(redStyleTexts[0])
    490  assert_equals(sheet.cssRules.length, 1);
    491  assert_equals(redStyleTexts[0], sheet.cssRules[0].cssText);
    492 
    493  sheet.replaceSync(redStyleTexts[1]);
    494  assert_equals(sheet.cssRules.length, 1);
    495  assert_equals(redStyleTexts[1], sheet.cssRules[0].cssText);
    496 }, 'CSSStyleSheet.replaceSync replaces stylesheet text synchronously');
    497 
    498 test(() => {
    499  // Attach a div inside a shadow root with the class ".red".
    500  const span = document.createElement("span");
    501  thirdSection.appendChild(span);
    502  const shadowDiv = attachShadowDiv(span);
    503  shadowDiv.classList.add("red");
    504  // Create empty stylesheet.
    505  const sheet = new CSSStyleSheet();
    506  span.shadowRoot.adoptedStyleSheets = [sheet];
    507  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    508  // Replace the stylesheet text that will color it red.
    509  sheet.replaceSync(redStyleTexts[0]);
    510  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
    511  assert_equals(sheet.cssRules.length, 1);
    512  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
    513  sheet.insertRule(redStyleTexts[1]);
    514  assert_equals(sheet.cssRules.length, 2);
    515  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
    516 }, 'CSSStyleSheet.replaceSync correctly updates the style of its adopters synchronously');
    517 
    518 test(() => {
    519  // Attach a div inside a shadow root with the class ".red".
    520  const span = document.createElement("span");
    521  thirdSection.appendChild(span);
    522  const shadowDiv = attachShadowDiv(span);
    523  shadowDiv.classList.add("target");
    524 
    525  // Create empty stylesheet.
    526  const sheet = new CSSStyleSheet();
    527  span.shadowRoot.adoptedStyleSheets = [sheet];
    528  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    529 
    530  // Replace the stylesheet text that will color it red.
    531  sheet.replaceSync(".target { color: red; }");
    532  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
    533 
    534  // Create a style element that will set colors to white.
    535  const style = document.createElement("style");
    536  style.textContent = ".target { color: white; }";
    537  span.shadowRoot.appendChild(style)
    538  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
    539 
    540  span.shadowRoot.adoptedStyleSheets = [];
    541  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
    542 
    543  span.shadowRoot.adoptedStyleSheets = [sheet];
    544  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
    545 
    546  sheet.disabled = true;
    547  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
    548 
    549  sheet.disabled = false;
    550  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again");
    551 }, 'Adopted sheets are ordered after non-adopted sheets in the shadow root')
    552 
    553 test(() => {
    554  // Attach a div inside a shadow root with the class ".red".
    555  const span = document.createElement("span");
    556  thirdSection.appendChild(span);
    557  span.classList.add("target");
    558 
    559  // Create empty stylesheet.
    560  const sheet = new CSSStyleSheet();
    561  document.adoptedStyleSheets = [sheet];
    562  assert_equals(getComputedStyle(span).color, "rgb(0, 0, 0)");
    563 
    564  // Replace the stylesheet text that will color it red.
    565  sheet.replaceSync(".target { color: red; }");
    566  assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)");
    567 
    568  // Create a style element that will set colors to white.
    569  const style = document.createElement("style");
    570  style.textContent = ".target { color: white; }";
    571  span.appendChild(style)
    572  assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
    573 
    574  document.adoptedStyleSheets = [];
    575  assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
    576 
    577  document.adoptedStyleSheets = [sheet];
    578  assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
    579 
    580  sheet.disabled = true;
    581  assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
    582 
    583  sheet.disabled = false;
    584  assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again")
    585 }, 'Adopted sheets are ordered after non-adopted sheets in the document')
    586 
    587 const import_text = '@import url("support/constructable-import.css");';
    588 
    589 test(() => {
    590  assert_throws_dom("SyntaxError", () => { (new CSSStyleSheet).insertRule(import_text) });
    591 }, 'Inserting an @import rule through insertRule on a constructed stylesheet throws an exception');
    592 
    593 promise_test(t => {
    594    const importUrl = "support/constructable-import.css";
    595    const sheet = new CSSStyleSheet();
    596 
    597    sheet.replaceSync(`@import url("${importUrl}");`);
    598 
    599    const timeAfterReplaceSync = performance.now();
    600    let link = document.createElement("link");
    601    link.rel = "stylesheet";
    602    link.href = importUrl;
    603 
    604    return new Promise(resolve => {
    605      link.addEventListener("error", t.unreached_func("Load shouldn't fail"));
    606      link.addEventListener("load", t.step_func(() => {
    607        let entries = window.performance.getEntriesByType('resource').filter(entry => entry.name.includes(importUrl));
    608        assert_equals(entries.length, 1, "There should be only one entry for the import URL");
    609        assert_greater_than_equal(entries[0].startTime, timeAfterReplaceSync, "The entry's start time should be after replaceSync threw");
    610        link.remove();
    611        resolve();
    612      }));
    613      document.body.appendChild(link);
    614    });
    615 }, "CSSStyleSheet.replaceSync should not trigger any loads from @import rules")
    616 
    617 promise_test(() => {
    618  const span = document.createElement("span");
    619  thirdSection.appendChild(span);
    620  const shadowDiv = attachShadowDiv(span);
    621  const sheet = new CSSStyleSheet();
    622  span.shadowRoot.adoptedStyleSheets = [sheet];
    623  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    624  // Replace and assert that the imported rule is NOT applied.
    625  const sheet_promise = sheet.replace(import_text);
    626  return sheet_promise.then((sheet) => {
    627    // replace() ignores @import rules:
    628    assert_equals(sheet.cssRules.length, 0);
    629    assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    630  }).catch((reason) => {
    631    assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
    632  });
    633 }, 'CSSStyleSheet.replace allows, but ignores, import rule inside');
    634 
    635 promise_test(() => {
    636  const span = document.createElement("span");
    637  thirdSection.appendChild(span);
    638  const shadowDiv = attachShadowDiv(span);
    639  const targetSpan = document.createElement("span");
    640  targetSpan.classList.add("target");
    641  shadowDiv.appendChild(targetSpan);
    642  const sheet = new CSSStyleSheet();
    643  span.shadowRoot.adoptedStyleSheets = [sheet];
    644  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    645  // Replace and assert that the imported rule is NOT applied, but regular rule does apply.
    646  const sheet_promise = sheet.replace(import_text + ".target { color: blue; }");
    647  return sheet_promise.then((sheet) => {
    648    assert_equals(sheet.cssRules.length, 1);
    649    // @import not applied:
    650    assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    651    // regular rule applied:
    652    assert_equals(getComputedStyle(targetSpan).color, "rgb(0, 0, 255)");
    653  }).catch((reason) => {
    654    assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
    655  });
    656 }, 'CSSStyleSheet.replace ignores @import rule but still loads other rules');
    657 
    658 test(() => {
    659  const span = document.createElement("span");
    660  thirdSection.appendChild(span);
    661  const shadowDiv = attachShadowDiv(span);
    662  const sheet = new CSSStyleSheet();
    663  span.shadowRoot.adoptedStyleSheets = [sheet];
    664  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    665  // Replace and assert that the imported rule is NOT applied.
    666  try {
    667    sheet.replaceSync(import_text);
    668    // replaceSync() ignores @import rules:
    669    assert_equals(sheet.cssRules.length, 0);
    670    assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    671  } catch(reason) {
    672    assert_unreached(`replaceSync threw an exception (${reason}) when it shouldn't have`);
    673  }
    674 }, 'CSSStyleSheet.replaceSync allows, but ignores, import rule inside');
    675 
    676 promise_test(() => {
    677  const sheet = new CSSStyleSheet();
    678  const sheet_promise = sheet.replace("@import url('not-there.css');");
    679 
    680  return sheet_promise.then((sheet) => {
    681    // No exception here
    682  }).catch((reason) => {
    683    assert_unreached("Promise was rejected");
    684  });
    685 }, 'CSSStyleSheet.replace does not reject on failed imports');
    686 
    687 test(() => {
    688  const span = document.createElement("span");
    689  thirdSection.appendChild(span);
    690  const shadowDiv = attachShadowDiv(span);
    691  const sheet = new CSSStyleSheet();
    692  span.shadowRoot.adoptedStyleSheets = [sheet];
    693 
    694  const newSpan = span.cloneNode(true);
    695  assert_equals(newSpan.shadowRoot, null);
    696 }, 'Cloning a shadow host will not clone shadow root, and also adoptedStyleSheets');
    697 
    698 test(() => {
    699  const span = document.createElement("span");
    700  thirdSection.appendChild(span);
    701  const shadowDiv = attachShadowDiv(span);
    702  const sheet = new CSSStyleSheet();
    703  span.shadowRoot.adoptedStyleSheets = [sheet];
    704 
    705  const iframe = document.createElement("iframe");
    706  document.body.appendChild(iframe);
    707  const newSpan = iframe.contentDocument.importNode(span, true);
    708  iframe.contentDocument.body.appendChild(newSpan);
    709  assert_equals(newSpan.shadowRoot, null);
    710 }, 'Importing a shadow host will not copy shadow root, and also adoptedStyleSheets');
    711 
    712 test(() => {
    713  const span = document.createElement("span");
    714  thirdSection.appendChild(span);
    715  const shadowDiv = attachShadowDiv(span);
    716  const sheet = new CSSStyleSheet();
    717  sheet.replaceSync("* { color: red; }");
    718  span.shadowRoot.adoptedStyleSheets = [sheet];
    719  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
    720 
    721  document.adoptNode(span);
    722  assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
    723  assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
    724 
    725  const iframe = document.createElement("iframe");
    726  document.body.appendChild(iframe);
    727  iframe.contentDocument.adoptNode(span);
    728  iframe.contentDocument.body.appendChild(span);
    729  assert_not_equals(span.shadowRoot, null);
    730  assert_equals(span.shadowRoot.adoptedStyleSheets.length, 0);
    731  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    732 }, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
    733 
    734 test(() => {
    735  const span = document.createElement("span");
    736  const div = document.createElement("div");
    737  thirdSection.appendChild(span);
    738  span.appendChild(div);
    739  const shadowDiv = attachShadowDiv(div);
    740  const sheet = new CSSStyleSheet();
    741  sheet.replaceSync("* { color: red; }");
    742  div.shadowRoot.adoptedStyleSheets = [sheet];
    743  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
    744 
    745  document.adoptNode(span);
    746  assert_equals(div.shadowRoot.adoptedStyleSheets.length, 1);
    747  assert_equals(div.shadowRoot.adoptedStyleSheets[0], sheet);
    748 
    749  const iframe = document.createElement("iframe");
    750  document.body.appendChild(iframe);
    751  iframe.contentDocument.adoptNode(span);
    752  iframe.contentDocument.body.appendChild(span);
    753  assert_not_equals(div.shadowRoot, null);
    754  assert_equals(div.shadowRoot.adoptedStyleSheets.length, 0);
    755  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
    756 }, `Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document`);
    757 
    758 test(() => {
    759  const host = document.createElement("div");
    760  const root = host.attachShadow({mode: "open"});
    761  root.adoptedStyleSheets = [new CSSStyleSheet()];
    762  document.body.offsetTop;
    763 }, 'Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.');
    764 
    765 test(() => {
    766  const host = document.createElement("div");
    767  thirdSection.appendChild(host);
    768  const root = host.attachShadow({mode: "open"});
    769  const sheet = new CSSStyleSheet();
    770  root.adoptedStyleSheets = [sheet];
    771  host.remove();
    772  sheet.replaceSync('');
    773 }, 'Modifying an adopted stylesheet on a disconnected shadow root should not crash.');
    774 
    775 function currentLocation() {
    776  const sections = location.href.split("/")
    777  sections.pop();
    778  return sections.join("/");
    779 }
    780 
    781 test(() => {
    782  const span = document.createElement("span");
    783  thirdSection.appendChild(span);
    784  const shadowDiv = attachShadowDiv(span);
    785 
    786  const fileName = "example.png"
    787  const fullPath = `${currentLocation()}/${fileName}`
    788 
    789  const sheet = new CSSStyleSheet();
    790  span.shadowRoot.adoptedStyleSheets = [sheet];
    791 
    792  sheet.replaceSync(`* { background-image: url("${fileName}"); }`);
    793  const styleFromRelative = getComputedStyle(shadowDiv).backgroundImage;
    794 
    795  sheet.replaceSync(`* { background-image: url("${fullPath}"); }`);
    796  const styleFromFull = getComputedStyle(shadowDiv).backgroundImage;
    797 
    798  assert_equals(styleFromRelative, styleFromFull);
    799 }, "Constructing a sheet with the default base URL uses the constructor document's base URL for CSS rules");
    800 
    801 </script>