commit 970699bd70129261357b00a2ce91e4782dd7bd95
parent c7ad5ae4e59bd912af38ba0c536a5bc78de45902
Author: Mason Freed <masonf@chromium.org>
Date: Fri, 7 Nov 2025 08:47:33 +0000
Bug 1998479 [wpt PR 55861] - Reland "Refactor menu event handling code [2/4]", a=testonly
Automatic update from web-platform-tests
Reland "Refactor menu event handling code [2/4]"
This is a reland of commit 95f912cedcfed49b1360d308897f441882b57f13
Original change's description:
> Refactor menu event handling code [2/4]
>
> Another refactoring CL for menu element code. Previously, the command
> invoker logic was split (and roughly duplicated) between
> HTMLButtonElement and HTMLMenuItemElement. Since both can be command
> invokers, it makes sense to move the command management stuff to the
> common ancestor class, HTMLElement. This CL does that, and de-dupes
> the code out of both subclasses. There is now just one base class
> method that is overridden in sub-classes that can be command
> invokers: CanBeCommandInvoker().
>
> There was also a weird combination of popover activation command
> code, which belongs on HTMLElement because any element can be a
> popover, and menu activation command code, which belongs on the
> HTMLMenuItemElement class, because only that class handles menu
> commands.
>
> This touches a few outside classes like ax_object, which get simpler
> now that they don't have to deal with each case of a command invoker.
>
> There is one behavior change here: now, if a menuitem is *both*
> checkable *and* a sub-menu invoker, the sub-menu wins, and the
> item does not do checked/unchecked behaviors.
>
> I also added a test that seemed missing: make sure only buttons and
> menuitems can be command invokers. Even though <menuitem> isn't
> shipped, this test should pass because it explicitly skips <menuitem>,
> and anyway menuitem isn't included in the HTML5_ELEMENTS list.
>
> Bug: 406566432
> Change-Id: I281eda0eda4b0dced3ad38bd09a488f2c6b1ddf4
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7078858
> Reviewed-by: Dominic Farolino <dom@chromium.org>
> Commit-Queue: Mason Freed <masonf@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1538871}
Bug: 406566432
Change-Id: Iec91410726ae22a3673bdf32eb64aad79f672d6a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7113161
Commit-Queue: Dominic Farolino <dom@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Dominic Farolino <dom@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1540144}
--
wpt-commits: b31a7126b333e9020a7c1be9aa3812f536386c77
wpt-pr: 55861
Diffstat:
2 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/testing/web-platform/tests/html/semantics/menu/tentative/menubar-invoke-menulist.html b/testing/web-platform/tests/html/semantics/menu/tentative/menubar-invoke-menulist.html
@@ -128,14 +128,13 @@ test(() => {
}, "Menuitem with invalid command/commandfor cannot invoke menulist popover.");
test(() => {
- checkableMenuitem.command = "toggle-menu";
- checkableMenuitem.commandForElement = menulist;
-
+ assert_equals(checkableMenuitem.commandForElement,null,
+ "To start, checkable item shouldn't be an invoker")
checkableMenuitem.click();
assert_true(checkableMenuitem.checked,
"checkable menu item becomes checked");
- assert_true(menulist.matches(":popover-open"),
- "menulist matches :popover-open");
+ assert_false(menulist.matches(":popover-open"),
+ "not an invoker yet");
checkableMenuitem.click();
@@ -143,5 +142,19 @@ test(() => {
"checkable menu item is no longer checked");
assert_false(menulist.matches(":popover-open"),
"menulist no longer matches :popover-open");
+
+ // Being an invoker for a sub-menu causes checkability to stop.
+ checkableMenuitem.command = "toggle-menu";
+ checkableMenuitem.commandForElement = menulist;
+ checkableMenuitem.click();
+ assert_false(checkableMenuitem.checked,
+ "checkable menu item that invokes a menu does not become checked");
+ assert_true(menulist.matches(":popover-open"),
+ "menulist matches :popover-open");
+ checkableMenuitem.click();
+ assert_false(checkableMenuitem.checked,
+ "checkable menu item is still not checked");
+ assert_false(menulist.matches(":popover-open"),
+ "menulist no longer matches :popover-open");
}, "Checkable menuitems can still invoke menulist popovers");
</script>
diff --git a/testing/web-platform/tests/html/semantics/the-button-element/command-and-commandfor/invalid-element-types.html b/testing/web-platform/tests/html/semantics/the-button-element/command-and-commandfor/invalid-element-types.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<meta name="timeout" content="long" />
+<meta charset="utf-8" />
+<meta name="author" href="mailto:masonf@chromium.org" />
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<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>
+<script src="resources/invoker-utils.js"></script>
+<script src="/html/resources/common.js"></script>
+
+<meta name=variant content=?command=--custom-event&half=first>
+<meta name=variant content=?command=--custom-event&half=second>
+<meta name=variant content=?command=show-popover&half=first>
+<meta name=variant content=?command=show-popover&half=second>
+<meta name=variant content=?command=show-modal&half=first>
+<meta name=variant content=?command=show-modal&half=second>
+
+<div id="invokee"></div>
+
+<script>
+ // The command parameter is provided by variants, to
+ // effectively split this (slow) test into multiple runs.
+ const urlParams = new URLSearchParams(window.location.search);
+ command = urlParams.get('command');
+ half = urlParams.get('half');
+ const firstHalf = half === 'first';
+ assert_true(firstHalf || half === 'second');
+
+ const allowed = ['button','input','menuitem'];
+ const allTags = HTML5_ELEMENTS.filter(el => (!allowed.includes(el)));
+ const midpoint = Math.floor(allTags.length / 2);
+ const tags = firstHalf ? allTags.slice(0,midpoint) : allTags.slice(midpoint);
+ let gotEvent = false;
+ invokee.addEventListener('command',() => (gotEvent = true));
+ for(const tag of tags) {
+ promise_test(async () => {
+ gotEvent = false;
+ const element = document.createElement(tag);
+ element.setAttribute('commandfor','invokee');
+ element.setAttribute('command',command);
+ element.style.display = 'block'; // For normally invisible elements
+ document.body.appendChild(element);
+ // Click two ways
+ element.click();
+ await clickOn(element);
+ assert_false(gotEvent,'Command should not be fired');
+ },`command/commandfor on <${tag}> with command=${command} should not function`);
+ }
+</script>