summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/disabled-elements
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/html/semantics/disabled-elements
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/disabled-elements')
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html57
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/disabledElement.html44
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html249
3 files changed, 350 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html
new file mode 100644
index 0000000000..e2b8846fc3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch.tentative.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/2368">
+<link rel=help href="https://github.com/whatwg/html/issues/5886">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<div id=targetparent>
+ <button disabled>
+ hello world
+ <span style="border: 1px solid black">child</span>
+ </button>
+ <my-control disabled>
+ hello world
+ <span style="border: 1px solid black">child</span>
+ </my-control>
+</div>
+
+<script>
+customElements.define('my-control', class extends HTMLElement {
+ static get formAssociated() { return true; }
+});
+
+['mousedown', 'mouseup', 'pointerdown', 'pointerup', 'click'].forEach(eventName => {
+ [true, false].forEach(clickChildElement => {
+ for (const target of targetparent.children) {
+ promise_test(async () => {
+ let parentReceivedEvent = false;
+ targetparent.addEventListener(eventName, () => parentReceivedEvent = true);
+
+ let targetReceivedEvent = false;
+ target.addEventListener(eventName, () => targetReceivedEvent = true);
+
+ let childReceivedEvent = false;
+ let targetchild = target.firstElementChild;
+ targetchild.addEventListener(eventName, () => childReceivedEvent = true);
+
+ await test_driver.click(clickChildElement ? targetchild : target);
+
+ const parentShouldReceiveEvents = eventName.startsWith('pointer');
+ assert_equals(parentReceivedEvent, parentShouldReceiveEvents,
+ `parent element received ${eventName} events`);
+
+ const targetShouldReceiveEvents = eventName.startsWith('pointer');
+ assert_equals(targetReceivedEvent, targetShouldReceiveEvents,
+ `target element received ${eventName} events`);
+ assert_equals(childReceivedEvent, clickChildElement,
+ `child element received ${eventName} events`);
+ }, `Testing ${eventName} events when clicking ${clickChildElement ? 'child of ' : ''}disabled ${target.localName}.`);
+ }
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/disabledElement.html b/testing/web-platform/tests/html/semantics/disabled-elements/disabledElement.html
new file mode 100644
index 0000000000..03f57424d2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/disabledElement.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Disabled elements</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#disabled-elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<button disabled>button</button>
+<input disabled>
+<select disabled>
+ <optgroup label="options" disabled>
+ <option value="option1" disabled>option1
+ <option value="option2">option2
+</select>
+<textarea disabled>textarea</textarea>
+<fieldset disabled>
+ <input type=radio name=c value=0 checked>
+ <input type=radio name=c value=1>
+</fieldset>
+<a href="http://www.w3.org/" disabled>w3</a>
+<span tabindex=0 disabled>foobar</span>
+
+<script>
+ test(function(){
+ assert_equals(document.activeElement, document.body);
+ }, "The body element must be the active element if no element is focused");
+
+ ["button", "input", "select", "optgroup", "option", "textarea", "input[type=radio]"].forEach(function(el) {
+ test(function() {
+ var element = document.querySelector(el);
+ element.focus();
+ assert_equals(document.activeElement, document.body, "activeElement after focus on a disabled <" + el + "> remains unchanged");
+ }, "A disabled <" + el + "> should not be focusable");
+ });
+
+ ["a", "span"].forEach(function(el) {
+ test(function() {
+ var element = document.querySelector(el);
+ element.focus();
+ assert_equals(document.activeElement, element, "focus on a <" + el + "> with a disabled attribute should make it the activeElement");
+ }, "A disabled <" + el + "> should be focusable");
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html b/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html
new file mode 100644
index 0000000000..9c8642d10f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html
@@ -0,0 +1,249 @@
+<!DOCTYPE html>
+<meta charset="utf8">
+<meta name="timeout" content="long">
+<title>Event propagation on disabled form elements</title>
+<link rel="author" href="mailto:krosylight@mozilla.com">
+<link rel="help" href="https://github.com/whatwg/html/issues/2368">
+<link rel="help" href="https://github.com/whatwg/html/issues/5886">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<div id="cases">
+ <input> <!-- Sanity check with non-disabled control -->
+ <select disabled></select>
+ <select disabled>
+ <!-- <option> can't be clicked as it doesn't have its own painting area -->
+ <option>foo</option>
+ </select>
+ <fieldset disabled>Text</fieldset>
+ <fieldset disabled><span class="target">Span</span></fieldset>
+ <button disabled>Text</button>
+ <button disabled><span class="target">Span</span></button>
+ <textarea disabled></textarea>
+ <input disabled type="button">
+ <input disabled type="checkbox">
+ <input disabled type="color" value="#000000">
+ <input disabled type="date">
+ <input disabled type="datetime-local">
+ <input disabled type="email">
+ <input disabled type="file">
+ <input disabled type="image">
+ <input disabled type="month">
+ <input disabled type="number">
+ <input disabled type="password">
+ <input disabled type="radio">
+ <!-- Native click will click the bar -->
+ <input disabled type="range" value="0">
+ <!-- Native click will click the slider -->
+ <input disabled type="range" value="50">
+ <input disabled type="reset">
+ <input disabled type="search">
+ <input disabled type="submit">
+ <input disabled type="tel">
+ <input disabled type="text">
+ <input disabled type="time">
+ <input disabled type="url">
+ <input disabled type="week">
+ <my-control disabled>Text</my-control>
+</div>
+
+<script>
+ customElements.define('my-control', class extends HTMLElement {
+ static get formAssociated() { return true; }
+ get disabled() { return this.hasAttribute("disabled"); }
+ });
+
+ /**
+ * @param {Element} element
+ */
+ function getEventFiringTarget(element) {
+ return element.querySelector(".target") || element;
+ }
+
+ const allEvents = ["pointermove", "mousemove", "pointerdown", "mousedown", "pointerup", "mouseup", "click"];
+
+ /**
+ * @param {*} t
+ * @param {Element} element
+ * @param {Element} observingElement
+ */
+ function setupTest(t, element, observingElement) {
+ /** @type {{type: string, composedPath: Node[]}[]} */
+ const observedEvents = [];
+ const controller = new AbortController();
+ const { signal } = controller;
+ const listenerFn = t.step_func(event => {
+ observedEvents.push({
+ type: event.type,
+ target: event.target,
+ isTrusted: event.isTrusted,
+ composedPath: event.composedPath().map(n => n.constructor.name),
+ });
+ });
+ for (const event of allEvents) {
+ observingElement.addEventListener(event, listenerFn, { signal });
+ }
+ t.add_cleanup(() => controller.abort());
+
+ const target = getEventFiringTarget(element);
+ return { target, observedEvents };
+ }
+
+ /**
+ * @param {Element} target
+ * @param {*} observedEvent
+ */
+ function shouldNotBubble(target, observedEvent) {
+ return (
+ target.disabled &&
+ observedEvent.isTrusted &&
+ ["mousedown", "mouseup", "click"].includes(observedEvent.type)
+ );
+ }
+
+ /**
+ * @param {Event} event
+ */
+ function getExpectedComposedPath(event) {
+ let target = event.target;
+ const result = [];
+ while (target) {
+ if (shouldNotBubble(target, event)) {
+ return result;
+ }
+ result.push(target.constructor.name);
+ target = target.parentNode;
+ }
+ result.push("Window");
+ return result;
+ }
+
+ /**
+ * @param {object} options
+ * @param {Element & { disabled: boolean }} options.element
+ * @param {Element} options.observingElement
+ * @param {string[]} options.expectedEvents
+ * @param {(target: Element) => (Promise<void> | void)} options.clickerFn
+ * @param {string} options.title
+ */
+ function promise_event_test({ element, observingElement, expectedEvents, nonDisabledExpectedEvents, clickerFn, title }) {
+ promise_test(async t => {
+ const { target, observedEvents } = setupTest(t, element, observingElement);
+
+ await t.step_func(clickerFn)(target);
+ await new Promise(resolve => t.step_timeout(resolve, 0));
+
+ const expected = element.disabled ? expectedEvents : nonDisabledExpectedEvents;
+ assert_array_equals(observedEvents.map(e => e.type), expected, "Observed events");
+
+ for (const observed of observedEvents) {
+ assert_equals(observed.target, target, `${observed.type}.target`)
+ assert_array_equals(
+ observed.composedPath,
+ getExpectedComposedPath(observed),
+ `${observed.type}.composedPath`
+ );
+ }
+
+ }, `${title} on ${element.outerHTML}, observed from <${observingElement.localName}>`);
+ }
+
+ /**
+ * @param {object} options
+ * @param {Element & { disabled: boolean }} options.element
+ * @param {string[]} options.expectedEvents
+ * @param {(target: Element) => (Promise<void> | void)} options.clickerFn
+ * @param {string} options.title
+ */
+ function promise_event_test_hierarchy({ element, expectedEvents, nonDisabledExpectedEvents, clickerFn, title }) {
+ const targets = [element, document.body];
+ if (element.querySelector(".target")) {
+ targets.unshift(element.querySelector(".target"));
+ }
+ for (const observingElement of targets) {
+ promise_event_test({ element, observingElement, expectedEvents, nonDisabledExpectedEvents, clickerFn, title });
+ }
+ }
+
+ function trusted_click(target) {
+ // To workaround type=file clicking issue
+ // https://github.com/w3c/webdriver/issues/1666
+ return new test_driver.Actions()
+ .pointerMove(0, 0, { origin: target })
+ .pointerDown()
+ .pointerUp()
+ .send();
+ }
+
+ const mouseEvents = ["mousemove", "mousedown", "mouseup", "click"];
+ const pointerEvents = ["pointermove", "pointerdown", "pointerup"];
+
+ // Events except mousedown/up/click
+ const allowedEvents = ["pointermove", "mousemove", "pointerdown", "pointerup"];
+
+ const elements = document.getElementById("cases").children;
+ for (const element of elements) {
+ // Observe on a child element of the control, if exists
+ const target = element.querySelector(".target");
+ if (target) {
+ promise_event_test({
+ element,
+ observingElement: target,
+ expectedEvents: allEvents,
+ nonDisabledExpectedEvents: allEvents,
+ clickerFn: trusted_click,
+ title: "Trusted click"
+ });
+ }
+
+ // Observe on the control itself
+ promise_event_test({
+ element,
+ observingElement: element,
+ expectedEvents: allowedEvents,
+ nonDisabledExpectedEvents: allEvents,
+ clickerFn: trusted_click,
+ title: "Trusted click"
+ });
+
+ // Observe on document.body
+ promise_event_test({
+ element,
+ observingElement: document.body,
+ expectedEvents: allowedEvents,
+ nonDisabledExpectedEvents: allEvents,
+ clickerFn: trusted_click,
+ title: "Trusted click"
+ });
+
+ const eventFirePair = [
+ [MouseEvent, mouseEvents],
+ [PointerEvent, pointerEvents]
+ ];
+
+ for (const [eventInterface, events] of eventFirePair) {
+ promise_event_test_hierarchy({
+ element,
+ expectedEvents: events,
+ nonDisabledExpectedEvents: events,
+ clickerFn: target => {
+ for (const event of events) {
+ target.dispatchEvent(new eventInterface(event, { bubbles: true }))
+ }
+ },
+ title: `Dispatch new ${eventInterface.name}()`
+ })
+ }
+
+ promise_event_test_hierarchy({
+ element,
+ expectedEvents: getEventFiringTarget(element) === element ? [] : ["click"],
+ nonDisabledExpectedEvents: ["click"],
+ clickerFn: target => target.click(),
+ title: `click()`
+ })
+ }
+</script>