Skip to content

Commit 6d77634

Browse files
committed
test: add hamburger menu integration tests
Tests cover: hamburger existence, visibility when menus fit/overflow, dropdown open/close on click, flyout submenu on hover, restore on expand, close on ESC key, command execution from flyout menu items, and command execution from flyout submenu items. Uses awaitsForCondition for robust async assertions.
1 parent 1111b29 commit 6d77634

1 file changed

Lines changed: 268 additions & 1 deletion

File tree

test/spec/Menu-integ-test.js

Lines changed: 268 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
*/
2121

22-
/*global describe, it, expect, beforeAll, afterAll*/
22+
/*global describe, it, expect, beforeAll, afterAll, afterEach*/
2323

2424
define(function (require, exports, module) {
2525

@@ -1151,5 +1151,272 @@ define(function (require, exports, module) {
11511151
expect(element.getElementsByClassName("forced-hidden").length).toBe(0);
11521152
});
11531153
});
1154+
1155+
describe("Hamburger Menu", function () {
1156+
1157+
function getHamburger() {
1158+
return testWindow.$("#hamburger-menu");
1159+
}
1160+
1161+
function getHamburgerDropdown() {
1162+
return testWindow.$("#hamburger-menu .hamburger-dropdown");
1163+
}
1164+
1165+
function getHiddenMenuItems() {
1166+
return testWindow.$("#titlebar .nav > li.dropdown:not(.hamburger-menu)").filter(function () {
1167+
return testWindow.$(this).css("display") === "none";
1168+
});
1169+
}
1170+
1171+
function forceNarrowTitlebar() {
1172+
// Shrink the .content container so the titlebar becomes narrow
1173+
const $content = testWindow.$(".content");
1174+
$content.css({"right": "", "width": "200px"});
1175+
$content[0].offsetHeight;
1176+
}
1177+
1178+
function restoreTitlebar() {
1179+
const $content = testWindow.$(".content");
1180+
$content.css({"left": "", "right": "", "width": ""});
1181+
$content[0].offsetHeight;
1182+
}
1183+
1184+
function awaitsForCondition(conditionFn, message, timeout) {
1185+
timeout = timeout || 5000;
1186+
return new Promise(function (resolve, reject) {
1187+
const startTime = Date.now();
1188+
function check() {
1189+
if (conditionFn()) {
1190+
resolve();
1191+
} else if (Date.now() - startTime > timeout) {
1192+
reject(new Error("Timed out waiting for: " + (message || "condition")));
1193+
} else {
1194+
testWindow.requestAnimationFrame(check);
1195+
}
1196+
}
1197+
check();
1198+
});
1199+
}
1200+
1201+
afterEach(function () {
1202+
// Clean up: close hamburger properly (clears _activeSubmenuId)
1203+
const $hamburger = getHamburger();
1204+
if ($hamburger.hasClass("hamburger-open")) {
1205+
$hamburger.find(".hamburger-toggle").click();
1206+
}
1207+
Menus.closeAll();
1208+
restoreTitlebar();
1209+
});
1210+
1211+
it("should exist in the DOM", function () {
1212+
const $hamburger = getHamburger();
1213+
expect($hamburger.length).toBe(1);
1214+
expect($hamburger.find(".hamburger-toggle").length).toBe(1);
1215+
expect($hamburger.find(".hamburger-dropdown").length).toBe(1);
1216+
});
1217+
1218+
it("should be hidden when all menus fit on one row", async function () {
1219+
// The test window may have extra test menus from prior tests.
1220+
// Verify with a very wide container that hamburger hides.
1221+
const $content = testWindow.$(".content");
1222+
const $main = $content.parent();
1223+
$main.css("width", "4000px");
1224+
$content.css({"left": "0", "right": "0", "position": "relative", "width": "4000px"});
1225+
$content[0].offsetHeight;
1226+
await awaitsForCondition(function () {
1227+
return getHamburger().is(":hidden");
1228+
}, "hamburger to be hidden");
1229+
$main.css("width", "");
1230+
$content.css({"left": "", "right": "", "position": "", "width": ""});
1231+
});
1232+
1233+
it("should appear when titlebar is too narrow", async function () {
1234+
forceNarrowTitlebar();
1235+
await awaitsForCondition(function () {
1236+
return !getHamburger().is(":hidden");
1237+
}, "hamburger to appear");
1238+
const $hidden = getHiddenMenuItems();
1239+
expect($hidden.length).toBeGreaterThan(0);
1240+
const $entries = getHamburgerDropdown().find(".hamburger-submenu-item");
1241+
expect($entries.length).toBe($hidden.length);
1242+
});
1243+
1244+
it("should open dropdown on click", async function () {
1245+
forceNarrowTitlebar();
1246+
await awaitsForCondition(function () {
1247+
return !getHamburger().is(":hidden");
1248+
}, "hamburger to appear");
1249+
const $hamburger = getHamburger();
1250+
expect($hamburger.hasClass("hamburger-open")).toBe(false);
1251+
1252+
$hamburger.find(".hamburger-toggle").click();
1253+
expect($hamburger.hasClass("hamburger-open")).toBe(true);
1254+
1255+
const $dropdown = getHamburgerDropdown();
1256+
expect($dropdown.css("display")).toBe("block");
1257+
});
1258+
1259+
it("should close dropdown on second click", async function () {
1260+
forceNarrowTitlebar();
1261+
await awaitsForCondition(function () {
1262+
return !getHamburger().is(":hidden");
1263+
}, "hamburger to appear");
1264+
const $hamburger = getHamburger();
1265+
const $toggle = $hamburger.find(".hamburger-toggle");
1266+
1267+
$toggle.click();
1268+
expect($hamburger.hasClass("hamburger-open")).toBe(true);
1269+
1270+
$toggle.click();
1271+
expect($hamburger.hasClass("hamburger-open")).toBe(false);
1272+
});
1273+
1274+
it("should open flyout submenu on entry hover", async function () {
1275+
forceNarrowTitlebar();
1276+
await awaitsForCondition(function () {
1277+
return !getHamburger().is(":hidden");
1278+
}, "hamburger to appear");
1279+
const $hamburger = getHamburger();
1280+
$hamburger.find(".hamburger-toggle").click();
1281+
1282+
const $entries = getHamburgerDropdown().find(".hamburger-submenu-item");
1283+
expect($entries.length).toBeGreaterThan(0);
1284+
1285+
const $firstEntry = $entries.first();
1286+
$firstEntry.trigger("mouseenter");
1287+
1288+
expect($firstEntry.hasClass("hamburger-submenu-open")).toBe(true);
1289+
1290+
const menuId = $firstEntry.find("a").attr("data-menu-id");
1291+
const $menuDropdown = testWindow.$("#" + menuId + " > .dropdown-menu");
1292+
expect($menuDropdown.css("visibility")).toBe("visible");
1293+
expect($menuDropdown.css("position")).toBe("fixed");
1294+
});
1295+
1296+
it("should restore all menus when titlebar expands", async function () {
1297+
forceNarrowTitlebar();
1298+
await awaitsForCondition(function () {
1299+
return !getHamburger().is(":hidden");
1300+
}, "hamburger to appear");
1301+
expect(getHiddenMenuItems().length).toBeGreaterThan(0);
1302+
1303+
// Expand wide enough for all menus
1304+
restoreTitlebar();
1305+
const $content = testWindow.$(".content");
1306+
const $main = $content.parent();
1307+
$main.css("width", "4000px");
1308+
$content.css({"left": "0", "right": "0", "position": "relative", "width": "4000px"});
1309+
$content[0].offsetHeight;
1310+
await awaitsForCondition(function () {
1311+
return getHamburger().is(":hidden");
1312+
}, "hamburger to hide after expanding");
1313+
expect(getHiddenMenuItems().length).toBe(0);
1314+
$main.css("width", "");
1315+
$content.css({"left": "", "right": "", "position": "", "width": ""});
1316+
});
1317+
1318+
it("should execute command when clicking a flyout menu item", async function () {
1319+
// Register a test command and add it to a menu
1320+
let commandExecuted = false;
1321+
CommandManager.register("Hamburger Test Command", "Menu-test.hamburgerCmd1", function () {
1322+
commandExecuted = true;
1323+
});
1324+
const fileMenu = Menus.getMenu(Menus.AppMenuBar.FILE_MENU);
1325+
fileMenu.addMenuItem("Menu-test.hamburgerCmd1");
1326+
1327+
forceNarrowTitlebar();
1328+
await awaitsForCondition(function () {
1329+
return !getHamburger().is(":hidden");
1330+
}, "hamburger to appear");
1331+
1332+
// Open hamburger and hover File menu entry
1333+
const $hamburger = getHamburger();
1334+
$hamburger.find(".hamburger-toggle").click();
1335+
const $entries = getHamburgerDropdown().find(".hamburger-submenu-item");
1336+
// Find the File menu entry
1337+
const $fileEntry = $entries.filter(function () {
1338+
return testWindow.$(this).find("a").attr("data-menu-id") === "file-menu";
1339+
});
1340+
expect($fileEntry.length).toBe(1);
1341+
$fileEntry.trigger("mouseenter");
1342+
1343+
// Click the test command in the flyout
1344+
const $menuItem = testWindow.$("#file-menu-Menu-test\\.hamburgerCmd1");
1345+
expect($menuItem.length).toBe(1);
1346+
$menuItem.click();
1347+
1348+
await awaitsForCondition(function () {
1349+
return commandExecuted;
1350+
}, "command to be executed");
1351+
await awaitsForCondition(function () {
1352+
return !$hamburger.hasClass("hamburger-open");
1353+
}, "hamburger to close after command");
1354+
});
1355+
1356+
it("should execute command when clicking a flyout submenu item", async function () {
1357+
// Register a command, create a submenu in the File menu
1358+
let subCommandExecuted = false;
1359+
CommandManager.register("Hamburger SubMenu Test", "Menu-test.hamburgerSubCmd1", function () {
1360+
subCommandExecuted = true;
1361+
});
1362+
const fileMenu = Menus.getMenu(Menus.AppMenuBar.FILE_MENU);
1363+
const subMenu = fileMenu.addSubMenu("Hamburger Sub", "hamburger-test-submenu1");
1364+
subMenu.addMenuItem("Menu-test.hamburgerSubCmd1");
1365+
1366+
forceNarrowTitlebar();
1367+
await awaitsForCondition(function () {
1368+
return !getHamburger().is(":hidden");
1369+
}, "hamburger to appear");
1370+
1371+
// Open hamburger and hover File menu entry
1372+
const $hamburger = getHamburger();
1373+
$hamburger.find(".hamburger-toggle").click();
1374+
const $entries = getHamburgerDropdown().find(".hamburger-submenu-item");
1375+
const $fileEntry = $entries.filter(function () {
1376+
return testWindow.$(this).find("a").attr("data-menu-id") === "file-menu";
1377+
});
1378+
$fileEntry.trigger("mouseenter");
1379+
1380+
// Hover the submenu trigger to open it
1381+
const $subMenuTrigger = testWindow.$("#file-menu-hamburger-test-submenu1").closest("li");
1382+
expect($subMenuTrigger.length).toBe(1);
1383+
$subMenuTrigger.trigger("mouseenter");
1384+
1385+
// Wait for submenu to open
1386+
await awaitsForCondition(function () {
1387+
return testWindow.$("#hamburger-test-submenu1").hasClass("open");
1388+
}, "submenu to open");
1389+
1390+
// Click the command in the submenu
1391+
const $subItem = testWindow.$("#hamburger-test-submenu1-Menu-test\\.hamburgerSubCmd1");
1392+
expect($subItem.length).toBe(1);
1393+
$subItem.closest("li").click();
1394+
1395+
await awaitsForCondition(function () {
1396+
return subCommandExecuted;
1397+
}, "submenu command to be executed");
1398+
});
1399+
1400+
it("should close on ESC key", async function () {
1401+
forceNarrowTitlebar();
1402+
await awaitsForCondition(function () {
1403+
return !getHamburger().is(":hidden");
1404+
}, "hamburger to appear");
1405+
const $hamburger = getHamburger();
1406+
$hamburger.find(".hamburger-toggle").click();
1407+
expect($hamburger.hasClass("hamburger-open")).toBe(true);
1408+
1409+
// Dispatch ESC keydown event
1410+
const escEvent = new testWindow.KeyboardEvent("keydown", {
1411+
key: "Escape",
1412+
keyCode: KeyEvent.DOM_VK_ESCAPE,
1413+
bubbles: true,
1414+
cancelable: true
1415+
});
1416+
testWindow.document.dispatchEvent(escEvent);
1417+
1418+
expect($hamburger.hasClass("hamburger-open")).toBe(false);
1419+
});
1420+
});
11541421
});
11551422
});

0 commit comments

Comments
 (0)