diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/css/css-nesting | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-nesting')
25 files changed, 1104 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..c4fabd672a --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/conditional-rules-ref.html @@ -0,0 +1,64 @@ +<!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: 30px; + height: 30px; + display: grid; + } + + @media (min-width: 10px) { + .test-5 > div { + background-color: green; + } + } + + @media (min-width: 10px) { + .test-6 > div { + background-color: green; + } + } + + @supports (display: grid) { + .test-10 { + background-color: green; + } + } + + @layer { + .test-11 { + background-color: green !important; + } + } + + @scope (.test-12) { + :scope { + background-color: green; + } + } + + div { + container-type: inline-size; + } + @container (width >= 0px) { + .test-13 { + 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-6"><div></div></div> + <div class="test test-10"><div></div></div> + <div class="test test-11"><div></div></div> + <div class="test"><div class="test-12"></div></div> + <div class="test"><div class="test-13"></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..55ecc1f9e4 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/conditional-rules.html @@ -0,0 +1,75 @@ +<!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: 30px; + height: 30px; + display: grid; + } + + .test-5 { + @media (min-width: 10px) { + & { + background-color: green; + } + } + } + + .test-6 { + @media (min-width: 10px) { + background-color: green; + } + } + + .test-10 { + @supports (display: grid) { + & { + background-color: green; + } + } + } + + .test-11 { + @layer { + & { + background-color: green !important; + } + } + } + + .test-12 { + @scope (.test-12) { + :scope { + background-color: green; + } + } + } + + div { + container-type: inline-size; + } + .test-13 { + @container (width >= 0px) { + & { + 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 class="test test-6"></div> + <div class="test test-10"></div> + <div class="test test-11"></div> + <div class="test test-12"></div> + <div class="test"><div class="test-13"></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..b5bd80d1b4 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/cssom.html @@ -0,0 +1,187 @@ +<!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'); + }); + + // We cannot insert anything starting with an tag, as that would cause + // the serialized rule not to parse back. Compounds starting with a tag + // that are _not_ the first compound in a complex selector are OK, though, + // as are complex selectors that are not the first in the list. + test(() => { + document.getElementById('ss').innerHTML = sampleSheetText; + let [ss] = document.styleSheets; + ss.cssRules[0].cssRules[0].selectorText = 'div.b .c &'; // Ignored. + ss.cssRules[0].cssRules[1].selectorText = '.c div.b &, div &'; // Allowed. + assert_throws_dom('SyntaxError', () => { ss.cssRules[0].insertRule('div & {}'); }); + assert_equals(ss.cssRules[0].cssText, +`.a { + color: red; + & .b { color: green; } + .c div.b &, div & { color: blue; } +}`, 'one rule is kept unchanged, the other is changed'); + }); + + // Rules that are dropped in forgiving parsing but that contain &, + // must still be serialized out as they were. + test(() => { + const text = '.a { :is(!& .foo, .b) { color: green; } }'; + document.getElementById('ss').innerHTML = text; + let [ss] = document.styleSheets; + assert_equals(ss.cssRules[0].cssText, +`.a { + :is(!& .foo, .b) { color: green; } +}`, 'invalid rule containing ampersand is kept in serialization'); + }); + + test((t) => { + let main = document.createElement('main'); + main.innerHTML = ` + <style> + .a { + & { z-index:1; } + & #inner1 { z-index:1; } + .stuff, :is(&) #inner2 { z-index:1; } + } + </style> + <div id="outer" class="b"> + <div id="inner1"></div> + <div id="inner2"></div> + </div> + `; + document.documentElement.append(main); + t.add_cleanup(() => main.remove()); + + assert_equals(getComputedStyle(outer).zIndex, 'auto'); + assert_equals(getComputedStyle(inner1).zIndex, 'auto'); + assert_equals(getComputedStyle(inner2).zIndex, 'auto'); + + // .a => .b + main.firstElementChild.sheet.cssRules[0].selectorText = '.b'; + + assert_equals(getComputedStyle(outer).zIndex, '1'); + assert_equals(getComputedStyle(inner1).zIndex, '1'); + assert_equals(getComputedStyle(inner2).zIndex, '1'); + }, 'Mutating the selectorText of outer rule invalidates inner rules'); +</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..0057a67fd0 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ref.html @@ -0,0 +1,27 @@ +<!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: 30px; + height: 30px; + 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> +</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..0a76dedc5b --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting.html @@ -0,0 +1,82 @@ +<!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: 30px; + height: 30px; + 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-5 { + :is(.test-5, &.does-not-exist) { + background-color: green; + } + } + + .test-6 { + > .foo,.test-6-child,+ .bar { + background-color: green; + } + } + + .test-7 { + > .foo, .bar, + .test-7-sibling { + background-color: green; + } + } + + .test-8 { + > .foo, .test-8-child, + .bar { + 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 class="test-5"></div></div> + <div class="test test-6"><div class="test-6-child"></div></div> + <div class="test test-7" style="display:none"></div><div class="test test-7-sibling"></div> + <div class="test test-8"><div class="test-8-child"></div></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..ffb53420e2 --- /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. */ + @font-face { + &.a { font-size: 10px; } + } + + @media screen { + &.a { color: red; } + + /* Same. */ + @font-face { + &.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('@font-face {}', 0); }); + assert_throws_dom('HierarchyRequestError', + () => { ss.cssRules[0].insertRule('@font-face {}', 0); }); + + // The @font-face 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/nest-containing-forgiving-ref.html b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving-ref.html new file mode 100644 index 0000000000..36b07c92b6 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving-ref.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>Nest-containing in forgiving parsing</title> +<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> +</body> diff --git a/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving.html b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving.html new file mode 100644 index 0000000000..d399142f7e --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Nest-containing in forgiving parsing</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="nest-containing-forgiving-ref.html"> +<style> + .test { + background-color: red; + width: 100px; + height: 100px; + display: grid; + } + + .does-not-exist { + :is(.test-1, !&) { + 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> +</body> 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..8038f369cd --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nesting-basic-ref.html @@ -0,0 +1,30 @@ +<!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: 30px; + height: 30px; + 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> + <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..19ff48e4a2 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nesting-basic.html @@ -0,0 +1,112 @@ +<!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: 30px; + height: 30px; + 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; + } + + /* & at top level counts as :scope, i.e. the root element here */ + & .test-12 { + background-color: green; + } + & > .test-12 { + background-color: red !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> + <div class="test test-12"></div> +</body> diff --git a/testing/web-platform/tests/css/css-nesting/nesting-type-selector.html b/testing/web-platform/tests/css/css-nesting/nesting-type-selector.html new file mode 100644 index 0000000000..1805896b8d --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nesting-type-selector.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Nesting works with bare type selectors</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-nesting-1/"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<style> +:root { + div { + width: 100px; + height: 100px; + background: green; + } +} +</style> +<p>Test passes if there is a filled green square.</p> +<div></div> 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..c22eaada3c --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/parsing.html @@ -0,0 +1,47 @@ +<!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 > .bar { color: green; }\n}`, + `.foo {\n > & .bar { color: green; }\n}`, + `.foo {\n + .bar & { color: green; }\n}`, + `.foo {\n .test > & .bar { color: green; }\n}`, + `.foo {\n + .bar, .foo, > .lol { 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) { 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> diff --git a/testing/web-platform/tests/css/css-nesting/supports-is-consistent-ref.html b/testing/web-platform/tests/css/css-nesting/supports-is-consistent-ref.html new file mode 100644 index 0000000000..0eb8cd16a1 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/supports-is-consistent-ref.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<title>@supports needs to be consistent with actual nesting support</title> +<body> + <p>Test passes if this text is not red</p> +</body> diff --git a/testing/web-platform/tests/css/css-nesting/supports-is-consistent.html b/testing/web-platform/tests/css/css-nesting/supports-is-consistent.html new file mode 100644 index 0000000000..8be0d666d6 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/supports-is-consistent.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>@supports needs to be consistent with actual nesting support</title> +<link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org"> +<link rel="help" href="https://crbug.com/1414012"> +<link rel="match" href="supports-is-consistent-ref.html"> +<style> + /* This test is expected to pass even if the browser does not support nesting. */ + @supports selector(&) { + p { + color: red; + & { color: inherit; } + } + } +</style> +<body> + <p>Test passes if this text is not red</p> +</body> diff --git a/testing/web-platform/tests/css/css-nesting/top-level-is-scope.html b/testing/web-platform/tests/css/css-nesting/top-level-is-scope.html new file mode 100644 index 0000000000..fefc77d5d0 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/top-level-is-scope.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>Top-level & is treated like :scope</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> + +<div id="p"> + <div class="match" id="level1"> + <div class="match" id="level2"></div> + </div> +</div> + +<script> + test(() => { + let matched = []; + for (const elem of p.querySelectorAll('& .match')) { + matched.push(elem.getAttribute('id')); + } + assert_array_equals(matched, ['level1', 'level2']); + }, '& as direct ancestor'); + + test(() => { + let matched = []; + for (const elem of p.querySelectorAll('& > .match')) { + matched.push(elem.getAttribute('id')); + } + assert_array_equals(matched, ['level1']); + }, '& matches scoped element only, not everything'); +</script> |