summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html')
-rw-r--r--testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html801
1 files changed, 801 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html b/testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html
new file mode 100644
index 0000000000..f84e4ea9af
--- /dev/null
+++ b/testing/web-platform/tests/css/cssom/CSSStyleSheet-constructable.html
@@ -0,0 +1,801 @@
+<!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({disabled: true, media: "screen, print"});
+ assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
+ 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, null, "The title attribute must return the title or null if title is the empty string");
+ 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, null, "The title attribute must return the title or null if title is the empty string");
+ 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');
+
+test(() => {
+ const sheet = new CSSStyleSheet({title: "something"});
+ assert_equals(sheet.title, null, "title and alternate are not supported by the constructor. https://github.com/WICG/construct-stylesheets/issues/105");
+}, "title can be set in the CSSStyleSheet constructor");
+
+promise_test(() => {
+ const sheet = new CSSStyleSheet({disabled: true, media: "screen, print"});
+ const promise_sheet = sheet.replace(redStyleTexts[0]);
+ return promise_sheet.then(function(sheet) {
+ assert_equals(sheet.title, null, "The title attribute must return the title or null if title is the empty string");
+ 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({disabled: true});
+ const whiteSheet = new CSSStyleSheet({disabled: 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.
+
+ // disabled stylesheets aren't applied
+ document.adoptedStyleSheets = [whiteStyleSheet];
+ 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)");
+
+ // disable dsheets don't block other styles from applying
+ document.adoptedStyleSheets = [greenStyleSheet, blueStyleSheet];
+ 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)");
+ document.adoptedStyleSheets = [];
+ });
+}, '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');
+
+test(() => {
+ const sheet = new CSSStyleSheet();
+ sheet.replaceSync(":host { color: red; }");
+ const host = document.createElement("div");
+ let sr = host.attachShadow({mode: "open"});
+ sr.adoptedStyleSheets = [sheet];
+ document.body.appendChild(host);
+ assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies when connected");
+ sheet.replaceSync(":host { color: blue; }");
+ assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Style update applies when connected");
+}, 'Attaching a shadow root that already has adopted stylesheets work');
+
+test(() => {
+ const sheet = new CSSStyleSheet();
+ sheet.replaceSync(":host([red]) { color: red; } :host(.blue) { color: blue; }");
+ const host = document.createElement("div");
+ host.toggleAttribute("red");
+ document.body.appendChild(host);
+ assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "No style applies yet");
+
+ let sr = host.attachShadow({mode: "open"});
+ sr.adoptedStyleSheets = [sheet];
+
+ assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after adding style");
+ document.body.removeChild(host);
+ document.body.appendChild(host);
+ assert_equals(getComputedStyle(host).color, "rgb(255, 0, 0)", "Style applies after reattachment");
+ host.toggleAttribute("red");
+ assert_equals(getComputedStyle(host).color, "rgb(0, 0, 0)", "Attribute updates to the element after reattachment apply");
+ host.classList.toggle("blue");
+ assert_equals(getComputedStyle(host).color, "rgb(0, 0, 255)", "Class updates to the element after reattachment apply");
+
+}, "Re-attaching shadow host and updating attributes 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)");
+ document.adoptedStyleSheets = [];
+ });
+}, '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_dom(
+ 'NotAllowedError',
+ iframe.contentWindow.DOMException,
+ () => { 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(async () => {
+ const iframe = document.createElement("iframe");
+ const iframeLoaded = new Promise(resolve => iframe.addEventListener("load", resolve));
+ document.body.appendChild(iframe);
+ await iframeLoaded;
+ 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_dom('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_dom('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_dom('NotAllowedError', iframe.contentWindow.DOMException, () => {
+ 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_dom('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(() => {
+ const sheet = new CSSStyleSheet();
+ assert_equals(sheet.cssRules.length, 0);
+
+ sheet.replaceSync(redStyleTexts[0])
+ assert_equals(sheet.cssRules.length, 1);
+ assert_equals(redStyleTexts[0], sheet.cssRules[0].cssText);
+
+ sheet.replaceSync(redStyleTexts[1]);
+ assert_equals(sheet.cssRules.length, 1);
+ assert_equals(redStyleTexts[1], sheet.cssRules[0].cssText);
+}, 'CSSStyleSheet.replaceSync replaces stylesheet text synchronously');
+
+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 correctly updates the style of its adopters synchronously');
+
+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("target");
+
+ // 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(".target { color: red; }");
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
+
+ // Create a style element that will set colors to white.
+ const style = document.createElement("style");
+ style.textContent = ".target { color: white; }";
+ span.shadowRoot.appendChild(style)
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
+
+ span.shadowRoot.adoptedStyleSheets = [];
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
+
+ span.shadowRoot.adoptedStyleSheets = [sheet];
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
+
+ sheet.disabled = true;
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
+
+ sheet.disabled = false;
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again");
+}, 'Adopted sheets are ordered after non-adopted sheets in the shadow root')
+
+test(() => {
+ // Attach a div inside a shadow root with the class ".red".
+ const span = document.createElement("span");
+ thirdSection.appendChild(span);
+ span.classList.add("target");
+
+ // Create empty stylesheet.
+ const sheet = new CSSStyleSheet();
+ document.adoptedStyleSheets = [sheet];
+ assert_equals(getComputedStyle(span).color, "rgb(0, 0, 0)");
+
+ // Replace the stylesheet text that will color it red.
+ sheet.replaceSync(".target { color: red; }");
+ assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)");
+
+ // Create a style element that will set colors to white.
+ const style = document.createElement("style");
+ style.textContent = ".target { color: white; }";
+ span.appendChild(style)
+ assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "non-adopted styles should be ordered before adopted styles");
+
+ document.adoptedStyleSheets = [];
+ assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with no adopted styles in conflict, the non-adopted style should take effect");
+
+ document.adoptedStyleSheets = [sheet];
+ assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted style should be ordered after the non-adopted style");
+
+ sheet.disabled = true;
+ assert_equals(getComputedStyle(span).color, "rgb(255, 255, 255)", "with the adopted sheet disabled, the non-adopted style should take effect");
+
+ sheet.disabled = false;
+ assert_equals(getComputedStyle(span).color, "rgb(255, 0, 0)", "the adopted sheet re-enabled, it should take effect again")
+}, 'Adopted sheets are ordered after non-adopted sheets in the document')
+
+const import_text = '@import url("support/constructable-import.css");';
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => { (new CSSStyleSheet).insertRule(import_text) });
+}, 'Inserting an @import rule through insertRule on a constructed stylesheet throws an exception');
+
+promise_test(t => {
+ const importUrl = "support/constructable-import.css";
+ const sheet = new CSSStyleSheet();
+
+ sheet.replaceSync(`@import url("${importUrl}");`);
+
+ const timeAfterReplaceSync = performance.now();
+ let link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.href = importUrl;
+
+ return new Promise(resolve => {
+ link.addEventListener("error", t.unreached_func("Load shouldn't fail"));
+ link.addEventListener("load", t.step_func(() => {
+ let entries = window.performance.getEntriesByType('resource').filter(entry => entry.name.includes(importUrl));
+ assert_equals(entries.length, 1, "There should be only one entry for the import URL");
+ assert_greater_than_equal(entries[0].startTime, timeAfterReplaceSync, "The entry's start time should be after replaceSync threw");
+ link.remove();
+ resolve();
+ }));
+ document.body.appendChild(link);
+ });
+}, "CSSStyleSheet.replaceSync should not trigger any loads from @import rules")
+
+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 NOT applied.
+ const sheet_promise = sheet.replace(import_text);
+ return sheet_promise.then((sheet) => {
+ // replace() ignores @import rules:
+ assert_equals(sheet.cssRules.length, 0);
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
+ }).catch((reason) => {
+ assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
+ });
+}, 'CSSStyleSheet.replace allows, but ignores, import rule inside');
+
+promise_test(() => {
+ const span = document.createElement("span");
+ thirdSection.appendChild(span);
+ const shadowDiv = attachShadowDiv(span);
+ const targetSpan = document.createElement("span");
+ targetSpan.classList.add("target");
+ shadowDiv.appendChild(targetSpan);
+ 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 NOT applied, but regular rule does apply.
+ const sheet_promise = sheet.replace(import_text + ".target { color: blue; }");
+ return sheet_promise.then((sheet) => {
+ assert_equals(sheet.cssRules.length, 1);
+ // @import not applied:
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
+ // regular rule applied:
+ assert_equals(getComputedStyle(targetSpan).color, "rgb(0, 0, 255)");
+ }).catch((reason) => {
+ assert_unreached(`Promise was rejected (${reason}) when it should have been resolved`);
+ });
+}, 'CSSStyleSheet.replace ignores @import rule but still loads other rules');
+
+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 NOT applied.
+ try {
+ sheet.replaceSync(import_text);
+ // replaceSync() ignores @import rules:
+ assert_equals(sheet.cssRules.length, 0);
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
+ } catch(reason) {
+ assert_unreached(`replaceSync threw an exception (${reason}) when it shouldn't have`);
+ }
+}, 'CSSStyleSheet.replaceSync allows, but ignores, import rule inside');
+
+promise_test(() => {
+ const sheet = new CSSStyleSheet();
+ const sheet_promise = sheet.replace("@import url('not-there.css');");
+
+ return sheet_promise.then((sheet) => {
+ // No exception here
+ }).catch((reason) => {
+ assert_unreached("Promise was rejected");
+ });
+}, 'CSSStyleSheet.replace does not reject 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');
+
+test(() => {
+ const span = document.createElement("span");
+ const div = document.createElement("div");
+ thirdSection.appendChild(span);
+ span.appendChild(div);
+ const shadowDiv = attachShadowDiv(div);
+ const sheet = new CSSStyleSheet();
+ sheet.replaceSync("* { color: red; }");
+ div.shadowRoot.adoptedStyleSheets = [sheet];
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
+
+ document.adoptNode(span);
+ assert_equals(div.shadowRoot.adoptedStyleSheets.length, 1);
+ assert_equals(div.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(div.shadowRoot, null);
+ assert_equals(div.shadowRoot.adoptedStyleSheets.length, 0);
+ assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
+}, `Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document`);
+
+test(() => {
+ const host = document.createElement("div");
+ const root = host.attachShadow({mode: "open"});
+ root.adoptedStyleSheets = [new CSSStyleSheet()];
+ document.body.offsetTop;
+}, 'Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.');
+
+test(() => {
+ const host = document.createElement("div");
+ thirdSection.appendChild(host);
+ const root = host.attachShadow({mode: "open"});
+ const sheet = new CSSStyleSheet();
+ root.adoptedStyleSheets = [sheet];
+ host.remove();
+ sheet.replaceSync('');
+}, 'Modifying an adopted stylesheet on a disconnected shadow root should not crash.');
+
+function currentLocation() {
+ const sections = location.href.split("/")
+ sections.pop();
+ return sections.join("/");
+}
+
+test(() => {
+ const span = document.createElement("span");
+ thirdSection.appendChild(span);
+ const shadowDiv = attachShadowDiv(span);
+
+ const fileName = "example.png"
+ const fullPath = `${currentLocation()}/${fileName}`
+
+ const sheet = new CSSStyleSheet();
+ span.shadowRoot.adoptedStyleSheets = [sheet];
+
+ sheet.replaceSync(`* { background-image: url("${fileName}"); }`);
+ const styleFromRelative = getComputedStyle(shadowDiv).backgroundImage;
+
+ sheet.replaceSync(`* { background-image: url("${fullPath}"); }`);
+ const styleFromFull = getComputedStyle(shadowDiv).backgroundImage;
+
+ assert_equals(styleFromRelative, styleFromFull);
+}, "Constructing a sheet with the default base URL uses the constructor document's base URL for CSS rules");
+
+</script>