Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 5 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /html/semantics/menu/tentative/menuitem-activate.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<meta name="timeout" content="long">
<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="../../popovers/resources/popover-utils.js"></script>
<link rel=author href=mailto:dom@chromium.org>
<menubar>
<menuitem id=openMainMenu commandfor=mainmenu command=toggle-menu>Open first menu</menuitem>
</menubar>
<menulist id=mainmenu>
<menuitem id=openSubMenu commandfor=submenu command=toggle-menu>Toggle menu</menuitem>
<menuitem id=showPopoverMenuItem command=toggle-popover commandfor=popover>Show popover</menuitem>
<menuitem id=doNothing>Normal item</menuitem>
</menulist>
<menulist id=submenu>
<menuitem>Sub menu</menuitem>
</menulist>
<div popover id=popover>Popover</div>
<button popovertarget=popoverwithmenu>Open popover with menu</button>
<div popover id=popoverwithmenu>
<button popovertarget=menuinpopover>Open menu in the popover</button>
<menulist id=menuinpopover>
<menuitem id=menuinpopoveritem1>First item</menuitem>
<menuitem id=menuinpopoveritem2 command=toggle-menu commandfor=menuinpopover2>Toggle menu 2</menuitem>
</menulist>
<menulist id=menuinpopover2>
<menuitem>Submenu item</menuitem>
</menulist>
</div>
<style>
[popover] {
width: 400px;
height: 400px;
}
</style>
<script>
promise_test(async () => {
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed");
await clickOn(openMainMenu);
assert_true(mainmenu.matches(":popover-open"), "mainmenu opens");
assert_false(submenu.matches(":popover-open"), "submenu popover starts closed");
await clickOn(openSubMenu);
assert_true(submenu.matches(":popover-open"), "submenu opens");
// Close the submenu.
await clickOn(openSubMenu);
assert_false(submenu.matches(":popover-open"), "submenu popover gets closed");
assert_true(mainmenu.matches(":popover-open"), "mainmenu still open");
// Close the mainmenu.
await clickOn(openMainMenu);
assert_false(mainmenu.matches(":popover-open"), "mainmenu gets closed");
}, 'User menuitem activation works with the toggle-menu command');
promise_test(async () => {
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed");
await clickOn(openMainMenu);
assert_true(mainmenu.matches(":popover-open"), "mainmenu popover opens");
assert_false(popover.matches(":popover-open"), "div popover starts closed");
await clickOn(showPopoverMenuItem);
assert_true(popover.matches(":popover-open"), "div popover opens");
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover closes");
// Close the popover.
await clickOn(openMainMenu);
assert_false(popover.matches(":popover-open"), "div popover gets closed");
assert_true(mainmenu.matches(":popover-open"), "mainmenu gets opened");
await clickOn(openMainMenu);
assert_false(mainmenu.matches(":popover-open"), "mainmenu gets closed");
}, 'User menuitem activation works with show-popover command');
promise_test(async (t) => {
assert_false(popoverwithmenu.matches(":popover-open"),
"popover with menu starts closed");
// Open the popover that hosts two menulists.
await clickOn(
document.querySelector("button[popovertarget=popoverwithmenu]"));
assert_true(popoverwithmenu.matches(":popover-open"),
"popover with menu opens");
assert_false(menuinpopover.matches(":popover-open"),
"menu in popover starts closed");
// Open the first menu in the popover.
await clickOn(
document.querySelector('button[popovertarget=menuinpopover]'));
assert_true(menuinpopover.matches(":popover-open"), "menu in popover opens");
assert_true(popoverwithmenu.matches(":popover-open"),
"outer popover remains open");
assert_false(menuinpopover2.matches(":popover-open"),
"menu 2 in popover starts closed");
// Open the second menu in the popover.
await clickOn(menuinpopoveritem2);
assert_true(menuinpopover2.matches(":popover-open"),
"menu 2 in popover opens");
assert_true(popoverwithmenu.matches(":popover-open"),
"outer popover remains open after opening menu 2");
assert_true(menuinpopover.matches(":popover-open"),
"menu in popover remains open");
// Close the second, "sub", menu within the popover by just clicking off of
// it.
await clickOn(menuinpopoveritem2);
assert_false(menuinpopover2.matches(":popover-open"),
"menu 2 in popover closes");
assert_true(popoverwithmenu.matches(":popover-open"),
"outer popover remains open after closing menu 2");
assert_true(menuinpopover.matches(":popover-open"),
"menu in popover remains open");
}, 'Menulist inside a popover works correctly; does not get accidentally ' +
'dismissed by opening submenus');
async function getMenuItemCoords(invoker, targetMenuItem) {
// test_driver isn't suited to mousedown-drag-mouseup interactions when the
// mousedown triggers visibility of one of the elements.
const menulist = targetMenuItem.parentElement;
assert_false(menulist.matches(":popover-open"), "menulist popover should start closed");
await clickOn(invoker);
assert_true(menulist.matches(":popover-open"), "menulist popover opens when clicked");
let rect = targetMenuItem.getBoundingClientRect();
let coords = {x: Math.round(rect.x + rect.width / 2),
y: Math.round(rect.y + rect.height / 2)};
await clickOn(invoker);
assert_false(menulist.matches(":popover-open"), "menulist popover closes when clicked");
return coords;
}
promise_test(async (t) => {
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed");
const doNothingCoordinates = await getMenuItemCoords(openMainMenu, doNothing);
let invokerClicks = 0;
let itemClicks = 0;
openMainMenu.addEventListener('click',() => (++invokerClicks));
doNothing.addEventListener('click',() => (++itemClicks));
let openStateAfterPointerdown = "none";
openMainMenu.addEventListener('pointermove',() => {
// There will be two move events, one before the pointerdown and one after.
// Just capture the one after.
if (openStateAfterPointerdown === "none") {
openStateAfterPointerdown = "first-move";
} else if (openStateAfterPointerdown === "first-move") {
openStateAfterPointerdown = mainmenu.matches(":popover-open") ? "open" : "closed";
}
},{signal: t.get_signal()});
await new test_driver.Actions()
.addPointer('mouse', 'mouse')
.pointerMove(0, 0, {origin: openMainMenu})
.pointerDown()
// Extra move to trigger event on openMainMenu:
.pointerMove(2, 2, {origin: openMainMenu})
.pointerMove(doNothingCoordinates.x, doNothingCoordinates.y, {})
.pointerUp()
.send();
await waitForRender();
assert_equals(openStateAfterPointerdown,"open", "mainmenu popover should open after pointer down");
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover should be closed after interaction");
assert_equals(invokerClicks,0, "the invoking menu didn't get a click");
// TODO: Menu items should fire a click event when they are selected.
// assert_equals(itemClicks,1, "the invoked menu did get a click");
}, 'A mousedown-drag-mouseup gesture on a normal menuitem picks the item');
promise_test(async (t) => {
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover starts closed");
assert_false(submenu.matches(":popover-open"), "submenu popover starts closed");
const openSubMenuCoordinates = await getMenuItemCoords(openMainMenu, openSubMenu);
await new test_driver.Actions()
.addPointer('mouse', 'mouse')
.pointerMove(0, 0, {origin: openMainMenu})
.pointerDown()
.pointerMove(openSubMenuCoordinates.x, openSubMenuCoordinates.y, {})
.pointerUp()
.send();
await waitForRender();
assert_true(mainmenu.matches(":popover-open"), "mainmenu popover should remain open, because submenu chosen");
assert_true(submenu.matches(":popover-open"), "submenu popover should be open");
await clickOn(openMainMenu); // Cleanup.
assert_false(mainmenu.matches(":popover-open"), "mainmenu popover should be closed");
assert_false(submenu.matches(":popover-open"), "submenu popover should be closed");
}, 'A mousedown-drag-mouseup gesture on a submenu item leaves both menus open');
</script>