diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/custom-elements/state | |
parent | Initial commit. (diff) | |
download | firefox-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')
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> |