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-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/html/semantics/disabled-elements
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/html/semantics/disabled-elements')
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/disabled-checkbox-click.html26
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch-additional.tentative.html74
-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-keyboard.tentative.html135
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html264
-rw-r--r--testing/web-platform/tests/html/semantics/disabled-elements/fieldset-event-propagation.tentative.html55
7 files changed, 655 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/disabled-checkbox-click.html b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-checkbox-click.html
new file mode 100644
index 0000000000..805770c854
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-checkbox-click.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<link rel="author" title="Aditya Keerthi" href="https://github.com/pxlcoder">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute">
+<title>Test disabled checkbox does not change state when clicked</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input type="checkbox" disabled>
+<script>
+const input = document.querySelector("input");
+
+promise_test(async function() {
+ assert_false(input.checked);
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, { origin: input })
+ .pointerDown()
+ .pointerUp()
+ .send();
+
+ assert_false(input.checked);
+}, `Disabled checkbox does not change state when clicked`);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch-additional.tentative.html b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch-additional.tentative.html
new file mode 100644
index 0000000000..8ef4e5ccc7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/disabled-event-dispatch-additional.tentative.html
@@ -0,0 +1,74 @@
+<!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>
+
+<!-- This test should be merged with disabled-event-dispatch.tentative.html after interop2023 is over. -->
+
+<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; }
+});
+
+['dblclick', 'auxclick'].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);
+
+ const elementToClick = clickChildElement ? targetchild : target;
+ if (eventName === 'dblclick') {
+ await (new test_driver.Actions()
+ .pointerMove(1, 1, {origin: elementToClick})
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp())
+ .send();
+ } else if (eventName === 'auxclick') {
+ const actions = new test_driver.Actions();
+ await actions
+ .pointerMove(1, 1, {origin: elementToClick})
+ .pointerDown({button: actions.ButtonType.MIDDLE})
+ .pointerUp({button: actions.ButtonType.MIDDLE})
+ .send();
+ }
+
+
+ const shouldReceiveEvents = eventName.startsWith('pointer') || eventName === 'auxclick';
+ assert_equals(parentReceivedEvent, shouldReceiveEvents,
+ `parent element received ${eventName} events`);
+ assert_equals(targetReceivedEvent, shouldReceiveEvents,
+ `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/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-keyboard.tentative.html b/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled-keyboard.tentative.html
new file mode 100644
index 0000000000..3aacf21f1d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled-keyboard.tentative.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>KeyboardEvent propagation on disabled form elements</title>
+<link rel="author" href="mailto:avandolder@mozilla.com">
+<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>
+<script>
+ class CustomControl extends HTMLElement {
+ static get formAssociated() {return true;}
+
+ constructor() {
+ super();
+ this.internals = this.attachInternals();
+
+ this.attachShadow({mode: "open", delegatesFocus: true});
+ this.shadowRoot.append(
+ document.querySelector("template").content.cloneNode(true)
+ );
+ }
+
+ get target() {
+ return this.shadowRoot.getElementById("target");
+ }
+ }
+
+ customElements.define("custom-control", CustomControl)
+</script>
+
+<template>
+ <div tabindex="0" id="target">
+ <slot></slot>
+ </div>
+</template>
+
+<div tabindex="0" id="reset"></div>
+
+<form id="form">
+ <input> <!-- Sanity check with non-disabled control -->
+ <select disabled></select>
+ <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">
+ <input disabled type="range" value="0">
+ <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">
+
+ <fieldset disabled><span tabindex="0">Span</span></fieldset>
+ <button disabled><span tabindex="0">Span</span></button>
+ <custom-control disabled>Text</custom-control>
+</form>
+
+<script>
+ const keyEvents = ["keydown", "keyup"];
+
+ function setupTest(t, element, observingElement) {
+ const observedEvents = [];
+ const controller = new AbortController();
+ const {signal} = controller;
+ const listenerFn = t.step_func(event => {
+ observedEvents.push(event.type);
+ });
+ for (const event of keyEvents) {
+ observingElement.addEventListener(event, listenerFn, {signal});
+ }
+ t.add_cleanup(() => controller.abort());
+
+ const target = element;
+ return {target, observedEvents};
+ }
+
+ function fire_trusted_key_events(target) {
+ const actions = new test_driver.Actions();
+ return actions.keyDown("a").keyUp("a").send();
+ }
+
+ function fire_untrusted_key_events(target) {
+ target.dispatchEvent(new KeyboardEvent("keydown", {bubbles: true}));
+ target.dispatchEvent(new KeyboardEvent("keyup", {bubbles: true}));
+ }
+
+ const observingElement = document.getElementById("form");
+ const reset = document.getElementById("reset");
+
+ for (const element of observingElement.children) {
+ promise_test(async t => {
+ const {observedEvents} = setupTest(t, element, observingElement);
+
+ const target = element.firstElementChild ?? element.target ?? element;
+ await t.step_func(fire_untrusted_key_events)(target);
+ await new Promise(resolve => t.step_timeout(resolve, 0));
+
+ assert_array_equals(observedEvents, keyEvents, "Observed events");
+ }, `Untrusted key events on ${element.outerHTML}, observed from <${observingElement.localName}>`);
+
+ // Only test elements with children for trusted key events.
+ if (!element.firstElementChild && !element.target) {
+ continue;
+ }
+
+ promise_test(async t => {
+ const {observedEvents} = setupTest(t, element, observingElement);
+
+ const target = element.firstElementChild ?? element.target;
+
+ reset.focus();
+ assert_not_equals(document.activeElement, target, "Reset current focus");
+ target.focus();
+ assert_equals(document.activeElement, element.firstElementChild ?? element, "Focus the target element");
+
+ await t.step_func(fire_trusted_key_events)(target);
+ await new Promise(resolve => t.step_timeout(resolve, 0));
+
+ assert_array_equals(observedEvents, keyEvents, "Observed events");
+ }, `Trusted key events on ${element.outerHTML}, observed from <${observingElement.localName}>`);
+ }
+</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..e3dcd43a17
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/event-propagate-disabled.tentative.html
@@ -0,0 +1,264 @@
+<!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} element
+ * @returns {boolean}
+ */
+ function isFormControl(element) {
+ if (["button", "input", "select", "textarea"].includes(element.localName)) {
+ return true;
+ }
+ return element.constructor.formAssociated;
+ }
+
+ function isDisabledFormControl(element) {
+ return isFormControl(element) && element.disabled;
+ }
+
+ /**
+ * @param {Element} target
+ * @param {*} observedEvent
+ */
+ function shouldNotBubble(target, observedEvent) {
+ return (
+ isDisabledFormControl(target) &&
+ 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 = isDisabledFormControl(element) ? 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>
diff --git a/testing/web-platform/tests/html/semantics/disabled-elements/fieldset-event-propagation.tentative.html b/testing/web-platform/tests/html/semantics/disabled-elements/fieldset-event-propagation.tentative.html
new file mode 100644
index 0000000000..6d1a39c1de
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/disabled-elements/fieldset-event-propagation.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled">
+<link rel=help href="https://github.com/whatwg/html/issues/5886#issuecomment-1460425364">
+<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=target1parent>
+ <fieldset disabled id=target1fieldset>
+ <div id=target1child>hello world</div>
+ </fieldset>
+</div>
+
+<div id=target2parent>
+ <fieldset disabled id=target2fieldset>hello world</fieldset>
+</div>
+
+<script>
+ const clickers = {
+ "native click": target => test_driver.click(target),
+ "click()": target => target.click(),
+ };
+
+ for (const [clickerName, clicker] of Object.entries(clickers)) {
+ promise_test(async () => {
+ let target1parentClicked = false;
+ let target1childClicked = false;
+ let target1fieldsetClicked = false;
+ target1parent.onclick = () => target1parentClicked = true;
+ target1child.onclick = () => target1childClicked = true;
+ target1fieldset.onclick = () => target1fieldsetClicked = true;
+
+ await clicker(target1child);
+
+ assert_true(target1parentClicked, 'The parent of the fieldset should receive a click event.');
+ assert_true(target1childClicked, 'The child of the fieldset should receive a click event.');
+ assert_true(target1fieldsetClicked, 'The fieldset element should receive a click event.');
+ }, `Disabled fieldset elements should not prevent click event propagation from ${clickerName}`);
+
+ promise_test(async () => {
+ let target2parentClicked = false;
+ let target2fieldsetClicked = false;
+ target2parent.onclick = () => target2parentClicked = true;
+ target2fieldset.onclick = () => target2fieldsetClicked = true;
+
+ await clicker(target2fieldset);
+
+ assert_true(target2parentClicked, 'The parent of the fieldset should receive a click event.');
+ assert_true(target2fieldsetClicked, 'The fieldset element should receive a click event.');
+ }, `Disabled fieldset elements should not block click events from ${clickerName}.`);
+ }
+</script>