summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-cascade/scope-invalidation.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/css/css-cascade/scope-invalidation.html
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-cascade/scope-invalidation.html')
-rw-r--r--testing/web-platform/tests/css/css-cascade/scope-invalidation.html782
1 files changed, 782 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-cascade/scope-invalidation.html b/testing/web-platform/tests/css/css-cascade/scope-invalidation.html
new file mode 100644
index 0000000000..d53257e894
--- /dev/null
+++ b/testing/web-platform/tests/css/css-cascade/scope-invalidation.html
@@ -0,0 +1,782 @@
+<!DOCTYPE html>
+<title>@scope - invalidation</title>
+<link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+function test_scope_invalidation(script_element, callback_fn, description) {
+ test((t) => {
+ // The provided <script> element must be an immedate subsequent sibling of
+ // a <template> element.
+ let template_element = script_element.previousElementSibling;
+ assert_equals(template_element.tagName, 'TEMPLATE');
+
+ t.add_cleanup(() => {
+ while (main.firstChild)
+ main.firstChild.remove()
+ });
+
+ main.append(template_element.content.cloneNode(true));
+
+ callback_fn();
+ }, description);
+}
+
+function assert_green(element) {
+ assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 128, 0)');
+}
+function assert_not_green(element) {
+ assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 0, 0)');
+}
+</script>
+<style>
+ main * {
+ background-color: black;
+ }
+</style>
+<main id=main>
+</main>
+
+<!-- Tests follow -->
+
+<template>
+ <style>
+ @scope (.a) {
+ span { background-color: green; }
+ }
+ </style>
+ <div>
+ <span></span>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let div = main.querySelector('div');
+ let span = main.querySelector('div > span');
+ assert_not_green(span);
+ div.classList.add('a');
+ assert_green(span);
+ div.classList.remove('a');
+ assert_not_green(span);
+}, 'Element becoming scope root');
+</script>
+
+<template>
+ <style>
+ @scope (.a, .b) {
+ span { background-color: green; }
+ }
+ </style>
+ <div>
+ <span></span>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let div = main.querySelector('div');
+ let span = main.querySelector('div > span');
+
+ // .a
+ assert_not_green(span);
+ div.classList.add('a');
+ assert_green(span);
+ div.classList.remove('a');
+ assert_not_green(span);
+
+ // .b
+ assert_not_green(span);
+ div.classList.add('b');
+ assert_green(span);
+ div.classList.remove('b');
+ assert_not_green(span);
+}, 'Element becoming scope root (selector list)');
+</script>
+
+<template>
+ <style>
+ @scope (.a) {
+ :scope { background-color: green; }
+ }
+ </style>
+ <div class=b></div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let b = main.querySelector('.b');
+ assert_not_green(b);
+ b.classList.add('a');
+ assert_green(b);
+ b.classList.remove('a');
+ assert_not_green(b);
+}, 'Element becoming scope root, with inner :scope rule');
+</script>
+
+<template>
+ <style>
+ @scope (.a) to (.b) {
+ span { background-color: green; }
+ }
+ </style>
+ <div class=a>
+ <div>
+ <span></span>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let inner_div = main.querySelector('.a > div');
+ let span = main.querySelector('.a > div > span');
+ assert_green(span);
+ inner_div.classList.add('b');
+ assert_not_green(span);
+ inner_div.classList.remove('b');
+ assert_green(span);
+}, 'Parent element becoming scope limit');
+</script>
+
+<template>
+ <style>
+ @scope (.a) to (.b, .c) {
+ span { background-color: green; }
+ }
+ </style>
+ <div class=a>
+ <div>
+ <span></span>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let inner_div = main.querySelector('.a > div');
+ let span = main.querySelector('.a > div > span');
+
+ // .b
+ assert_green(span);
+ inner_div.classList.add('b');
+ assert_not_green(span);
+ inner_div.classList.remove('b');
+ assert_green(span);
+
+ // .c
+ assert_green(span);
+ inner_div.classList.add('c');
+ assert_not_green(span);
+ inner_div.classList.remove('c');
+ assert_green(span);
+}, 'Parent element becoming scope limit (selector list)');
+</script>
+
+<template>
+ <style>
+ @scope (.a) to (.b) {
+ span { background-color: green; }
+ }
+ </style>
+ <div class=a>
+ <div>
+ <span></span>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let span = main.querySelector('.a > div > span');
+ assert_green(span);
+ span.classList.add('b');
+ assert_not_green(span);
+ span.classList.remove('b');
+ assert_green(span);
+}, 'Subject element becoming scope limit');
+</script>
+
+<template>
+ <style>
+ @scope (.a) to (.b .c) {
+ span { background-color: green; }
+ }
+ </style>
+ <div class=a>
+ <div>
+ <div class=c>
+ <span></span>
+ </div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let intermediate_div = main.querySelector('.a > div');
+ let span = main.querySelector('span');
+ assert_green(span);
+ intermediate_div.classList.add('b');
+ assert_not_green(span);
+ intermediate_div.classList.remove('b');
+ assert_green(span);
+}, 'Parent element affecting scope limit');
+</script>
+
+<template>
+ <style>
+ @scope (.a) to (.b ~ .c) {
+ span { background-color: green; }
+ }
+ </style>
+ <div class=a>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div class=c>
+ <span></span>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let sibling_div = main.querySelector('.a > div');
+ let span = main.querySelector('span');
+ assert_green(span);
+ sibling_div.classList.add('b');
+ assert_not_green(span);
+ sibling_div.classList.remove('b');
+ assert_green(span);
+}, 'Sibling element affecting scope limit');
+</script>
+
+<template>
+ <style>
+ @scope (.a) {
+ @scope (.b) {
+ span { background-color: green; }
+ }
+ }
+ </style>
+ <div>
+ <div>
+ <span></span>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let outer_div = main.querySelector(':scope > div');
+ let inner_div = main.querySelector(':scope > div > div');
+ let span = main.querySelector('div > div > span');
+
+ assert_not_green(span);
+
+ outer_div.classList.add('a');
+ assert_not_green(span);
+
+ inner_div.classList.add('b');
+ assert_green(span);
+
+ // Toggle .b while .a remains.
+ inner_div.classList.remove('b');
+ assert_not_green(span);
+ inner_div.classList.add('b');
+ assert_green(span);
+
+ // Toggle .a while .b remains.
+ outer_div.classList.remove('a');
+ assert_not_green(span);
+ outer_div.classList.add('a');
+ assert_green(span);
+}, 'Toggling inner/outer scope roots');
+</script>
+
+
+<template>
+ <style>
+ @scope (.a) {
+ :scope { background-color:green; }
+ }
+ </style>
+ <div></div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let div = main.querySelector('main > div');
+ assert_not_green(div);
+ div.classList.add('a');
+ assert_green(div);
+ div.classList.remove('a');
+ assert_not_green(div);
+}, 'Element becoming root, with :scope in subject');
+</script>
+
+
+<template>
+ <style>
+ @scope (.a:has(.c)) {
+ .b { background-color:green; }
+ }
+ </style>
+ <div class=a>
+ <div class=b>
+ <div></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let b = main.querySelector('.b');
+ let innermost = main.querySelector('.b > div');
+ assert_not_green(b);
+ innermost.classList.add('c');
+ assert_green(b);
+ innermost.classList.remove('c');
+ assert_not_green(b);
+}, 'Scope root with :has()');
+</script>
+
+
+<template>
+ <style>
+ @scope (.a:has(.c)) {
+ :scope { background-color:green; }
+ }
+ </style>
+ <div class=a>
+ <div class=b>
+ <div></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let a = main.querySelector('.a');
+ let innermost = main.querySelector('.b > div');
+ assert_not_green(a);
+ innermost.classList.add('c');
+ assert_green(a);
+ innermost.classList.remove('c');
+ assert_not_green(a);
+}, 'Scope root with :has(), :scope subject');
+</script>
+
+
+<template>
+ <style>
+ @scope (.a:has(.c)) {
+ :scope { background-color:green; }
+ :scope .b { background-color:green; }
+ }
+ </style>
+ <div class=a>
+ <div class=b>
+ <div></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let a = main.querySelector('.a');
+ let b = main.querySelector('.b');
+ let innermost = main.querySelector('.b > div');
+ assert_not_green(a);
+ assert_not_green(b);
+ innermost.classList.add('c');
+ assert_green(a);
+ assert_green(b);
+ innermost.classList.remove('c');
+ assert_not_green(a);
+ assert_not_green(b);
+}, 'Scope root with :has(), :scope both subject and non-subject');
+</script>
+
+
+<template>
+ <style>
+ @scope (.a) to (.b:has(.c)) {
+ .b { background-color:green; }
+ }
+ </style>
+ <div class=a>
+ <div class=b>
+ <div></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let b = main.querySelector('.b');
+ let innermost = main.querySelector('.b > div');
+ assert_green(b);
+ innermost.classList.add('c');
+ assert_not_green(b);
+ innermost.classList.remove('c');
+ assert_green(b);
+}, 'Scope limit with :has()');
+</script>
+
+<template>
+ <style>
+ @scope (.a) {
+ .b ~ :scope { background-color:green; }
+ }
+ </style>
+ <div></div>
+ <div></div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let div1 = main.querySelector('main > div:nth-of-type(1)');
+ let div2 = main.querySelector('main > div:nth-of-type(2)');
+
+ assert_not_green(div2);
+ div1.classList.add('b');
+ assert_not_green(div2);
+ div2.classList.add('a');
+ assert_green(div2);
+ div1.classList.remove('b');
+ assert_not_green(div2);
+}, 'Element becoming root, with :scope selected by ~ combinator');
+</script>
+
+<template>
+ <style>
+ @scope (.a ~ .b) {
+ .c { background-color:green; }
+ }
+ </style>
+ <div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div class=b>
+ <div class=c></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('div > div:first-child');
+ let c = main.querySelector('.c');
+ assert_not_green(c);
+ root.classList.add('a');
+ assert_green(c);
+ root.classList.remove('a');
+ assert_not_green(c);
+}, 'Element becoming root via ~ combinator');
+</script>
+
+<template>
+ <style>
+ @scope (.a + .b) {
+ .c { background-color:green; }
+ }
+ </style>
+ <div>
+ <div></div>
+ <div class=b>
+ <div class=c></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('div > div:first-child');
+ let c = main.querySelector('.c');
+ assert_not_green(c);
+ root.classList.add('a');
+ assert_green(c);
+ root.classList.remove('a');
+ assert_not_green(c);
+}, 'Element becoming root via + combinator');
+</script>
+
+<template>
+ <style>
+ @scope (.root) {
+ :not(:scope) { background-color:green; }
+ }
+ </style>
+ <div class=root>
+ <div class=a></div>
+ <div class=b></div>
+ <div class=c></div>
+ </div>
+ <div class=a></div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('.root');
+ let a1 = main.querySelector('.root > .a');
+ let b = main.querySelector('.root > .b');
+ let c = main.querySelector('.root > .c');
+ let a2 = main.querySelector('main > .a');
+
+ assert_not_green(root);
+ assert_green(a1);
+ assert_green(b);
+ assert_green(c);
+ assert_not_green(a2);
+
+ root.classList.remove('root');
+ assert_not_green(root);
+ assert_not_green(a1);
+ assert_not_green(b);
+ assert_not_green(c);
+ assert_not_green(a2);
+
+ root.classList.add('root');
+ assert_not_green(root);
+ assert_green(a1);
+ assert_green(b);
+ assert_green(c);
+ assert_not_green(a2);
+}, ':not(scope) in subject');
+</script>
+
+<template>
+ <style>
+ @scope (.root) {
+ :not(:scope) > .a { background-color:green; }
+ }
+ </style>
+ <div class=root>
+ <div class=a></div>
+ <div>
+ <div class=a></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('.root');
+ let outer_a = main.querySelector('.root > .a');
+ let inner_a = main.querySelector('.root > div > .a');
+
+ assert_not_green(outer_a);
+ assert_green(inner_a);
+
+ root.classList.remove('root');
+ assert_not_green(outer_a);
+ assert_not_green(inner_a);
+
+ root.classList.add('root');
+ assert_not_green(outer_a);
+ assert_green(inner_a);
+}, ':not(scope) in ancestor');
+</script>
+
+<template>
+ <style>
+ @scope (.root) to (:not(:scope)) {
+ :is(div, :scope) { background-color: green; }
+ }
+ </style>
+ <div class=root>
+ <div class=a></div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('.root');
+ let a = main.querySelector('.root > .a');
+
+ assert_green(root);
+ assert_not_green(a);
+
+ root.classList.remove('root');
+ assert_not_green(root);
+ assert_not_green(a);
+
+ root.classList.add('root');
+ assert_green(root);
+ assert_not_green(a);
+}, ':not(scope) in limit subject');
+</script>
+
+<template>
+ <style>
+ @scope (.root) to (:not(:scope) > .a) {
+ :is(div, :scope) { background-color: green; }
+ }
+ </style>
+ <div class=root>
+ <div class=a>
+ <div class=a></div>
+ </div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let root = main.querySelector('.root');
+ let outer_a = main.querySelector('.root > .a');
+ let inner_a = main.querySelector('.root > .a > .a');
+
+ assert_green(root);
+ assert_green(outer_a);
+ assert_not_green(inner_a);
+
+ root.classList.remove('root');
+ assert_not_green(root);
+ assert_not_green(outer_a);
+ assert_not_green(inner_a);
+
+ root.classList.add('root');
+ assert_green(root);
+ assert_green(outer_a);
+ assert_not_green(inner_a);
+}, ':not(scope) in limit ancestor');
+</script>
+
+<template>
+ <style>
+ @scope (:nth-child(2n of .a)) {
+ :scope { background-color: green; }
+ }
+ </style>
+ <div id=wrapper>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let e = main.querySelectorAll('#wrapper > div');
+ assert_equals(e.length, 8);
+
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ assert_not_green(e[0]);
+ assert_not_green(e[1]);
+ assert_green(e[2]);
+ assert_not_green(e[3]);
+ assert_not_green(e[4]);
+ assert_not_green(e[5]);
+ assert_green(e[6]);
+ assert_not_green(e[7]);
+
+ e[1].classList.add('a');
+ // <div class=a></div>
+ // <div class=a></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ assert_not_green(e[0]);
+ assert_green(e[1]);
+ assert_not_green(e[2]);
+ assert_not_green(e[3]);
+ assert_green(e[4]);
+ assert_not_green(e[5]);
+ assert_not_green(e[6]);
+ assert_not_green(e[7]);
+
+ e[1].classList.remove('a');
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ assert_not_green(e[0]);
+ assert_not_green(e[1]);
+ assert_green(e[2]);
+ assert_not_green(e[3]);
+ assert_not_green(e[4]);
+ assert_not_green(e[5]);
+ assert_green(e[6]);
+ assert_not_green(e[7]);
+}, ':nth-child() in scope root');
+</script>
+
+<template>
+ <style>
+ @scope (#wrapper) to (:nth-child(4n of .a)) {
+ div { background-color: green; }
+ }
+ </style>
+ <div id=wrapper>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ <div class=a></div>
+ <div></div>
+ </div>
+</template>
+<script>
+test_scope_invalidation(document.currentScript, () => {
+ let e = main.querySelectorAll('#wrapper > div');
+ assert_equals(e.length, 8);
+
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div> <= limit
+ // <div></div>
+ assert_green(e[0]);
+ assert_green(e[1]);
+ assert_green(e[2]);
+ assert_green(e[3]);
+ assert_green(e[4]);
+ assert_green(e[5]);
+ assert_not_green(e[6]);
+ assert_green(e[7]);
+
+ e[1].classList.add('a');
+ // <div class=a></div>
+ // <div class=a></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div> <= limit
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ assert_green(e[0]);
+ assert_green(e[1]);
+ assert_green(e[2]);
+ assert_green(e[3]);
+ assert_not_green(e[4]);
+ assert_green(e[5]);
+ assert_green(e[6]);
+ assert_green(e[7]);
+
+ e[1].classList.remove('a');
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div>
+ // <div></div>
+ // <div class=a></div> <= limit
+ // <div></div>
+ assert_green(e[0]);
+ assert_green(e[1]);
+ assert_green(e[2]);
+ assert_green(e[3]);
+ assert_green(e[4]);
+ assert_green(e[5]);
+ assert_not_green(e[6]);
+ assert_green(e[7]);
+}, ':nth-child() in scope limit');
+
+</script>