mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-29 13:46:31 +00:00
Tests: Import all WPT css/css-nesting tests
A few are skipped for now: - A few ref tests fail - Crash tests are not supported by our runner and time out - top-level-is-scope.html crashes and needs further investigation
This commit is contained in:
parent
6bb1ffbcd3
commit
b0e79ce549
Notes:
github-actions[bot]
2024-11-07 14:12:28 +00:00
Author: https://github.com/AtkinsSJ
Commit: b0e79ce549
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2202
62 changed files with 2098 additions and 0 deletions
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>Nested has shouldn't match</title>
|
||||||
|
<style>
|
||||||
|
ul { background: green }
|
||||||
|
</style>
|
||||||
|
<ul>
|
||||||
|
<li>Bar</li>
|
||||||
|
</ul>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>@supports with nesting</title>
|
||||||
|
<link rel="author" title="Matthieu Dubet" href="mailto:m_dubet@apple.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>
|
||||||
|
</body>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
|
||||||
|
<p>Test passes if there is a filled green square.</p>
|
||||||
|
<div style="width:100px; height:100px; background:green;"></div>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -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="../../../../expected/wpt-import//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>
|
|
@ -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="../../../../expected/wpt-import/css/css-nesting/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>
|
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>@supports with nesting</title>
|
||||||
|
<link rel="author" title="Matthieu Dubet" href="mailto:m_dubet@apple.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
|
||||||
|
<link rel="match" href="../../../../expected/wpt-import/css/css-nesting/supports-rule-ref.html">
|
||||||
|
<style>
|
||||||
|
.test {
|
||||||
|
background-color: red;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports(not selector(> .test-1)) {
|
||||||
|
.test-1 {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.test {
|
||||||
|
> .test-2 {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
@supports (selector(> .test-2)) {
|
||||||
|
> .test-2 {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-3 {
|
||||||
|
@supports (selector(&)) {
|
||||||
|
& {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports(selector(&)) {
|
||||||
|
.test-4 {
|
||||||
|
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"><div class="test-2"></div></div>
|
||||||
|
<div class="test test-3"></div>
|
||||||
|
<div class="test test-4"></div>
|
||||||
|
</body>
|
|
@ -55,3 +55,18 @@ Text/input/wpt-import/html/infrastructure/safe-passing-of-structured-data/resour
|
||||||
|
|
||||||
; Flaky, apparently due to font loading
|
; Flaky, apparently due to font loading
|
||||||
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
||||||
|
|
||||||
|
; WPT ref-tests that currently fail
|
||||||
|
Ref/input/wpt-import/css/css-nesting/has-nesting.html
|
||||||
|
Ref/input/wpt-import/css/css-nesting/host-nesting-003.html
|
||||||
|
Ref/input/wpt-import/css/css-nesting/host-nesting-004.html
|
||||||
|
Ref/input/wpt-import/css/css-nesting/nest-containing-forgiving.html
|
||||||
|
|
||||||
|
; WPT crash tests are not supported yet - and probably should go in a separate directory
|
||||||
|
Text/input/wpt-import/css/css-nesting/delete-other-rule-crash.html
|
||||||
|
Text/input/wpt-import/css/css-nesting/implicit-parent-insertion-crash.html
|
||||||
|
Text/input/wpt-import/css/css-nesting/pseudo-part-crash.html
|
||||||
|
Text/input/wpt-import/css/css-nesting/pseudo-where-crash.html
|
||||||
|
|
||||||
|
; Currently crashes
|
||||||
|
Text/input/wpt-import/css/css-nesting/top-level-is-scope.html
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass CSS Nesting bug: Block ignored after lack of whitespace
|
|
@ -0,0 +1,12 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 2 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass Unknown declaration does not consume subsequent declaration
|
||||||
|
Pass Unknown declaration with blocks does not consume subsequent declaration
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass Nested rule starting with tag
|
|
@ -0,0 +1,12 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 2 tests
|
||||||
|
|
||||||
|
2 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Simple CSSOM manipulation of subrules
|
||||||
|
Fail Simple CSSOM manipulation of subrules 1
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass CSS Selectors nested invalidation on changed parent
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass CSS Selectors nested invalidation on changed child
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass CSS Selectors nested invalidation with :has()
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass CSS Selectors nested invalidation through @media by selectorText
|
|
@ -0,0 +1,12 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 2 tests
|
||||||
|
|
||||||
|
2 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Empty CSSNestedDeclarations do not affect outer serialization
|
||||||
|
Fail Empty CSSNestedDeclarations do not affect outer serialization (nested grouping rule)
|
|
@ -0,0 +1,23 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 12 tests
|
||||||
|
|
||||||
|
6 Pass
|
||||||
|
6 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Trailing declarations
|
||||||
|
Fail Mixed declarations
|
||||||
|
Fail CSSNestedDeclarations.style
|
||||||
|
Pass Nested group rule
|
||||||
|
Pass Nested @scope rule
|
||||||
|
Fail Inner rule starting with an ident
|
||||||
|
Fail Inserting a CSSNestedDeclaration rule into style rule Unable to parse CSS rule.
|
||||||
|
Fail Inserting a CSSNestedDeclaration rule into nested group rule Unable to parse CSS rule.
|
||||||
|
Pass Attempting to insert a CSSNestedDeclaration rule into top-level @media rule
|
||||||
|
Pass Attempting to insert a CSSNestedDeclaration rule into a stylesheet
|
||||||
|
Pass Attempting to insert a CSSNestedDeclaration rule, empty block
|
||||||
|
Pass Attempting to insert a CSSNestedDeclaration rule, all invalid declarations
|
|
@ -0,0 +1,21 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 11 tests
|
||||||
|
|
||||||
|
11 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Trailing declarations apply after any preceding rules
|
||||||
|
Fail Trailing declarations apply after any preceding rules (no leading)
|
||||||
|
Fail Trailing declarations apply after any preceding rules (multiple)
|
||||||
|
Fail Nested declarations rule has same specificity as outer selector
|
||||||
|
Fail Nested declarations rule has top-level specificity behavior
|
||||||
|
Fail Nested declarations rule has top-level specificity behavior (max matching)
|
||||||
|
Fail Bare declartaion in nested grouping rule can match pseudo-element
|
||||||
|
Fail Nested group rules have top-level specificity behavior
|
||||||
|
Fail Nested @scope rules behave like :where(:scope)
|
||||||
|
Fail Nested @scope rules behave like :where(:scope) (trailing)
|
||||||
|
Fail Nested declarations rule responds to parent selector text change
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Nested rule responds to parent selector text change
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass @layer can be nested
|
|
@ -0,0 +1,43 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 32 tests
|
||||||
|
|
||||||
|
31 Pass
|
||||||
|
1 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass .foo { & { color: green; }}
|
||||||
|
Pass .foo { &.bar { color: green; }}
|
||||||
|
Pass .foo { & .bar { color: green; }}
|
||||||
|
Pass .foo { & > .bar { color: green; }}
|
||||||
|
Pass .foo { > .bar { color: green; }}
|
||||||
|
Pass .foo { > & .bar { color: green; }}
|
||||||
|
Pass .foo { + .bar & { color: green; }}
|
||||||
|
Pass .foo { + .bar, .foo, > .baz { color: green; }}
|
||||||
|
Pass .foo { .foo { color: green; }}
|
||||||
|
Pass .foo { .test > & .bar { color: green; }}
|
||||||
|
Pass .foo { .foo, .foo & { color: green; }}
|
||||||
|
Pass .foo { .foo, .bar { color: green; }}
|
||||||
|
Pass .foo { :is(.bar, .baz) { color: green; }}
|
||||||
|
Pass .foo { &:is(.bar, .baz) { color: green; }}
|
||||||
|
Pass .foo { :is(.bar, &.baz) { color: green; }}
|
||||||
|
Pass .foo { &:is(.bar, &.baz) { color: green; }}
|
||||||
|
Pass .foo { div& { color: green; }}
|
||||||
|
Fail INVALID: .foo { &div { color: green; }}
|
||||||
|
Pass .foo { .class& { color: green; }}
|
||||||
|
Pass .foo { &.class { color: green; }}
|
||||||
|
Pass .foo { [attr]& { color: green; }}
|
||||||
|
Pass .foo { &[attr] { color: green; }}
|
||||||
|
Pass .foo { #id& { color: green; }}
|
||||||
|
Pass .foo { &#id { color: green; }}
|
||||||
|
Pass .foo { :hover& { color: green; }}
|
||||||
|
Pass .foo { &:hover { color: green; }}
|
||||||
|
Pass .foo { :is(div)& { color: green; }}
|
||||||
|
Pass .foo { &:is(div) { color: green; }}
|
||||||
|
Pass .foo { & .bar & .baz & .qux { color: green; }}
|
||||||
|
Pass .foo { && { color: green; }}
|
||||||
|
Pass .foo { & > section, & > article { color: green; }}
|
||||||
|
Pass .foo, .bar { & + .baz, &.qux { color: green; }}
|
|
@ -0,0 +1,26 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 15 tests
|
||||||
|
|
||||||
|
4 Pass
|
||||||
|
11 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Declarations are serialized on one line, rules on two.
|
||||||
|
Fail Mixed declarations/rules are on two lines.
|
||||||
|
Fail Implicit rule is serialized
|
||||||
|
Fail Implicit rule not removed
|
||||||
|
Fail Implicit + empty hover rule
|
||||||
|
Fail Implicit like rule not in first position
|
||||||
|
Fail Two implicit-like rules
|
||||||
|
Fail Implicit like rule after decls
|
||||||
|
Fail Implicit like rule after decls, missing closing braces
|
||||||
|
Fail Implicit like rule with other selectors
|
||||||
|
Fail Implicit-like rule in style rule
|
||||||
|
Pass Empty conditional rule
|
||||||
|
Pass Empty style rule
|
||||||
|
Pass Empty conditional inside style rule
|
||||||
|
Pass Empty style inside conditional
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail CSS Nesting: Specificity of top-level '&'
|
52
Tests/LibWeb/Text/input/wpt-import/common/gc.js
Normal file
52
Tests/LibWeb/Text/input/wpt-import/common/gc.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* Does a best-effort attempt at invoking garbage collection. Attempts to use
|
||||||
|
* the standardized `TestUtils.gc()` function, but falls back to other
|
||||||
|
* environment-specific nonstandard functions, with a final result of just
|
||||||
|
* creating a lot of garbage (in which case you will get a console warning).
|
||||||
|
*
|
||||||
|
* This should generally only be used to attempt to trigger bugs and crashes
|
||||||
|
* inside tests, i.e. cases where if garbage collection happened, then this
|
||||||
|
* should not trigger some misbehavior. You cannot rely on garbage collection
|
||||||
|
* successfully trigger, or that any particular unreachable object will be
|
||||||
|
* collected.
|
||||||
|
*
|
||||||
|
* @returns {Promise<undefined>} A promise you should await to ensure garbage
|
||||||
|
* collection has had a chance to complete.
|
||||||
|
*/
|
||||||
|
self.garbageCollect = async () => {
|
||||||
|
// https://testutils.spec.whatwg.org/#the-testutils-namespace
|
||||||
|
if (self.TestUtils?.gc) {
|
||||||
|
return TestUtils.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use --expose_gc for V8 (and Node.js)
|
||||||
|
// to pass this flag at chrome launch use: --js-flags="--expose-gc"
|
||||||
|
// Exposed in SpiderMonkey shell as well
|
||||||
|
if (self.gc) {
|
||||||
|
return self.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present in some WebKit development environments
|
||||||
|
if (self.GCController) {
|
||||||
|
return GCController.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
'Tests are running without the ability to do manual garbage collection. ' +
|
||||||
|
'They will still work, but coverage will be suboptimal.');
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; i++) {
|
||||||
|
gcRec(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gcRec(n) {
|
||||||
|
if (n < 1) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let temp = { i: "ab" + i + i / 100000 };
|
||||||
|
temp += "foo";
|
||||||
|
|
||||||
|
gcRec(n - 1);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
.test{span{color:red}span{color:green}}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There needs to be some text here, or the bug
|
||||||
|
* will not manifest for unrelated reasons.
|
||||||
|
*/
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>CSS Nesting bug: Block ignored after lack of whitespace</title>
|
||||||
|
<link rel="help" href="https://crbug.com/362674384">
|
||||||
|
<link rel="stylesheet" href="block-skipping.css"> <!-- Bug only manifests in external stylesheets. -->
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<div class="test">
|
||||||
|
<span id="target">Test passes if this text is green.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Nesting: CSSNestedDeclarations CSSOM (whitespace)</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-declarations-rule">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
// https://drafts.csswg.org/cssom/#serialize-a-css-rule
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
& { }
|
||||||
|
left: 1px;
|
||||||
|
& { }
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let a_rule = s.cssRules[0];
|
||||||
|
assert_equals(a_rule.cssRules.length, 4);
|
||||||
|
for (let child_rule of a_rule.cssRules) {
|
||||||
|
child_rule.style = '';
|
||||||
|
}
|
||||||
|
assert_equals(a_rule.cssText, '.a {\n & { }\n & { }\n}');
|
||||||
|
}, 'Empty CSSNestedDeclarations do not affect outer serialization');
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/cssom/#serialize-a-css-rule
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
@media (width > 1px) {
|
||||||
|
& { }
|
||||||
|
left: 1px;
|
||||||
|
& { }
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 1);
|
||||||
|
|
||||||
|
// @media
|
||||||
|
let media = outer.cssRules[0];
|
||||||
|
assert_equals(media.cssRules.length, 4);
|
||||||
|
for (let child_rule of media.cssRules) {
|
||||||
|
child_rule.style = '';
|
||||||
|
}
|
||||||
|
assert_equals(media.cssText, '@media (width > 1px) {\n & { }\n & { }\n}');
|
||||||
|
}, 'Empty CSSNestedDeclarations do not affect outer serialization (nested grouping rule)');
|
||||||
|
</script>
|
|
@ -0,0 +1,237 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Nesting: CSSNestedDeclarations CSSOM</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-declarations-rule">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
& { --x:1; }
|
||||||
|
--x:2;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 2);
|
||||||
|
assert_equals(outer.cssRules[0].cssText, `& { --x: 1; }`);
|
||||||
|
assert_equals(outer.cssRules[1].cssText, `--x: 2;`);
|
||||||
|
}, 'Trailing declarations');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
--a:1;
|
||||||
|
--b:1;
|
||||||
|
& { --c:1; }
|
||||||
|
--d:1;
|
||||||
|
--e:1;
|
||||||
|
& { --f:1; }
|
||||||
|
--g:1;
|
||||||
|
--h:1;
|
||||||
|
--i:1;
|
||||||
|
& { --j:1; }
|
||||||
|
--k:1;
|
||||||
|
--l:1;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 6);
|
||||||
|
assert_equals(outer.cssRules[0].cssText, `& { --c: 1; }`);
|
||||||
|
assert_equals(outer.cssRules[1].cssText, `--d: 1; --e: 1;`);
|
||||||
|
assert_equals(outer.cssRules[2].cssText, `& { --f: 1; }`);
|
||||||
|
assert_equals(outer.cssRules[3].cssText, `--g: 1; --h: 1; --i: 1;`);
|
||||||
|
assert_equals(outer.cssRules[4].cssText, `& { --j: 1; }`);
|
||||||
|
assert_equals(outer.cssRules[5].cssText, `--k: 1; --l: 1;`);
|
||||||
|
}, 'Mixed declarations');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
& { --x:1; }
|
||||||
|
--y:2;
|
||||||
|
--z:3;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 2);
|
||||||
|
let nested_declarations = outer.cssRules[1];
|
||||||
|
assert_true(nested_declarations instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(nested_declarations.style.length, 2);
|
||||||
|
assert_equals(nested_declarations.style.getPropertyValue('--x'), '');
|
||||||
|
assert_equals(nested_declarations.style.getPropertyValue('--y'), '2');
|
||||||
|
assert_equals(nested_declarations.style.getPropertyValue('--z'), '3');
|
||||||
|
}, 'CSSNestedDeclarations.style');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
@media (width > 100px) {
|
||||||
|
--x:1;
|
||||||
|
--y:1;
|
||||||
|
.b { }
|
||||||
|
--z:1;
|
||||||
|
}
|
||||||
|
--w:1;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 2);
|
||||||
|
|
||||||
|
// @media
|
||||||
|
let media = outer.cssRules[0];
|
||||||
|
assert_equals(media.cssRules.length, 3);
|
||||||
|
assert_true(media.cssRules[0] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(media.cssRules[0].cssText, `--x: 1; --y: 1;`);
|
||||||
|
assert_equals(media.cssRules[1].cssText, `& .b { }`);
|
||||||
|
assert_true(media.cssRules[2] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(media.cssRules[2].cssText, `--z: 1;`);
|
||||||
|
|
||||||
|
assert_true(outer.cssRules[1] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(outer.cssRules[1].cssText, `--w: 1;`);
|
||||||
|
}, 'Nested group rule');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
.a {
|
||||||
|
@scope (.foo) {
|
||||||
|
--x:1;
|
||||||
|
--y:1;
|
||||||
|
.b { }
|
||||||
|
--z:1;
|
||||||
|
}
|
||||||
|
--w:1;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
if (window.CSSScopeRule) {
|
||||||
|
assert_equals(outer.cssRules.length, 2);
|
||||||
|
|
||||||
|
// @scope
|
||||||
|
let scope = outer.cssRules[0];
|
||||||
|
assert_true(scope instanceof CSSScopeRule);
|
||||||
|
assert_equals(scope.cssRules.length, 3);
|
||||||
|
assert_true(scope.cssRules[0] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(scope.cssRules[0].cssText, `--x: 1; --y: 1;`);
|
||||||
|
assert_equals(scope.cssRules[1].cssText, `.b { }`); // Implicit :scope here.
|
||||||
|
assert_true(scope.cssRules[2] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(scope.cssRules[2].cssText, `--z: 1;`);
|
||||||
|
|
||||||
|
assert_true(outer.cssRules[1] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(outer.cssRules[1].cssText, `--w: 1;`);
|
||||||
|
} else {
|
||||||
|
assert_equals(outer.cssRules.length, 0);
|
||||||
|
}
|
||||||
|
}, 'Nested @scope rule');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync(`
|
||||||
|
a {
|
||||||
|
& { --x:1; }
|
||||||
|
width: 100px;
|
||||||
|
height: 200px;
|
||||||
|
color:hover {}
|
||||||
|
--y: 2;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let outer = s.cssRules[0];
|
||||||
|
assert_equals(outer.cssRules.length, 4);
|
||||||
|
assert_equals(outer.cssRules[0].cssText, `& { --x: 1; }`);
|
||||||
|
assert_equals(outer.cssRules[1].cssText, `width: 100px; height: 200px;`);
|
||||||
|
assert_equals(outer.cssRules[2].cssText, `& color:hover { }`);
|
||||||
|
assert_equals(outer.cssRules[3].cssText, `--y: 2;`);
|
||||||
|
}, 'Inner rule starting with an ident');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync('.a {}');
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let a_rule = s.cssRules[0];
|
||||||
|
assert_equals(a_rule.cssRules.length, 0);
|
||||||
|
a_rule.insertRule(`
|
||||||
|
width: 100px;
|
||||||
|
height: 200px;
|
||||||
|
`);
|
||||||
|
assert_equals(a_rule.cssRules.length, 1);
|
||||||
|
assert_true(a_rule.cssRules[0] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(a_rule.cssRules[0].cssText, `width: 100px; height: 200px;`);
|
||||||
|
}, 'Inserting a CSSNestedDeclaration rule into style rule');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync('.a { @media (width > 100px) {} }');
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
assert_equals(s.cssRules[0].cssRules.length, 1);
|
||||||
|
let media_rule = s.cssRules[0].cssRules[0];
|
||||||
|
assert_true(media_rule instanceof CSSMediaRule);
|
||||||
|
assert_equals(media_rule.cssRules.length, 0);
|
||||||
|
media_rule.insertRule(`
|
||||||
|
width: 100px;
|
||||||
|
height: 200px;
|
||||||
|
`);
|
||||||
|
assert_equals(media_rule.cssRules.length, 1);
|
||||||
|
assert_true(media_rule.cssRules[0] instanceof CSSNestedDeclarations);
|
||||||
|
assert_equals(media_rule.cssRules[0].cssText, `width: 100px; height: 200px;`);
|
||||||
|
}, 'Inserting a CSSNestedDeclaration rule into nested group rule');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync('@media (width > 100px) {}');
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let media_rule = s.cssRules[0];
|
||||||
|
assert_true(media_rule instanceof CSSMediaRule);
|
||||||
|
assert_equals(media_rule.cssRules.length, 0);
|
||||||
|
assert_throws_dom('SyntaxError', () => {
|
||||||
|
media_rule.insertRule(`
|
||||||
|
width: 100px;
|
||||||
|
height: 200px;
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}, 'Attempting to insert a CSSNestedDeclaration rule into top-level @media rule');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let sheet = new CSSStyleSheet();
|
||||||
|
assert_throws_dom('SyntaxError', () => {
|
||||||
|
sheet.insertRule(`
|
||||||
|
width: 100px;
|
||||||
|
height: 200px;
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}, 'Attempting to insert a CSSNestedDeclaration rule into a stylesheet');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync('.a {}');
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let a_rule = s.cssRules[0];
|
||||||
|
assert_equals(a_rule.cssRules.length, 0);
|
||||||
|
assert_throws_dom('SyntaxError', () => {
|
||||||
|
a_rule.insertRule('');
|
||||||
|
});
|
||||||
|
}, 'Attempting to insert a CSSNestedDeclaration rule, empty block');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let s = new CSSStyleSheet();
|
||||||
|
s.replaceSync('.a {}');
|
||||||
|
assert_equals(s.cssRules.length, 1);
|
||||||
|
let a_rule = s.cssRules[0];
|
||||||
|
assert_equals(a_rule.cssRules.length, 0);
|
||||||
|
assert_throws_dom('SyntaxError', () => {
|
||||||
|
a_rule.insertRule(`
|
||||||
|
xwidth: 100px;
|
||||||
|
xheight: 200px;
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}, 'Attempting to insert a CSSNestedDeclaration rule, all invalid declarations');
|
||||||
|
</script>
|
|
@ -0,0 +1,221 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Nesting: CSSNestedDeclarations matching</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-declarations-rule">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.trailing {
|
||||||
|
--x: FAIL;
|
||||||
|
& { --x: FAIL; }
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=trailing></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.trailing');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Trailing declarations apply after any preceding rules');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.trailing_no_leading {
|
||||||
|
& { --x: FAIL; }
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=trailing_no_leading></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.trailing_no_leading');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Trailing declarations apply after any preceding rules (no leading)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.trailing_multiple {
|
||||||
|
--x: FAIL;
|
||||||
|
--y: FAIL;
|
||||||
|
--z: FAIL;
|
||||||
|
--w: FAIL;
|
||||||
|
& { --x: FAIL; }
|
||||||
|
--x: PASS;
|
||||||
|
--y: PASS;
|
||||||
|
& { --z: FAIL; }
|
||||||
|
--z: PASS;
|
||||||
|
--w: PASS;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=trailing_multiple></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.trailing_multiple');
|
||||||
|
let s = getComputedStyle(e);
|
||||||
|
assert_equals(s.getPropertyValue('--x'), 'PASS');
|
||||||
|
assert_equals(s.getPropertyValue('--y'), 'PASS');
|
||||||
|
assert_equals(s.getPropertyValue('--z'), 'PASS');
|
||||||
|
assert_equals(s.getPropertyValue('--w'), 'PASS');
|
||||||
|
}, 'Trailing declarations apply after any preceding rules (multiple)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.trailing_specificity {
|
||||||
|
--x: FAIL;
|
||||||
|
:is(&, div.nomatch2) { --x: PASS; } /* Specificity: (0, 1, 1) */
|
||||||
|
--x: FAIL; /* Specificity: (0, 1, 0) */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=trailing_specificity></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.trailing_specificity');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested declarations rule has same specificity as outer selector');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#nomatch, .specificity_top_level {
|
||||||
|
--x: FAIL;
|
||||||
|
:is(&, div.nomatch2) { --x: PASS; } /* Specificity: (0, 1, 1) */
|
||||||
|
--x: FAIL; /* Specificity: (0, 1, 0). In particular, this does not have
|
||||||
|
specificity like :is(#nomatch, .specificity_top_level). */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=specificity_top_level></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.specificity_top_level');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested declarations rule has top-level specificity behavior');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#nomatch, .specificity_top_level_max, div.specificity_top_level_max {
|
||||||
|
--x: FAIL;
|
||||||
|
:is(:where(&), div.nomatch2) { --x: FAIL; } /* Specificity: (0, 1, 1) */
|
||||||
|
--x: PASS; /* Specificity: (0, 1, 1) (for div.specificity_top_level_max) */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=specificity_top_level_max></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.specificity_top_level_max');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested declarations rule has top-level specificity behavior (max matching)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nested_pseudo::after {
|
||||||
|
--x: FAIL;
|
||||||
|
@media (width > 0px) {
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=nested_pseudo></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.nested_pseudo');
|
||||||
|
assert_equals(getComputedStyle(e, '::after').getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Bare declartaion in nested grouping rule can match pseudo-element');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#nomatch, .nested_group_rule {
|
||||||
|
--x: FAIL;
|
||||||
|
@media (width > 0px) {
|
||||||
|
--x: FAIL; /* Specificity: (0, 1, 0) */
|
||||||
|
}
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=nested_group_rule></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.nested_group_rule');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested group rules have top-level specificity behavior');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nested_scope_rule {
|
||||||
|
div:where(&) { /* Specificity: (0, 0, 1) */
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
@scope (&) {
|
||||||
|
--x: FAIL; /* Specificity: (0, 0, 0) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=nested_scope_rule></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.nested_scope_rule');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested @scope rules behave like :where(:scope)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nested_scope_rule_trailing {
|
||||||
|
div:where(&) { /* Specificity: (0, 0, 1) */
|
||||||
|
--x: PASS;
|
||||||
|
}
|
||||||
|
@scope (&) {
|
||||||
|
--ignored: 1;
|
||||||
|
.ignored {}
|
||||||
|
--x: FAIL; /* Specificity: (0, 0, 0) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=nested_scope_rule_trailing></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let e = document.querySelector('.nested_scope_rule_trailing');
|
||||||
|
assert_equals(getComputedStyle(e).getPropertyValue('--x'), 'PASS');
|
||||||
|
}, 'Nested @scope rules behave like :where(:scope) (trailing)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style id=set_parent_selector_text_style>
|
||||||
|
.set_parent_selector_text {
|
||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.a1 {
|
||||||
|
.ignored {}
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=set_parent_selector_text>
|
||||||
|
<div class=a1>A1</div>
|
||||||
|
<div class=a2>A2</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let a1 = document.querySelector('.set_parent_selector_text > .a1');
|
||||||
|
let a2 = document.querySelector('.set_parent_selector_text > .a2');
|
||||||
|
assert_equals(getComputedStyle(a1).color, 'rgb(0, 128, 0)');
|
||||||
|
assert_equals(getComputedStyle(a2).color, 'rgb(255, 0, 0)');
|
||||||
|
|
||||||
|
let rules = set_parent_selector_text_style.sheet.cssRules;
|
||||||
|
assert_equals(rules.length, 1);
|
||||||
|
assert_equals(rules[0].cssRules.length, 2);
|
||||||
|
|
||||||
|
let a_rule = rules[0].cssRules[1];
|
||||||
|
assert_equals(a_rule.selectorText, '& .a1');
|
||||||
|
a_rule.selectorText = '.a2';
|
||||||
|
assert_equals(a_rule.selectorText, '& .a2');
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(a1).color, 'rgb(255, 0, 0)');
|
||||||
|
assert_equals(getComputedStyle(a2).color, 'rgb(0, 128, 0)');
|
||||||
|
}, 'Nested declarations rule responds to parent selector text change');
|
||||||
|
</script>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Nesting: Style invalidates after CSSOM mutations to nested rules</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-style-rule">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-group-rules">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<style id=set_parent_selector_text_style>
|
||||||
|
.set_parent_selector_text {
|
||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.a1 {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=set_parent_selector_text>
|
||||||
|
<div class=a1>A1</div>
|
||||||
|
<div class=a2>A2</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let a1 = document.querySelector('.set_parent_selector_text > .a1');
|
||||||
|
let a2 = document.querySelector('.set_parent_selector_text > .a2');
|
||||||
|
assert_equals(getComputedStyle(a1).color, 'rgb(0, 128, 0)');
|
||||||
|
assert_equals(getComputedStyle(a2).color, 'rgb(255, 0, 0)');
|
||||||
|
|
||||||
|
let rules = set_parent_selector_text_style.sheet.cssRules;
|
||||||
|
assert_equals(rules.length, 1);
|
||||||
|
assert_equals(rules[0].cssRules.length, 2);
|
||||||
|
|
||||||
|
let a_rule = rules[0].cssRules[1];
|
||||||
|
assert_equals(a_rule.selectorText, '& .a1');
|
||||||
|
a_rule.selectorText = '.a2';
|
||||||
|
|
||||||
|
assert_equals(getComputedStyle(a1).color, 'rgb(255, 0, 0)');
|
||||||
|
assert_equals(getComputedStyle(a2).color, 'rgb(0, 128, 0)');
|
||||||
|
}, 'Nested rule responds to parent selector text change');
|
||||||
|
</script>
|
||||||
|
|
|
@ -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>
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!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(".foo, .bar", {expected:"& .foo, & .bar"});
|
||||||
|
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>
|
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
.foo {
|
||||||
|
::before:where(&) {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class=foo></div>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Nesting: Specificity of top-level '&'</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-nesting-1">
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/10196">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<style>
|
||||||
|
/* Note: at the top level, '&' matches like ':root'. */
|
||||||
|
|
||||||
|
/* Should have zero specificity: */
|
||||||
|
& { color: red; }
|
||||||
|
/* Should also have zero specificity: */
|
||||||
|
:where(&) { color: green; }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
assert_equals(getComputedStyle(document.documentElement).color, 'rgb(0, 128, 0)');
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,2 @@
|
||||||
|
.a {}
|
||||||
|
.b { .c {} }
|
Loading…
Add table
Add a link
Reference in a new issue