summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/custom-elements/state
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/custom-elements/state
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/custom-elements/state')
-rw-r--r--testing/web-platform/tests/custom-elements/state/ElementInternals-states.html83
-rw-r--r--testing/web-platform/tests/custom-elements/state/META.yml1
-rw-r--r--testing/web-platform/tests/custom-elements/state/README.md2
-rw-r--r--testing/web-platform/tests/custom-elements/state/custom-state-set-strong-ref.html34
-rw-r--r--testing/web-platform/tests/custom-elements/state/state-css-selector-shadow-dom.html74
-rw-r--r--testing/web-platform/tests/custom-elements/state/state-css-selector.html104
-rw-r--r--testing/web-platform/tests/custom-elements/state/state-pseudo-class.html146
7 files changed, 444 insertions, 0 deletions
diff --git a/testing/web-platform/tests/custom-elements/state/ElementInternals-states.html b/testing/web-platform/tests/custom-elements/state/ElementInternals-states.html
new file mode 100644
index 0000000000..1521a8098a
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/ElementInternals-states.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<link rel=help href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+class TestElement extends HTMLElement {
+ constructor() {
+ super();
+ this._internals = this.attachInternals();
+ }
+
+ get internals() {
+ return this._internals;
+ }
+}
+customElements.define("test-element", TestElement);
+
+test(() => {
+ let i = (new TestElement()).internals;
+
+ assert_true(i.states instanceof CustomStateSet);
+ assert_equals(i.states.size, 0);
+ assert_false(i.states.has('foo'));
+ assert_false(i.states.has('--foo'));
+ assert_equals(i.states.toString(), '[object CustomStateSet]');
+}, 'CustomStateSet behavior of ElementInternals.states: Initial state');
+
+test(() => {
+ let i = (new TestElement()).internals;
+ assert_throws_js(TypeError, () => { i.states.supports('foo'); });
+ i.states.add(''); // should not throw.
+ i.states.add('--a\tb'); // should not throw.
+}, 'CustomStateSet behavior of ElementInternals.states: Exceptions');
+
+test(() => {
+ let i = (new TestElement()).internals;
+ i.states.add('--foo');
+ i.states.add('--bar');
+ i.states.add('--foo');
+ assert_equals(i.states.size, 2);
+ assert_true(i.states.has('--foo'));
+ assert_true(i.states.has('--bar'));
+ assert_array_equals([...i.states], ['--foo', '--bar']);
+ i.states.delete('--foo');
+ assert_array_equals([...i.states], ['--bar']);
+ i.states.add('--foo');
+ assert_array_equals([...i.states], ['--bar', '--foo']);
+ i.states.delete('--bar');
+ i.states.add('--baz');
+ assert_array_equals([...i.states], ['--foo', '--baz']);
+}, 'CustomStateSet behavior of ElementInternals.states: Modifications');
+
+test(() => {
+ let i = (new TestElement()).internals;
+ i.states.add('--one');
+ i.states.add('--two');
+ i.states.add('--three');
+ let iter = i.states.values();
+
+ // Delete the next item.
+ i.states.delete('--one');
+ let item = iter.next();
+ assert_false(item.done);
+ assert_equals(item.value, '--two');
+
+ // Clear the set.
+ i.states.clear();
+ item = iter.next();
+ assert_true(item.done);
+
+ // Delete the previous item.
+ i.states.add('--one');
+ i.states.add('--two');
+ i.states.add('--three');
+ iter = i.states.values();
+ item = iter.next();
+ assert_equals(item.value, '--one');
+ i.states.delete('--one');
+ item = iter.next();
+ assert_equals(item.value, '--two');
+}, 'Updating a CustomStateSet while iterating it should work');
+</script>
+
diff --git a/testing/web-platform/tests/custom-elements/state/META.yml b/testing/web-platform/tests/custom-elements/state/META.yml
new file mode 100644
index 0000000000..df335b339e
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/META.yml
@@ -0,0 +1 @@
+spec: https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class
diff --git a/testing/web-platform/tests/custom-elements/state/README.md b/testing/web-platform/tests/custom-elements/state/README.md
new file mode 100644
index 0000000000..4104881e03
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/README.md
@@ -0,0 +1,2 @@
+Tests for [Custom State Pseudo
+Class](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class)
diff --git a/testing/web-platform/tests/custom-elements/state/custom-state-set-strong-ref.html b/testing/web-platform/tests/custom-elements/state/custom-state-set-strong-ref.html
new file mode 100644
index 0000000000..da25943ffa
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/custom-state-set-strong-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="timeout" content="long">
+ <meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class" />
+ <title>CustomStateSet doesn't crash after GC on detached node</title>
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/common/gc.js"></script>
+ </head>
+ <body>
+ <custom-state id="myCE"></custom-state>
+ <script>
+ customElements.define('custom-state', class extends HTMLElement {
+ connectedCallback() {
+ this.elementInternals = this.attachInternals();
+ }
+ });
+
+ promise_test(async function() {
+ const states = myCE.elementInternals.states;
+ myCE.remove();
+ await garbageCollect();
+ states.add('still-works');
+ assert_equals(states.size, 1);
+ assert_true(states.delete('still-works'));
+ assert_equals(states.size, 0);
+ }, "customstateset doesn't crash after GC on detached node");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/custom-elements/state/state-css-selector-shadow-dom.html b/testing/web-platform/tests/custom-elements/state/state-css-selector-shadow-dom.html
new file mode 100644
index 0000000000..9d86b5d260
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/state-css-selector-shadow-dom.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="timeout" content="long" />
+ <meta
+ name="author"
+ title="Keith Cirkel"
+ href="mailto:wpt@keithcirkel.co.uk"
+ />
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class" />
+ <title>:state() css selector applies in shadow roots</title>
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <custom-state id="myCE"> I should be green </custom-state>
+ <style></style>
+ <script>
+ customElements.define(
+ "custom-state",
+ class extends HTMLElement {
+ connectedCallback() {
+ this.elementInternals = this.attachInternals();
+ const css = new CSSStyleSheet();
+ css.replaceSync(`
+ :host {
+ color: #f00;
+ }
+ :host(:state(green)) {
+ color: #0f0;
+ }
+ `);
+ this.attachShadow({ mode: "open" }).adoptedStyleSheets.push(css);
+ }
+ },
+ );
+
+ test(function () {
+ assert_false(myCE.elementInternals.states.has("green"));
+ assert_equals(
+ getComputedStyle(myCE).getPropertyValue("color"),
+ "rgb(255, 0, 0)",
+ );
+ }, "state selector has no influence when state is not applied");
+
+ test(function (t) {
+ myCE.elementInternals.states.add("green");
+ t.add_cleanup(() => {
+ myCE.elementInternals.states.delete("green");
+ });
+ assert_true(myCE.elementInternals.states.has("green"));
+ assert_equals(
+ getComputedStyle(myCE).getPropertyValue("color"),
+ "rgb(0, 255, 0)",
+ );
+ }, "state selector has influence when state is applied");
+
+ test(function (t) {
+ myCE.elementInternals.states.add("foo");
+ t.add_cleanup(() => {
+ myCE.elementInternals.states.delete("foo");
+ });
+ assert_false(myCE.elementInternals.states.has("green"));
+ assert_true(myCE.elementInternals.states.has("foo"));
+ assert_equals(
+ getComputedStyle(myCE).getPropertyValue("color"),
+ "rgb(255, 0, 0)",
+ );
+ }, "state selector only applies on given ident");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/custom-elements/state/state-css-selector.html b/testing/web-platform/tests/custom-elements/state/state-css-selector.html
new file mode 100644
index 0000000000..d29c927223
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/state-css-selector.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="timeout" content="long">
+ <meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class" />
+ <title>:state() css selector applies</title>
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <custom-state id="myCE">I should be green</custom-state>
+ <p id="mySibling">I should be blue</p>
+ <p id="myHas">I should be blue</p>
+ <style>
+ custom-state {
+ color: #f00;
+ }
+ custom-state + p {
+ color: #f00;
+ }
+ custom-state:state(--green) {
+ color: #0f0;
+ }
+ custom-state:--green {
+ color: #0f0;
+ }
+ body:has(custom-state:state(--green)) p {
+ color: #0ff;
+ }
+ custom-state:state(--green) + p[id] {
+ color: #00f;
+ }
+ custom-state:--green + p {
+ color: #00f;
+ }
+ </style>
+ <script>
+ customElements.define('custom-state', class extends HTMLElement {
+ connectedCallback() {
+ this.elementInternals = this.attachInternals();
+ }
+ });
+
+ test(function() {
+ assert_false(myCE.elementInternals.states.has('--green'));
+ assert_equals(getComputedStyle(myCE).getPropertyValue('color'), 'rgb(255, 0, 0)');
+ }, "state selector has no influence when state is not applied");
+
+ test(function() {
+ assert_false(myCE.elementInternals.states.has('--green'));
+ assert_equals(getComputedStyle(mySibling).getPropertyValue('color'), 'rgb(255, 0, 0)');
+ }, "state selector has no influence on sibling selectors when not applied");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--green');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--green') });
+ assert_true(myCE.elementInternals.states.has('--green'));
+ assert_equals(getComputedStyle(myCE).getPropertyValue('color'), 'rgb(0, 255, 0)');
+ }, "state selector has influence when state is applied");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--green');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--green') });
+ assert_true(myCE.elementInternals.states.has('--green'));
+ assert_equals(getComputedStyle(mySibling).getPropertyValue('color'), 'rgb(0, 0, 255)');
+ }, "state selector influences siblings when state is applied");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--green');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--green') });
+ assert_true(myCE.elementInternals.states.has('--green'));
+ assert_equals(getComputedStyle(myHas).getPropertyValue('color'), 'rgb(0, 255, 255)');
+ }, "state selector influences has() when state is applied");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--foo');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--foo') });
+ assert_false(myCE.elementInternals.states.has('--green'));
+ assert_true(myCE.elementInternals.states.has('--foo'));
+ assert_equals(getComputedStyle(myCE).getPropertyValue('color'), 'rgb(255, 0, 0)');
+ }, "state selector only applies on given ident");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--foo');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--foo') });
+ assert_false(myCE.elementInternals.states.has('--green'));
+ assert_true(myCE.elementInternals.states.has('--foo'));
+ assert_equals(getComputedStyle(mySibling).getPropertyValue('color'), 'rgb(255, 0, 0)');
+ }, "state selector only applies to siblings on given ident");
+
+ test(function(t) {
+ myCE.elementInternals.states.add('--foo');
+ t.add_cleanup(() => { myCE.elementInternals.states.delete('--foo') });
+ assert_false(myCE.elementInternals.states.has('--green'));
+ assert_true(myCE.elementInternals.states.has('--foo'));
+ assert_equals(getComputedStyle(mySibling).getPropertyValue('color'), 'rgb(255, 0, 0)');
+ }, "state selector only applies to has() on given ident");
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/custom-elements/state/state-pseudo-class.html b/testing/web-platform/tests/custom-elements/state/state-pseudo-class.html
new file mode 100644
index 0000000000..4e2ee0b779
--- /dev/null
+++ b/testing/web-platform/tests/custom-elements/state/state-pseudo-class.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<link rel=help href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#state-and-part::part(inner) {
+ opacity: 0;
+}
+#state-and-part::part(inner):state(innerFoo) {
+ opacity: 0.5;
+}
+#state-and-part:state(outerFoo)::part(inner) {
+ opacity: 0.25;
+}
+:state( \(escaped\ state ) {}
+</style>
+<body>
+<script>
+class TestElement extends HTMLElement {
+ constructor() {
+ super();
+ this._internals = this.attachInternals();
+ }
+
+ get i() {
+ return this._internals;
+ }
+}
+customElements.define('test-element', TestElement);
+
+class ContainerElement extends HTMLElement {
+ constructor() {
+ super();
+ this._internals = this.attachInternals();
+ this._shadow = this.attachShadow({mode:'open'});
+ this._shadow.innerHTML = `
+<style>
+:host {
+ border-style: solid;
+}
+:host(:state(dotted)) {
+ border-style: dotted;
+}
+</style>
+<test-element part="inner"></test-element>`;
+ }
+
+ get i() {
+ return this._internals;
+ }
+ get innerElement() {
+ return this._shadow.querySelector('test-element');
+ }
+}
+customElements.define('container-element', ContainerElement);
+
+test(() => {
+ document.querySelector(':state(foo)');
+ document.querySelector(':state(--foo)');
+ document.querySelector(':state(--)');
+ document.querySelector(':state(--16px)');
+}, ':state() parsing passes');
+
+test(() => {
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state('); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state()'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state(=)'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state(name=value)'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state( foo bar)'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':state(16px)'); });
+}, ':state() parsing failures');
+
+test(() => {
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':--('); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':--()'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':--)'); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':--='); });
+ assert_throws_dom('SyntaxError', () => { document.querySelector(':--name=value'); });
+}, 'deprecated :--state parsing failures');
+
+test(() => {
+ assert_equals(document.styleSheets[0].cssRules[1].cssText,
+ '#state-and-part::part(inner):state(innerFoo) { opacity: 0.5; }');
+ assert_equals(document.styleSheets[0].cssRules[3].selectorText,
+ ':state(\\(escaped\\ state)');
+}, ':state(foo) serialization');
+
+test(() => {
+ let element = new TestElement();
+ let states = element.i.states;
+
+ assert_false(element.matches(':state(foo)'));
+ assert_true(element.matches(':not(:state(foo))'));
+ states.add('foo');
+ assert_true(element.matches(':state(foo)'));
+ assert_true(element.matches(':is(:state(foo))'));
+ element.classList.add('c1', 'c2');
+ assert_true(element.matches('.c1:state(foo)'));
+ assert_true(element.matches(':state(foo).c1'));
+ assert_true(element.matches('.c2:state(foo).c1'));
+}, ':state(foo) in simple cases');
+
+test(() => {
+ let element = new TestElement();
+ element.tabIndex = 0;
+ document.body.appendChild(element);
+ element.focus();
+ let states = element.i.states;
+
+ states.add('foo');
+ assert_true(element.matches(':focus:state(foo)'));
+ assert_true(element.matches(':state(foo):focus'));
+}, ':state(foo) and other pseudo classes');
+
+test(() => {
+ let outer = new ContainerElement();
+ outer.id = 'state-and-part';
+ document.body.appendChild(outer);
+ let inner = outer.innerElement;
+ let innerStates = inner.i.states;
+
+ innerStates.add('innerFoo');
+ assert_equals(getComputedStyle(inner).opacity, '0.5',
+ '::part() followed by :state()');
+ innerStates.delete('innerFoo');
+ innerStates.add('innerfoo');
+ assert_equals(getComputedStyle(inner).opacity, '0',
+ ':state() matching should be case-sensitive');
+ innerStates.delete('innerfoo');
+
+ outer.i.states.add('outerFoo');
+ assert_equals(getComputedStyle(inner).opacity, '0.25',
+ ':state(foo) followed by ::part()');
+}, ':state(foo) and ::part()');
+
+test(() => {
+ let outer = new ContainerElement();
+ document.body.appendChild(outer);
+
+ assert_equals(getComputedStyle(outer).borderStyle, 'solid');
+ outer.i.states.add('dotted');
+ assert_equals(getComputedStyle(outer).borderStyle, 'dotted');
+}, ':state(foo) and :host()');
+</script>
+</body>