testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html
author Rakina Zata Amni <rakina@chromium.org>
Wed, 06 Mar 2019 10:35:55 +0000
changeset 522511 258fdb4dac181a03048494d63d00784f4066edfe
parent 522313 66b1aba3fb4372ec47986e728b1da9b32dd3d368
child 522560 df46e8c9bc569597d1774836fc8b16deb1a269ff
permissions -rw-r--r--
Bug 1529315 [wpt PR 15474] - Mark shadow trees for style collection update when inserted to document, a=testonly Automatic update from web-platform-tests Mark shadow trees for style collection update when inserted to document When we attach shadow trees with non-empty |adoptedStyleSheets|, we should update the active style sheet collection for that tree scope. Otherwise, if there are no other stylesheets for that tree scope, we will never mark the tree scope as dirty and thus have incorrect style calculation for that tree scope. Bug: 933578 Change-Id: Id7229b05440a51ac8e5d55570ed030b8cfb707d2 Reviewed-on: https://chromium-review.googlesource.com/c/1477623 Reviewed-by: Kent Tamura <tkent@chromium.org> Commit-Queue: Rakina Zata Amni <rakina@chromium.org> Cr-Commit-Position: refs/heads/master@{#633666} -- wpt-commits: 7266a4200f24ade6c91608ab05a936770c92e2f0 wpt-pr: 15474

<!DOCTYPE html>
<title>CSSStyleSheet constructor and adoptedStyleSheets</title>
<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
<link rel="help" href="https://wicg.github.io/construct-stylesheets/">
<script src = '/resources/testharness.js'></script>
<script src = '/resources/testharnessreport.js'></script>

<section id="firstSection">
  <div>
    <span class="green"></span>
    <span class="red"></span>
    <span class="blue"></span>
    <span class="white"></span>
    <span class="yellow"></span>
  </div>
</section>
<section id="shadowHost"></section>
<section id="thirdSection"></section>

<script>
'use strict';
const greenStyleText = ".green { color: green; }";
const redStyleTexts = [".red { color: red; }", ".red + span + span { color: red; }"];
const blueStyleTexts = [".blue { color: blue; }", ".blue + span + span { color: blue; }"];
const whiteStyleText = "* { color: white; }";
const yellowStyleText = ".yellow { color: yellow; }";

const firstDiv = document.querySelector('#firstSection > div');
const secondDiv = firstDiv.cloneNode(true);
const shadowHost = document.querySelector('#shadowHost');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.appendChild(secondDiv);

const greenSpan = firstDiv.children[0];
const redSpan = firstDiv.children[1];
const blueSpan = firstDiv.children[2];
const whiteSpan = firstDiv.children[3];
const yellowSpan = firstDiv.children[4];
const greenShadowSpan = secondDiv.children[0];
const redShadowSpan = secondDiv.children[1];
const blueShadowSpan = secondDiv.children[2];
const whiteShadowSpan = secondDiv.children[3];
const yellowShadowSpan = secondDiv.children[4];

test(() => {
  assert_equals(document.adoptedStyleSheets.length, 0);
}, "document.adoptedStyleSheets should initially have length 0.");

test(() => {
  const sheet = new CSSStyleSheet({title: "Red", disabled: true, media: "screen, print"});
  assert_equals(sheet.title, "Red");
  assert_equals(sheet.ownerNode, null);
  assert_equals(sheet.ownerRule, null);
  assert_equals(sheet.media.length, 2);
  assert_equals(sheet.media.item(0), "screen");
  assert_equals(sheet.media.item(1), "print");
  assert_true(sheet.disabled);
  assert_equals(sheet.cssRules.length, 0);

  sheet.insertRule(redStyleTexts[0]);
  assert_equals(sheet.cssRules.length, 1);
  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);

  sheet.insertRule(redStyleTexts[1]);
  assert_equals(sheet.cssRules.length, 2);
  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);

  const sheet2 = new CSSStyleSheet({});
  assert_equals(sheet2.title, "")
  assert_equals(sheet2.ownerNode, null);
  assert_equals(sheet2.ownerRule, null);
  assert_equals(sheet2.media.length, 0);
  assert_false(sheet2.disabled);
  assert_equals(sheet2.cssRules.length, 0);

  sheet2.insertRule(redStyleTexts[1]);
  assert_equals(sheet2.cssRules.length, 1);
  assert_equals(sheet2.cssRules[0].cssText, redStyleTexts[1]);

  sheet2.deleteRule(0);
  assert_equals(sheet2.cssRules.length, 0);

const sheet3 = new CSSStyleSheet();
  assert_equals(sheet3.title, "")
  assert_equals(sheet3.ownerNode, null);
  assert_equals(sheet3.ownerRule, null);
  assert_equals(sheet3.media.length, 0);
  assert_false(sheet3.disabled);
  assert_equals(sheet3.cssRules.length, 0);

  sheet3.insertRule(redStyleTexts[1]);
  assert_equals(sheet3.cssRules.length, 1);
  assert_equals(sheet3.cssRules[0].cssText, redStyleTexts[1]);

  sheet3.deleteRule(0);
  assert_equals(sheet3.cssRules.length, 0);
}, 'new CSSStyleSheet produces empty CSSStyleSheet');

promise_test(() => {
  const sheet = new CSSStyleSheet({title: "Red", disabled: true, media: "screen, print"});
  const promise_sheet = sheet.replace(redStyleTexts[0]);
  return promise_sheet.then(function(sheet) {
    assert_equals(sheet.title, "Red");
    assert_equals(sheet.ownerNode, null);
    assert_equals(sheet.ownerRule, null);
    assert_equals(sheet.media.length, 2);
    assert_equals(sheet.media.item(0), "screen");
    assert_equals(sheet.media.item(1), "print");
    assert_true(sheet.disabled);
    assert_equals(sheet.cssRules.length, 1);
    assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);

    sheet.insertRule(redStyleTexts[1]);
    assert_equals(sheet.cssRules.length, 2);
    assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
  });
}, 'CSSStyleSheet.replace produces Promise<CSSStyleSheet>');

function createAllSheetsPromise() {
  const greenSheet = new CSSStyleSheet();
  const redSheet = new CSSStyleSheet({media: "screen, print"});
  const blueSheet = new CSSStyleSheet({title: "Blue", disabled: true});
  const whiteSheet = new CSSStyleSheet({title: "White", alternate: true});
  const yellowSheet = new CSSStyleSheet({disabled: false});

  const greenPromise = greenSheet.replace(greenStyleText);
  const redPromise = redSheet.replace(redStyleTexts[0] + redStyleTexts[1]);
  const bluePromise = blueSheet.replace(blueStyleTexts[0] + blueStyleTexts[1]);
  const whitePromise = whiteSheet.replace(whiteStyleText);
  const yellowPromise = yellowSheet.replace(yellowStyleText);
  return [greenPromise, redPromise, bluePromise, whitePromise, yellowPromise];
}

promise_test(() => {
  return Promise.all(createAllSheetsPromise()).then(values => {
    const greenStyleSheet = values[0];
    const redStyleSheet = values[1];
    const blueStyleSheet = values[2];
    const whiteStyleSheet = values[3];
    const yellowStyleSheet = values[4];

    // Lists of style sheets can be created, assigned and read.
    document.adoptedStyleSheets = [whiteStyleSheet];
    // alternate stylesheets aren't applied when title != current preferable name
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    document.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
    // disabled stylesheets aren't applied
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];

    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");

    document.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 128, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(255, 255, 0)");
  });
}, 'Constructed style sheets can be applied on document');

promise_test(() => {
  return Promise.all(createAllSheetsPromise()).then(values => {
    const greenStyleSheet = values[0];
    const redStyleSheet = values[1];
    const blueStyleSheet = values[2];
    const whiteStyleSheet = values[3];
    const yellowStyleSheet = values[4];
    shadowRoot.adoptedStyleSheets = [whiteStyleSheet];
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");

    shadowRoot.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");

    shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet];
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");

    shadowRoot.adoptedStyleSheets = [redStyleSheet, yellowStyleSheet, greenStyleSheet, blueStyleSheet];
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(255, 255, 0)");
  });
}, 'Constructed style sheets can be applied on shadow root');

promise_test(() => {
  return Promise.all(createAllSheetsPromise()).then(values => {
    const greenStyleSheet = values[0];
    const redStyleSheet = values[1];
    shadowRoot.adoptedStyleSheets = [greenStyleSheet];
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies connected");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(0, 0, 0)", "Style applies when connected");
    let hostParent = shadowHost.parentNode;
    hostParent.removeChild(shadowHost);
    assert_equals(getComputedStyle(greenShadowSpan).color, "", "Style doesn't apply when detached");
    assert_equals(getComputedStyle(redShadowSpan).color, "", "Style doesn't apply when detached");
    shadowRoot.adoptedStyleSheets = [redStyleSheet, greenStyleSheet];
    hostParent.appendChild(shadowHost);
    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 128, 0)", "Style applies after reattach");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)", "Style applies after reattach");
  });
}, 'Re-attaching shadow host with adopted stylesheets work');

promise_test(() => {
  const plainSheet = new CSSStyleSheet();
  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
  return redStyleSheetPromise.then(function(redStyleSheet) {
    document.adoptedStyleSheets = [redStyleSheet];
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    redStyleSheet.insertRule(redStyleTexts[1]);
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    redStyleSheet.deleteRule(1);
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    redStyleSheet.cssRules[0].style.color = "white";
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 255, 255)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
});
}, 'Changes to constructed stylesheets through CSSOM is reflected');

promise_test(() => {
  const plainSheet = new CSSStyleSheet();
  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
  return redStyleSheetPromise.then(function(redStyleSheet) {
    document.adoptedStyleSheets = [redStyleSheet];
    shadowRoot.adoptedStyleSheets = [redStyleSheet];
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");

    shadowRoot.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    assert_equals(getComputedStyle(greenShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueShadowSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteShadowSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowShadowSpan).color, "rgb(0, 0, 0)");
});
}, 'Constructed stylesheet can be used and modified in multiple TreeScopes');

promise_test(() => {
  const iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  const thirdDiv = firstDiv.cloneNode(true);
  iframe.contentDocument.body.appendChild(thirdDiv);
  const greenIframeSpan = thirdDiv.children[0];
  const redIframeSpan = thirdDiv.children[1];
  const blueIframeSpan = thirdDiv.children[2];
  const whiteIframeSpan = thirdDiv.children[3];
  const yellowIframeSpan = thirdDiv.children[4];

  const plainSheet = new CSSStyleSheet();
  const redStyleSheetPromise = plainSheet.replace(redStyleTexts[0]);
  return redStyleSheetPromise.then(function(redStyleSheet) {
    assert_throws('NotAllowedError', () => { iframe.contentDocument.adoptedStyleSheets = [redStyleSheet]; });
    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");

    document.adoptedStyleSheets = [redStyleSheet];
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    document.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");
  });
}, 'Stylesheets constructed on the main Document cannot be used in iframes');

promise_test(() => {
  const iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  const thirdDiv = firstDiv.cloneNode(true);
  iframe.contentDocument.body.appendChild(thirdDiv);
  const greenIframeSpan = thirdDiv.children[0];
  const redIframeSpan = thirdDiv.children[1];
  const blueIframeSpan = thirdDiv.children[2];
  const whiteIframeSpan = thirdDiv.children[3];
  const yellowIframeSpan = thirdDiv.children[4];

  // Make sure both the main Document and the iframe are not styled
  const emptyStyleSheet = new CSSStyleSheet();
  document.adoptedStyleSheets = [emptyStyleSheet];
  assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

  assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(redIframeSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
  assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");

  const iframePlainSheet = new iframe.contentWindow.CSSStyleSheet();
  const iframeRedStyleSheetPromise = iframePlainSheet.replace(redStyleTexts[0]);
  return iframeRedStyleSheetPromise.then(function(iframeRedStyleSheet) {
    assert_throws('NotAllowedError', () => { document.adoptedStyleSheets = [iframeRedStyleSheet]; });
    assert_equals(getComputedStyle(greenSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(blueSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowSpan).color, "rgb(0, 0, 0)");

    iframe.contentDocument.adoptedStyleSheets = [iframeRedStyleSheet];
    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");

    iframe.contentDocument.adoptedStyleSheets[0].insertRule(redStyleTexts[1]);
    assert_equals(getComputedStyle(greenIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(redIframeSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(blueIframeSpan).color, "rgb(0, 0, 0)");
    assert_equals(getComputedStyle(whiteIframeSpan).color, "rgb(255, 0, 0)");
    assert_equals(getComputedStyle(yellowIframeSpan).color, "rgb(0, 0, 0)");
  });
}, 'Stylesheet constructed on iframe cannot be used in the main Document');
</script>

<div id="divNonConstructed" class="nonConstructed">
</div>

<script>
`use strict`;
const shadowRootNonConstructed = divNonConstructed.attachShadow({mode:'open'})
nonConstructedStyle = document.createElement("style");
shadowRootNonConstructed.appendChild(nonConstructedStyle);
nonConstructedStyle.sheet.insertRule(".nonConstructed { color: red; }", 0);
const nonConstructedStyleSheet = nonConstructedStyle.sheet;

test(() => {
  assert_equals(getComputedStyle(divNonConstructed).color, "rgb(0, 0, 0)");
  assert_throws('NotAllowedError', () => { document.adoptedStyleSheets = [nonConstructedStyleSheet]; });
}, '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');

test(() => {
  const iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  iframeDiv = iframe.contentDocument.createElement("div");
  iframeDiv.classList.add("nonConstructed");
  iframe.contentDocument.body.appendChild(iframeDiv);

  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
  assert_throws('NotAllowedError', () => { iframe.contentDocument.adoptedStyleSheets = [nonConstructedStyleSheet]; });
  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");

  iframeStyle = iframe.contentDocument.createElement("style");
  iframe.contentDocument.body.appendChild(iframeStyle);
  iframeStyle.sheet.insertRule(".nonConstructedSpan { color: red; }");
  const iframeStyleSheet = iframeStyle.sheet;
  nonConstructedSpan = document.createElement("span");
  nonConstructedSpan.classList.add(".nonConstructedSpan");
  divNonConstructed.appendChild(nonConstructedSpan);

  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
  assert_throws('NotAllowedError', () => { document.adoptedStyleSheets = [iframeStyleSheet]; });
  assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)");
}, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees');

function attachShadowDiv(host) {
  const shadowRoot = host.attachShadow({mode: 'open'});
  const shadowDiv = document.createElement("div");
  shadowRoot.appendChild(shadowDiv);
  return shadowDiv;
}

test(() => {
  // Attach a div inside a shadow root with the class ".red".
  const span = document.createElement("span");
  thirdSection.appendChild(span);
  const shadowDiv = attachShadowDiv(span);
  shadowDiv.classList.add("red");
  // Create empty stylesheet.
  const sheet = new CSSStyleSheet();
  span.shadowRoot.adoptedStyleSheets = [sheet];
  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
  // Replace the stylesheet text that will color it red.
  sheet.replaceSync(redStyleTexts[0]);
  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
  assert_equals(sheet.cssRules.length, 1);
  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]);
  sheet.insertRule(redStyleTexts[1]);
  assert_equals(sheet.cssRules.length, 2);
  assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]);
}, 'CSSStyleSheet.replaceSync replaces stylesheet text synchronously');

const import_text = '@import url("support/constructable-import.css");';

test(() => {
  assert_throws("NotAllowedError", () => { (new CSSStyleSheet).replaceSync(import_text) });
}, 'CSSStyleSheet.replaceSync throws exception when there is import rule inside');

test(() => {
  assert_throws("NotAllowedError", () => { (new CSSStyleSheet).insertRule(import_text) });
}, 'Inserting an @import rule through insertRule on a constructed stylesheet throws an exception');

promise_test(() => {
  const span = document.createElement("span");
  thirdSection.appendChild(span);
  const shadowDiv = attachShadowDiv(span);
  const sheet = new CSSStyleSheet();
  span.shadowRoot.adoptedStyleSheets = [sheet];
  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
  // Replace and assert that the imported rule is applied.
  const sheet_promise = sheet.replace(import_text);
  return sheet_promise.then((sheet) => {
    assert_equals(sheet.cssRules.length, 1);
    assert_equals(sheet.cssRules[0].cssText, import_text);
    assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
  });
}, 'CSSStyleSheet.replace allows import rule inside');

promise_test(() => {
  const sheet = new CSSStyleSheet();
  const sheet_promise = sheet.replace("import url('not-there.css');");
  return sheet_promise.catch((reason) => {
    assert_equals(reason.name, "NotAllowedError");
  });
}, 'CSSStyleSheet.replace returns rejected promise on failed imports');

test(() => {
  const span = document.createElement("span");
  thirdSection.appendChild(span);
  const shadowDiv = attachShadowDiv(span);
  const sheet = new CSSStyleSheet();
  span.shadowRoot.adoptedStyleSheets = [sheet];

  const newSpan = span.cloneNode(true);
  assert_equals(newSpan.shadowRoot, null);
}, 'Cloning a shadow host will not clone shadow root, and also adoptedStyleSheets');

test(() => {
  const span = document.createElement("span");
  thirdSection.appendChild(span);
  const shadowDiv = attachShadowDiv(span);
  const sheet = new CSSStyleSheet();
  span.shadowRoot.adoptedStyleSheets = [sheet];

  const iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  const newSpan = iframe.contentDocument.importNode(span, true);
  iframe.contentDocument.body.appendChild(newSpan);
  assert_equals(newSpan.shadowRoot, null);
}, 'Importing a shadow host will not copy shadow root, and also adoptedStyleSheets');

test(() => {
  const span = document.createElement("span");
  thirdSection.appendChild(span);
  const shadowDiv = attachShadowDiv(span);
  const sheet = new CSSStyleSheet();
  sheet.replaceSync("* { color: red; }");
  span.shadowRoot.adoptedStyleSheets = [sheet];
  assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");

  document.adoptNode(span);
  assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
  assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);

  const iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  iframe.contentDocument.adoptNode(span);
  iframe.contentDocument.body.appendChild(span);
  assert_not_equals(span.shadowRoot, null);
  assert_equals(span.shadowRoot.adoptedStyleSheets.length, 0);
  assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');

</script>