diff options
Diffstat (limited to 'testing/web-platform/tests/css/css-nesting')
36 files changed, 1429 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-nesting/WEB_FEATURES.yml b/testing/web-platform/tests/css/css-nesting/WEB_FEATURES.yml new file mode 100644 index 0000000000..297d31d99d --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: nesting + files: "**" 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..0172db645b --- /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 (&) { + :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 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/cssom.html b/testing/web-platform/tests/css/css-nesting/cssom.html new file mode 100644 index 0000000000..226fb791b5 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/cssom.html @@ -0,0 +1,188 @@ +<!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(() => { + assert_equals(CSSStyleRule.__proto__, CSSGroupingRule); + }, "CSSStyleRule is a CSSGroupingRule"); + + 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'); + }); + + test(() => { + document.getElementById('ss').innerHTML = sampleSheetText; + let [ss] = document.styleSheets; + ss.cssRules[0].cssRules[0].selectorText = 'div.b .c &'; // Allowed + ss.cssRules[0].cssRules[1].selectorText = '.c div.b &, div &'; // Allowed. + ss.cssRules[0].insertRule('div & {}'); // Allowed. + assert_equals(ss.cssRules[0].cssText, +`.a { + color: red; + div & { } + div.b .c & { color: green; } + .c div.b &, div & { color: blue; } +}`, 'selectorText and insertRule'); + }); + + // 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/has-nesting-ref.html b/testing/web-platform/tests/css/css-nesting/has-nesting-ref.html new file mode 100644 index 0000000000..5ab79b68f1 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/has-nesting-ref.html @@ -0,0 +1,8 @@ +<!doctype html> +<title>Nested has shouldn't match</title> +<style> +ul { background: green } +</style> +<ul> + <li>Bar</li> +</ul> diff --git a/testing/web-platform/tests/css/css-nesting/has-nesting.html b/testing/web-platform/tests/css/css-nesting/has-nesting.html new file mode 100644 index 0000000000..83fe720236 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/has-nesting.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>Nested has shouldn't match</title> +<link rel="help" href="https://drafts.csswg.org/selectors/#relational"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1864647"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9600"> +<link rel="match" href="has-nesting-ref.html"> +<style> +ul { background: green } + +li:has(strong) { + display: none; + + :has(> &) { + background: red; + } +} +</style> +<ul> + <li><strong>Foo</strong></li> + <li>Bar</li> +</ul> diff --git a/testing/web-platform/tests/css/css-nesting/host-nesting-001.html b/testing/web-platform/tests/css/css-nesting/host-nesting-001.html new file mode 100644 index 0000000000..a166efeac5 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/host-nesting-001.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>:host and nesting (basic) </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/#nest-selector"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="host"></div> +<script> + host.attachShadow({mode: "open"}).innerHTML = ` + <style> + :host { + .nested { + width: 100px; + height: 100px; + background-color: green; + } + } + </style> + <div class="nested"></div> + `; +</script> diff --git a/testing/web-platform/tests/css/css-nesting/host-nesting-002.html b/testing/web-platform/tests/css/css-nesting/host-nesting-002.html new file mode 100644 index 0000000000..8f087c4128 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/host-nesting-002.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<title>:host and nesting (bare declarations)</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/#nest-selector"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="host"></div> +<script> + host.attachShadow({mode: "open"}).innerHTML = ` + <style> + :host { + @media (width >= 0) { + width: 100px; + height: 100px; + background-color: green; + } + } + </style> + `; +</script> diff --git a/testing/web-platform/tests/css/css-nesting/host-nesting-003.html b/testing/web-platform/tests/css/css-nesting/host-nesting-003.html new file mode 100644 index 0000000000..f9830b4fb6 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/host-nesting-003.html @@ -0,0 +1,26 @@ +<!doctype html> +<meta charset="utf-8"> +<title>:host and nesting (combined with something else)</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/#nest-selector"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="host"></div> +<script> + host.attachShadow({mode: "open"}).innerHTML = ` + <style> + .nested { + width: 100px; + height: 100px; + background-color: green; + } + :host(#not-host), #host { + .nested { + background-color: red; + } + } + </style> + <div class="nested"></div> + `; +</script> diff --git a/testing/web-platform/tests/css/css-nesting/host-nesting-004.html b/testing/web-platform/tests/css/css-nesting/host-nesting-004.html new file mode 100644 index 0000000000..8b84720075 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/host-nesting-004.html @@ -0,0 +1,25 @@ +<!doctype html> +<meta charset="utf-8"> +<title>:host and nesting (combined with something else, bare declarations)</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/#nest-selector"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="host"></div> +<script> + host.attachShadow({mode: "open"}).innerHTML = ` + <style> + :host { + width: 100px; + height: 100px; + background-color: green; + } + :host(#not-host), #host { + @media (width >= 0) { + background-color: red; + } + } + </style> + `; +</script> diff --git a/testing/web-platform/tests/css/css-nesting/host-nesting-005.html b/testing/web-platform/tests/css/css-nesting/host-nesting-005.html new file mode 100644 index 0000000000..ca5449825a --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/host-nesting-005.html @@ -0,0 +1,24 @@ +<!doctype html> +<meta charset="utf-8"> +<title>:host and nesting (with pseudos)</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/#nest-selector"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="host"></div> +<script> + host.attachShadow({mode: "open"}).innerHTML = ` + <style> + :host { + &::before { + display: block; + content: ""; + width: 100px; + height: 100px; + background-color: green; + } + } + </style> + `; +</script> diff --git a/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident-recovery.html b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident-recovery.html new file mode 100644 index 0000000000..f3648324ce --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident-recovery.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>CSS Nesting: Nesting, error recovery</title> +<link rel="help" href="https://drafts.csswg.org/css-nesting-1/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #target1 { + display:block; + display:new-block; + color:green; + } + #target2 { + display:block; + display:hover {}; + color:green; + } +</style> +<div id=target1>Green</div> +<div id=target2>Green</div> +<script> + test(() => { + assert_equals(getComputedStyle(target1).color, 'rgb(0, 128, 0)'); + }, 'Unknown declaration does not consume subsequent declaration'); +</script> +<script> + test(() => { + assert_equals(getComputedStyle(target2).color, 'rgb(0, 128, 0)'); + }, 'Unknown declaration with blocks does not consume subsequent declaration'); +</script> diff --git a/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident.html b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident.html new file mode 100644 index 0000000000..d6d06b9b31 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/implicit-nesting-ident.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<title>CSS Nesting: Implicit nesting (ident)</title> +<link rel="help" href="https://drafts.csswg.org/css-nesting-1/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #main { + div { + color: green; + } + } +</style> +<div id=main> + <div id=target> + Green + </div> +</main> +<script> + test(() => { + assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)'); + }, 'Nested rule starting with tag'); +</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..87c7c9a934 --- /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 @font-face 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..8fb7c8674a --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving-ref.html @@ -0,0 +1,19 @@ +<!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> + <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..561b5a3af5 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nest-containing-forgiving.html @@ -0,0 +1,34 @@ +<!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; + } + } + + .does-not-exist { + :is(.test-2, :unknown(div,&)) { + 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 class="test test-2"></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-layer.html b/testing/web-platform/tests/css/css-nesting/nesting-layer.html new file mode 100644 index 0000000000..91db883059 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/nesting-layer.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<title>Nested @layers</title> +<link rel="help" href="https://drafts.csswg.org/css-nesting/#nested-group-rules"> +<link rel="help" href="https://drafts.csswg.org/css-cascade-5/#layering"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + + .a { + /* This should have no effect. Only at-rules containing style rules + are vaild when nested. */ + @layer theme, base; + } + + /* The theme layer wins over the base layer. */ + @layer base, theme; + + .a { + @layer theme { + & { + z-index: 1; + } + + .b { + background-color: green; + } + } + } + + @layer base { + .a { + z-index: 0; + } + .a .b { + background-color: red; + } + } +</style> +<main> + <div class="a"> + <div class="b"> + </div> + </div> +</main> +<script> + test(() => { + let a = document.querySelector("main > .a"); + let b = document.querySelector("main > .a > .b"); + assert_equals(getComputedStyle(a).zIndex, "1"); + assert_equals(getComputedStyle(b).backgroundColor, "rgb(0, 128, 0)"); + }, '@layer can be nested'); +</script> 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..f29eff9730 --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/parsing.html @@ -0,0 +1,86 @@ +<!doctype html> +<title>CSS Selectors parsing</title> +<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com"> +<link rel="author" title="Tab Atkins-Bittner" href="https://tabatkins.com/contact/"> +<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 + + function resetStylesheet() { + while (ss.rules.length) + ss.removeRule(0) + } + + function testNestedSelector(sel, {expected=sel, parent=".foo"}={}) { + resetStylesheet(); + const ruleText = `${parent} { ${sel} { color: green; }}` + test(()=>{ + ss.insertRule(ruleText); + assert_equals(ss.rules.length, 1, "Outer rule should exist."); + const rule = ss.rules[0]; + assert_equals(rule.cssRules.length, 1, "Inner rule should exist."); + const innerRule = rule.cssRules[0]; + assert_equals(innerRule.selectorText, expected, `Inner rule's selector should be "${expected}".`); + }, ruleText); + } + + function testInvalidNestingSelector(sel, {parent=".foo"}={}) { + resetStylesheet(); + const ruleText = `${parent} { ${sel} { color: green; }}` + test(()=>{ + ss.insertRule(ruleText); + assert_equals(ss.rules.length, 1, "Outer rule should exist."); + const rule = ss.rules[0]; + assert_equals(rule.cssRules.length, 0, "Inner rule should not exist."); + }, "INVALID: " + ruleText); + } + + // basic usage + testNestedSelector("&"); + testNestedSelector("&.bar"); + testNestedSelector("& .bar"); + testNestedSelector("& > .bar"); + + // relative selector + testNestedSelector("> .bar", {expected:"& > .bar"}); + testNestedSelector("> & .bar", {expected:"& > & .bar"}); + testNestedSelector("+ .bar &", {expected:"& + .bar &"}); + testNestedSelector("+ .bar, .foo, > .baz", {expected:"& + .bar, & .foo, & > .baz"}); + + // implicit relative (and not) + testNestedSelector(".foo", {expected:"& .foo"}); + testNestedSelector(".test > & .bar"); + testNestedSelector(".foo, .foo &", {expected:"& .foo, .foo &"}); + testNestedSelector(":is(.bar, .baz)", {expected:"& :is(.bar, .baz)"}); + testNestedSelector("&:is(.bar, .baz)"); + testNestedSelector(":is(.bar, &.baz)"); + testNestedSelector("&:is(.bar, &.baz)"); + + // Mixing nesting selector with other simple selectors + testNestedSelector("div&"); + testInvalidNestingSelector("&div"); // type selector must be first + testNestedSelector(".class&"); + testNestedSelector("&.class"); + testNestedSelector("[attr]&"); + testNestedSelector("&[attr]"); + testNestedSelector("#id&"); + testNestedSelector("&#id"); + testNestedSelector(":hover&"); + testNestedSelector("&:hover"); + testNestedSelector(":is(div)&"); + testNestedSelector("&:is(div)"); + + // Multiple nesting selectors + testNestedSelector("& .bar & .baz & .qux"); + testNestedSelector("&&"); + + // Selector list in inner rule + testNestedSelector("& > section, & > article"); + + // Selector list in both inner and outer rule. + testNestedSelector("& + .baz, &.qux", {parent:".foo, .bar"}); +</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.html b/testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.html new file mode 100644 index 0000000000..7e9aaafbeb --- /dev/null +++ b/testing/web-platform/tests/css/css-nesting/serialize-group-rules-with-decls.html @@ -0,0 +1,91 @@ +<!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, description) { + test(() => { + assert_equals(serialize(cssText), cssText, description); + }, description); + } + + function assert_becomes(cssText, serializedCssText, description) { + test(() => { + assert_equals(serialize(cssText), serializedCssText, description); + }, description); + } + + assert_unchanged( + "@media screen {\n div { color: red; background-color: green; }\n}", + "Declarations are serialized on one line, rules on two." + ) + + assert_becomes( + "div { @media screen { color: red; background-color: green; } }", + "div {\n @media screen {\n & { color: red; background-color: green; }\n}\n}", + "Mixed declarations/rules are on two lines." + ); + assert_becomes( + "div {\n @supports selector(&) { color: red; background-color: green; } &:hover { color: navy; } }", + "div {\n @supports selector(&) {\n & { color: red; background-color: green; }\n}\n &:hover { color: navy; }\n}", + "Implicit rule is serialized", + ); + + assert_unchanged("div {\n @media screen {\n & { color: red; }\n}\n}", "Implicit rule not removed"); + assert_becomes( + "div { @media screen { & { color: red; &:hover { } } }", + "div {\n @media screen {\n & {\n color: red;\n &:hover { }\n}\n}\n}", + "Implicit + empty hover rule" + ); + assert_becomes( + "div { @media screen { &.cls { color: red; } & { color: red; }", + "div {\n @media screen {\n &.cls { color: red; }\n & { color: red; }\n}\n}", + "Implicit like rule not in first position" + ); + assert_becomes( + "div { @media screen { & { color: red; } & { color: red; }", + "div {\n @media screen {\n & { color: red; }\n & { color: red; }\n}\n}", + "Two implicit-like rules" + ); + assert_becomes( + "div { @media screen { color: red; & { color: red; }", + "div {\n @media screen {\n & { color: red; }\n & { color: red; }\n}\n}", + "Implicit like rule after decls" + ); + assert_becomes( + "div { @media screen { color: red; & { color: blue; }", + "div {\n @media screen {\n & { color: red; }\n & { color: blue; }\n}\n}", + "Implicit like rule after decls, missing closing braces" + ); + assert_becomes( + "div { @media screen { &, p > & { color: blue; }", + "div {\n @media screen {\n &, p > & { color: blue; }\n}\n}", + "Implicit like rule with other selectors" + ); + + assert_becomes( + "div { & { color: red; } }", + "div {\n & { color: red; }\n}", + "Implicit-like rule in style rule" + ); + + // Empty rules (confusingly?) serialize different between style rules + // and conditional group rules. + assert_unchanged("@media screen {\n}", "Empty conditional rule"); + assert_unchanged("div { }", "Empty style rule"); + assert_unchanged("div {\n @media screen {\n}\n}", "Empty conditional inside style rule"); + assert_unchanged("@media screen {\n div { }\n}", "Empty style inside conditional"); +</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> |