mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +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: https://github.com/LadybirdBrowser/ladybird/commit/b0e79ce549b 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
|
||||
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…
Reference in a new issue