summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-nesting
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/css/css-nesting
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-nesting')
-rw-r--r--testing/web-platform/tests/css/css-nesting/conditional-properties-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-nesting/conditional-properties.html34
-rw-r--r--testing/web-platform/tests/css/css-nesting/conditional-rules-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-nesting/conditional-rules.html38
-rw-r--r--testing/web-platform/tests/css/css-nesting/cssom.html127
-rw-r--r--testing/web-platform/tests/css/css-nesting/delete-other-rule-crash.html15
-rw-r--r--testing/web-platform/tests/css/css-nesting/implicit-nesting-ref.html24
-rw-r--r--testing/web-platform/tests/css/css-nesting/implicit-nesting.html61
-rw-r--r--testing/web-platform/tests/css/css-nesting/implicit-parent-insertion-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-nesting/invalid-inner-rules.html56
-rw-r--r--testing/web-platform/tests/css/css-nesting/invalidation-001.html33
-rw-r--r--testing/web-platform/tests/css/css-nesting/invalidation-002.html33
-rw-r--r--testing/web-platform/tests/css/css-nesting/invalidation-003.html34
-rw-r--r--testing/web-platform/tests/css/css-nesting/invalidation-004.html30
-rw-r--r--testing/web-platform/tests/css/css-nesting/nesting-basic-ref.html29
-rw-r--r--testing/web-platform/tests/css/css-nesting/nesting-basic.html103
-rw-r--r--testing/web-platform/tests/css/css-nesting/parsing.html43
-rw-r--r--testing/web-platform/tests/css/css-nesting/pseudo-part-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.tentative.html69
19 files changed, 823 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-nesting/conditional-properties-ref.html b/testing/web-platform/tests/css/css-nesting/conditional-properties-ref.html
new file mode 100644
index 0000000000..0285acbf33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/conditional-properties-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Properties in nested conditional rules</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ @media (min-width: 50px) {
+ .test-5 > div {
+ background-color: green;
+ }
+ }
+
+ @supports (display: grid) {
+ .test-10 {
+ background-color: green;
+ }
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-5"><div></div></div>
+ <div class="test test-10"><div></div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/conditional-properties.html b/testing/web-platform/tests/css/css-nesting/conditional-properties.html
new file mode 100644
index 0000000000..122b8635c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/conditional-properties.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Properties in nested conditional rules</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<link rel="match" href="conditional-properties-ref.html">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ .test-5 {
+ @media (min-width: 50px) {
+ background-color: green;
+ }
+ }
+
+ .test-10 {
+ @supports (display: grid) {
+ background-color: green;
+ }
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-5"><div></div></div>
+ <div class="test test-10"><div></div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/conditional-rules-ref.html b/testing/web-platform/tests/css/css-nesting/conditional-rules-ref.html
new file mode 100644
index 0000000000..945ed30513
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/conditional-rules-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Conditional rules with nesting</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ @media (min-width: 50px) {
+ .test-5 > div {
+ background-color: green;
+ }
+ }
+
+ @supports (display: grid) {
+ .test-10 {
+ background-color: green;
+ }
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-5"><div></div></div>
+ <div class="test test-10"><div></div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/conditional-rules.html b/testing/web-platform/tests/css/css-nesting/conditional-rules.html
new file mode 100644
index 0000000000..be925d5d87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/conditional-rules.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Conditional rules with nesting</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<link rel="match" href="conditional-rules-ref.html">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ .test-5 {
+ @media (min-width: 50px) {
+ & {
+ background-color: green;
+ }
+ }
+ }
+
+ .test-10 {
+ @supports (display: grid) {
+ & {
+ background-color: green;
+ }
+ }
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-5"><div></div></div>
+ <div class="test test-10"><div></div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/cssom.html b/testing/web-platform/tests/css/css-nesting/cssom.html
new file mode 100644
index 0000000000..c7150cec5d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/cssom.html
@@ -0,0 +1,127 @@
+<!doctype html>
+<title>Simple CSSOM manipulation of subrules</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style id="ss"></style>
+
+<script>
+ test(() => {
+ let [ss] = document.styleSheets;
+ assert_equals(ss.cssRules.length, 0);
+ ss.insertRule('.a { color: red; }');
+ assert_equals(ss.cssRules.length, 1);
+ assert_equals(ss.cssRules[0].cssText, '.a { color: red; }');
+
+ // Test inserting sub-cssRules, at various positions.
+ ss.cssRules[0].insertRule('& .b { color: green; }');
+ ss.cssRules[0].insertRule('& .c { color: blue; }', 1);
+ ss.cssRules[0].insertRule('& .d { color: hotpink; }', 1);
+ assert_equals(ss.cssRules[0].cssText,
+`.a {
+ color: red;
+ & .b { color: green; }
+ & .d { color: hotpink; }
+ & .c { color: blue; }
+}`, 'inserting should work');
+
+ // Test deleting a rule.
+ ss.cssRules[0].deleteRule(1);
+ assert_equals(ss.cssRules[0].cssText,
+`.a {
+ color: red;
+ & .b { color: green; }
+ & .c { color: blue; }
+}`, 'deleting should work');
+ });
+
+ // Test that out-of-bounds throws exceptions and does not affect the stylesheet.
+ const sampleSheetText =
+`.a {
+ color: red;
+ & .b { color: green; }
+ & .c { color: blue; }
+}`;
+
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ assert_throws_dom('IndexSizeError', () => { ss.cssRules[0].insertRule('& .broken {}', 3); });
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText, 'unchanged after no-insert');
+ });
+
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ assert_throws_dom('IndexSizeError', () => { ss.cssRules[0].insertRule('& .broken {}', -1); });
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText, 'unchanged after no-insert');
+ });
+
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ assert_throws_dom('IndexSizeError', () => { ss.cssRules[0].deleteRule(5); });
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText, 'unchanged after no-delete');
+ });
+
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ assert_equals(ss.cssRules[0].cssRules[2], undefined, 'subscript out-of-bounds returns undefined');
+ assert_equals(ss.cssRules[0].cssRules.item(2), null, 'item() out-of-bounds returns null');
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText, 'unchanged after no-access');
+ });
+
+ // Test that inserting an invalid rule throws an exception.
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ let exception;
+ assert_throws_dom('SyntaxError', () => { ss.cssRules[0].insertRule('% {}'); });
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText, 'unchanged after invalid rule');
+ });
+
+ // Test that we can get out single rule through .cssRules.
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ assert_equals(ss.cssRules[0].cssRules[1].cssText, '& .c { color: blue; }');
+ });
+
+ // Test that we can insert a @supports rule, that it serializes in the right place
+ // and has the right parent. Note that the indentation is broken per-spec.
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ ss.cssRules[0].insertRule('@supports selector(&) { & div { font-size: 10px; }}', 1);
+ assert_equals(ss.cssRules[0].cssText,
+`.a {
+ color: red;
+ & .b { color: green; }
+ @supports selector(&) {
+ & div { font-size: 10px; }
+}
+ & .c { color: blue; }
+}`, '@supports is added');
+
+ assert_equals(ss.cssRules[0].cssRules[1].parentRule, ss.cssRules[0]);
+ ss.cssRules[0].deleteRule(1);
+ assert_equals(ss.cssRules[0].cssText, sampleSheetText);
+ });
+
+ // Nested rules are not part of declaration lists, and thus should not
+ // be possible to insert with .style.
+ test(() => {
+ document.getElementById('ss').innerHTML = sampleSheetText;
+ let [ss] = document.styleSheets;
+ ss.cssRules[0].style = 'color: olivedrab; &.d { color: peru; }';
+ assert_equals(ss.cssRules[0].cssText,
+`.a {
+ color: olivedrab;
+ & .b { color: green; }
+ & .c { color: blue; }
+}`, 'color is changed, new rule is ignored');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/delete-other-rule-crash.html b/testing/web-platform/tests/css/css-nesting/delete-other-rule-crash.html
new file mode 100644
index 0000000000..bde7c554e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/delete-other-rule-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<body>
+<title>Crash with lazy parsing child rules and stylesheet copy-on-write</title>
+<link rel="help" href="https://crbug.com/1404879">
+<link href="../support/delete-other-rule-crash.css" rel="stylesheet">
+<script src="/common/gc.js"></script>
+<script>
+addEventListener('DOMContentLoaded', async () => {
+ requestAnimationFrame(async () => {
+ document.styleSheets[0].deleteRule(0);
+ await garbageCollect();
+ document.styleSheets[0].cssRules[0].cssText;
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/implicit-nesting-ref.html b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ref.html
new file mode 100644
index 0000000000..006216b60e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Implicit nesting</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<style>
+ .test {
+ background-color: green;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/implicit-nesting.html b/testing/web-platform/tests/css/css-nesting/implicit-nesting.html
new file mode 100644
index 0000000000..05b9e04fa8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>Implicit nesting</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<link rel="match" href="implicit-nesting-ref.html">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ .test-1 {
+ > div {
+ background-color: green;
+ }
+ }
+
+ .test-2 {
+ .test-2-child {
+ background-color: green;
+ }
+ }
+ .test-2-child {
+ background-color: red;
+ }
+
+ .test-3-child {
+ background-color: red;
+ }
+ .test-3-child {
+ .test-3 & {
+ background-color: green;
+ }
+ }
+
+ .test-4 {
+ :is(&) {
+ background-color: green;
+ }
+ }
+
+ .test {
+ :is(.test-5, &.does-not-exist) {
+ background-color: green;
+ }
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-1"><div></div></div>
+ <div class="test test-2"><div class="test-2-child"></div></div>
+ <div class="test test-3"><div class="test-3-child"></div></div>
+ <div class="test test-4"></div>
+ <div class="test test-5"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/implicit-parent-insertion-crash.html b/testing/web-platform/tests/css/css-nesting/implicit-parent-insertion-crash.html
new file mode 100644
index 0000000000..4be1e1c8f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/implicit-parent-insertion-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<body>
+<title>Use-after-free when inserting implicit parent selector</title>
+<link rel="help" href="https://crbug.com/1380313">
+<style>
+:root {
+ :lang(en), :lang(en) {
+ }
+}
+</style>
+<div lang="en"></div>
+<script>
+ // Allocate a large chunk of memory, to trigger a GC.
+ new Int32Array(536870911);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-nesting/invalid-inner-rules.html b/testing/web-platform/tests/css/css-nesting/invalid-inner-rules.html
new file mode 100644
index 0000000000..219dcac3f5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/invalid-inner-rules.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<title>Simple CSSOM manipulation of subrules</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style id="ss">
+div {
+ /* This is not a conditional rule, and thus cannot be in nesting context. */
+ @layer {
+ &.a { font-size: 10px; }
+ }
+
+ @media screen {
+ &.a { color: red; }
+
+ /* Same. */
+ @layer {
+ &.a { font-size: 10px; }
+ }
+ }
+}
+</style>
+
+<script>
+ test(() => {
+ let [ss] = document.styleSheets;
+ assert_equals(ss.cssRules.length, 1);
+
+ // The @layer rule should be ignored.
+ assert_equals(ss.cssRules[0].cssText,
+`div {
+ @media screen {
+ &.a { color: red; }
+}
+}`);
+ });
+
+ test(() => {
+ let [ss] = document.styleSheets;
+ assert_equals(ss.cssRules.length, 1);
+ assert_throws_dom('HierarchyRequestError',
+ () => { ss.cssRules[0].cssRules[0].insertRule('@layer {}', 0); });
+ assert_throws_dom('HierarchyRequestError',
+ () => { ss.cssRules[0].insertRule('@layer {}', 0); });
+
+ // The @layer rules should be ignored (again).
+ assert_equals(ss.cssRules[0].cssText,
+`div {
+ @media screen {
+ &.a { color: red; }
+}
+}`);
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/invalidation-001.html b/testing/web-platform/tests/css/css-nesting/invalidation-001.html
new file mode 100644
index 0000000000..a9a4284cc3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/invalidation-001.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS Selectors nested invalidation on changed parent</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+ .b {
+ color: red;
+ }
+ .a {
+ & .b {
+ color: green;
+ }
+ }
+</style>
+
+<div id="container">
+ <div id="child" class="b">
+ Test passes if color is green.
+ </div>
+</div>
+
+<script>
+ test(() => {
+ let container = document.getElementById('container');
+ let child = document.getElementById('child');
+ assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
+ container.classList.add('a');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/invalidation-002.html b/testing/web-platform/tests/css/css-nesting/invalidation-002.html
new file mode 100644
index 0000000000..8419c4526e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/invalidation-002.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS Selectors nested invalidation on changed child</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+ .a {
+ color: green;
+ }
+ .a {
+ & .b {
+ color: red;
+ }
+ }
+</style>
+
+<div id="container" class="a">
+ <div id="child" class="b">
+ Test passes if color is green.
+ </div>
+</div>
+
+<script>
+ test(() => {
+ let container = document.getElementById('container');
+ let child = document.getElementById('child');
+ assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
+ child.classList.remove('b');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 128, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/invalidation-003.html b/testing/web-platform/tests/css/css-nesting/invalidation-003.html
new file mode 100644
index 0000000000..d1d6d4b9ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/invalidation-003.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>CSS Selectors nested invalidation with :has()</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+ .a {
+ color: red;
+ :has(&) {
+ color: green;
+ }
+ }
+</style>
+
+<div id="container">
+ Test passes if color is green.
+ <div>
+ <div id="child"></div>
+ </div>
+</div>
+
+<script>
+ test(() => {
+ let container = document.getElementById('container');
+ let child = document.getElementById('child');
+ assert_equals(getComputedStyle(container).color, 'rgb(0, 0, 0)');
+ assert_equals(getComputedStyle(child).color, 'rgb(0, 0, 0)');
+ child.classList.add('a');
+ assert_equals(getComputedStyle(container).color, 'rgb(0, 128, 0)');
+ assert_equals(getComputedStyle(child).color, 'rgb(255, 0, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/invalidation-004.html b/testing/web-platform/tests/css/css-nesting/invalidation-004.html
new file mode 100644
index 0000000000..a66c47cf16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/invalidation-004.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>CSS Selectors nested invalidation through @media by selectorText</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+ .b {
+ color: red;
+ }
+ & {
+ @media screen {
+ &.b { color: green; }
+ }
+ }
+</style>
+
+<div id="elem" class="a b">
+ Test passes if color is green.
+</div>
+
+<script>
+ test(() => {
+ let elem = document.getElementById('elem');
+ assert_equals(getComputedStyle(elem).color, 'rgb(255, 0, 0)');
+ document.styleSheets[0].rules[1].selectorText = '.a';
+ assert_equals(getComputedStyle(elem).color, 'rgb(0, 128, 0)');
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/nesting-basic-ref.html b/testing/web-platform/tests/css/css-nesting/nesting-basic-ref.html
new file mode 100644
index 0000000000..c2f7c66949
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/nesting-basic-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Basic nesting</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<style>
+ .test {
+ background-color: green;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+ <div class="test"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/nesting-basic.html b/testing/web-platform/tests/css/css-nesting/nesting-basic.html
new file mode 100644
index 0000000000..6bc727a731
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/nesting-basic.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<title>Basic nesting</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<link rel="match" href="nesting-basic-ref.html">
+<style>
+ .test {
+ background-color: red;
+ width: 100px;
+ height: 100px;
+ display: grid;
+ }
+
+ .test-1 {
+ & > div {
+ background-color: green;
+ }
+ }
+
+ .test-2 {
+ & > div {
+ background-color: green;
+ }
+ }
+
+ .test-3 {
+ & .test-3-child {
+ background-color: green;
+ }
+ }
+
+ span > b {
+ .test-4 section & {
+ display: inline-block;
+ background-color: green;
+ width: 100%;
+ height: 100%;
+ }
+
+ .test-4 section > & {
+ background-color: red;
+ }
+ }
+
+ .test-6 {
+ &.test {
+ background-color: green;
+ }
+ }
+
+ .test-7, .t7- {
+ & + .test-7-child, &.t7-- {
+ background-color: green;
+ }
+ }
+
+ .test-8 {
+ & {
+ background-color: green;
+ }
+ }
+
+ .test-9 {
+ &:is(.t9-, &.t9--) {
+ background-color: green;
+ }
+ }
+
+ .test-10 {
+ & {
+ background-color: green;
+ }
+ background-color: red;
+ }
+
+ .test-11 {
+ & {
+ background-color: red;
+ }
+ background-color: green !important;
+ }
+
+ body * + * {
+ margin-top: 8px;
+ }
+</style>
+<body>
+ <p>Tests pass if <strong>block is green</strong></p>
+ <div class="test test-1"><div></div></div>
+ <div class="test test-2"><div></div></div>
+ <div class="test test-3"><div class="test-3-child"></div></div>
+ <div class="test test-4">
+ <section>
+ <span><b></b></span>
+ </section>
+ </div>
+ <div class="test test-6"><div></div></div>
+ <div class="test t7- t7--"><div class="test-7-child"></div></div>
+ <div class="test test-8"><div></div></div>
+ <div class="test test-9 t9-- t9-"><div></div></div>
+ <div class="test test-10"><div></div></div>
+ <div class="test test-11"><div></div></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-nesting/parsing.html b/testing/web-platform/tests/css/css-nesting/parsing.html
new file mode 100644
index 0000000000..66d1566586
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/parsing.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<title>CSS Selectors parsing</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style id="test-sheet"></style>
+<script>
+ let [ss] = document.styleSheets
+
+ const beforeEach = () => {
+ while (ss.rules.length)
+ ss.removeRule(0)
+ }
+
+ const testRules = [
+ `.foo {\n & { color: green; }\n}`, // 🐰
+ `.foo {\n &.bar { color: green; }\n}`,
+ `.foo {\n & .bar { color: green; }\n}`,
+ `.foo {\n & > .bar { color: green; }\n}`,
+ `.foo {\n &:is(.bar, &.baz) { color: green; }\n}`,
+ `.foo {\n .bar& { color: green; }\n}`,
+ `.foo {\n .bar & { color: green; }\n}`,
+ `.foo {\n .bar > & { color: green; }\n}`,
+ `.foo, .bar {\n & + .baz, &.qux { color: green; }\n}`,
+ `.foo {\n & .bar & .baz & .qux { color: green; }\n}`,
+ `.foo {\n @media (min-width: 50px) {\n & { color: green; }\n}\n}`,
+ `.foo {\n @media (min-width: 50px) { color: green; }\n}`,
+ `main {\n & > section, & > article {\n & > header { color: green; }\n}\n}`,
+ ]
+
+ testRules.forEach(testRule => {
+ test(function() {
+ beforeEach()
+ ss.insertRule(testRule)
+ // todo?
+ // when parsing is being ready/prototyped,
+ // switch to crawling nested rules instead of comparing text
+ assert_equals(ss.rules[0].cssText, testRule)
+ }, testRule)
+ })
+</script>
diff --git a/testing/web-platform/tests/css/css-nesting/pseudo-part-crash.html b/testing/web-platform/tests/css/css-nesting/pseudo-part-crash.html
new file mode 100644
index 0000000000..3ab521d71c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/pseudo-part-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Nesting pseudo element selectors should not crash</title>
+<link rel="help" href="https://crbug.com/1376227">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7912">
+<style>
+ div::part(x) {
+ & {
+ color: red;
+ }
+ }
+</style>
diff --git a/testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.tentative.html b/testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.tentative.html
new file mode 100644
index 0000000000..c3b6bb7be7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.tentative.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<title>Serialization of declarations in group rules</title>
+<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7850">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style id="test-sheet"></style>
+<script>
+ function serialize(cssText) {
+ let [ss] = document.styleSheets;
+ while (ss.rules.length) {
+ ss.removeRule(0)
+ }
+ ss.insertRule(cssText);
+ return ss.rules[0].cssText;
+ }
+
+ function assert_unchanged(cssText) {
+ assert_equals(serialize(cssText), cssText);
+ }
+
+ function assert_becomes(cssText, serializedCssText) {
+ assert_equals(serialize(cssText), serializedCssText);
+ }
+
+ // Declarations are serialized on one line, rules on two.
+ test(() => {
+ assert_unchanged("@media screen {\n div { color: red; background-color: green; }\n}");
+ assert_unchanged("div {\n @media screen { color: red; background-color: green; }\n}");
+ });
+
+ // Mixed declarations/rules are on two lines.
+ test(() => {
+ assert_unchanged("div {\n @supports selector(&) {\n color: red; background-color: green;\n &:hover { color: navy; }\n}\n}");
+ });
+
+ // & {} rules are removed if and only if they are first, and they have no children.
+ test(() => {
+ assert_becomes("div { @media screen { & { color: red; } }",
+ "div {\n @media screen { color: red; }\n}");
+ assert_becomes("div { @media screen { & { color: red; &:hover { } } }",
+ "div {\n @media screen {\n & {\n color: red;\n &:hover { }\n}\n}\n}");
+ assert_becomes("div { @media screen { &.cls { color: red; } & { color: red; }",
+ "div {\n @media screen {\n &.cls { color: red; }\n & { color: red; }\n}\n}");
+ assert_becomes("div { @media screen { & { color: red; } & { color: red; }",
+ "div {\n @media screen {\n color: red;\n & { color: red; }\n}\n}");
+ assert_becomes("div { @media screen { color: red; & { color: red; }",
+ "div {\n @media screen {\n color: red;\n & { color: red; }\n}\n}");
+ assert_becomes("div { @media screen { color: red; & { color: blue; }",
+ "div {\n @media screen {\n color: red;\n & { color: blue; }\n}\n}");
+ assert_becomes("div { @media screen { &, p > & { color: blue; }",
+ "div {\n @media screen {\n &, p > & { color: blue; }\n}\n}");
+ });
+
+ // They are not removed from regular rules.
+ test(() => {
+ assert_becomes("div { & { color: red; } }", "div {\n & { color: red; }\n}");
+ });
+
+ // Empty rules (confusingly?) serialize different between style rules
+ // and conditional group rules.
+ test(() => {
+ assert_unchanged("@media screen {\n}");
+ assert_unchanged("div { }");
+ assert_unchanged("div {\n @media screen {\n}\n}");
+ assert_unchanged("@media screen {\n div { }\n}");
+ });
+</script>