1
0
mirror of https://github.com/videojs/video.js.git synced 2024-12-23 02:04:34 +02:00
video.js/test/unit/menu.test.js
Noemite b7cb9d06d6
fix(accessibility): fix broken aria menu (#7699)
* fix(accessibility): fix broken aria menu

* Update src/js/menu/menu-button.js

Co-authored-by: mister-ben <git@misterben.me>

* add tests

Co-authored-by: Noémie Macault <noemie.macault@capgemini.com>
Co-authored-by: mister-ben <git@misterben.me>
2022-04-15 12:56:29 -04:00

239 lines
8.5 KiB
JavaScript

/* eslint-env qunit */
import DomData from '../../src/js/utils/dom-data';
import MenuButton from '../../src/js/menu/menu-button.js';
import Menu from '../../src/js/menu/menu.js';
import CaptionSettingsMenuItem from '../../src/js/control-bar/text-track-controls/caption-settings-menu-item';
import MenuItem from '../../src/js/menu/menu-item.js';
import TestHelpers from './test-helpers.js';
import * as Events from '../../src/js/utils/events.js';
import sinon from 'sinon';
QUnit.module('MenuButton');
QUnit.test('should not throw an error when there is no children', function(assert) {
assert.expect(0);
const player = TestHelpers.makePlayer();
const menuButton = new MenuButton(player);
const el = menuButton.el();
try {
Events.trigger(el, 'click');
} catch (error) {
assert.ok(!error, 'click should not throw anything');
}
player.dispose();
menuButton.dispose();
});
QUnit.test('should place title list item into ul', function(assert) {
const player = TestHelpers.makePlayer();
const menuButton = new MenuButton(player, {
title: 'testTitle'
});
const menuContentElement = menuButton.el().getElementsByTagName('UL')[0];
const titleElement = menuContentElement.children[0];
assert.ok(titleElement.innerHTML === 'TestTitle', 'title element placed in ul');
menuButton.dispose();
player.dispose();
});
QUnit.test('should not include menu title in hide threshold', function(assert) {
const player = TestHelpers.makePlayer();
const menuButton = new MenuButton(player, {
title: 'testTitle'
});
assert.strictEqual(menuButton.hideThreshold_, 0, 'title should not increment hideThreshold_');
menuButton.createItems = () => [new MenuItem(player, { label: 'menu-item1' })];
menuButton.update();
assert.strictEqual(menuButton.hasClass('vjs-hidden'), false, 'menu button with single (non-title) item is not hidden');
menuButton.dispose();
player.dispose();
});
QUnit.test('clicking should display the menu', function(assert) {
assert.expect(6);
const player = TestHelpers.makePlayer();
// Make sure there's some content in the menu, even if it's just a title!
const menuButton = new MenuButton(player, {
title: 'testTitle'
});
const el = menuButton.menuButton_.el();
assert.ok(menuButton.menu !== undefined, 'menu is created');
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'menu defaults to hidden');
Events.trigger(el, 'click');
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), true, 'clicking on the menu button shows the menu');
Events.trigger(el, 'click');
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'clicking again on the menu button hides the menu');
menuButton.disable();
Events.trigger(el, 'click');
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'disable() prevents clicking from showing the menu');
menuButton.enable();
Events.trigger(el, 'click');
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), true, 'enable() allows clicking to show the menu');
menuButton.dispose();
player.dispose();
});
QUnit.test('should keep all the added menu items', function(assert) {
const player = TestHelpers.makePlayer();
const menuItems = [];
const menuItem1 = new MenuItem(player, { label: 'menu-item1' });
const menuItem2 = new MenuItem(player, { label: 'menu-item2' });
const oldCreateItems = MenuButton.prototype.createItems;
MenuButton.prototype.createItems = function() {
return menuItems;
};
const menuButton = new MenuButton(player, {});
menuItems.push(menuItem1);
menuButton.update();
assert.strictEqual(menuButton.children()[1].children().length, 1, 'the children number of the menu is 1 ');
assert.strictEqual(menuButton.children()[1].children()[0], menuItem1, 'the first child of the menu is `menuItem1`');
assert.ok(menuButton.el().contains(menuItem1.el()), 'the menu button contains the DOM element of `menuItem1`');
menuItems.push(menuItem2);
menuButton.update();
assert.strictEqual(menuButton.children()[1].children().length, 2, 'the children number of the menu is 2 after second update');
assert.strictEqual(menuButton.children()[1].children()[0], menuItem1, 'the first child of the menu is `menuItem1` after second update');
assert.strictEqual(menuButton.children()[1].children()[1], menuItem2, 'the second child of the menu is `menuItem2` after second update');
assert.ok(menuButton.el().contains(menuItem1.el()), 'the menu button contains the DOM element of `menuItem1` after second update');
assert.ok(menuButton.el().contains(menuItem2.el()), 'the menu button contains the DOM element of `menuItem2` after second update');
menuButton.dispose();
menuItem1.dispose();
menuItem2.dispose();
player.dispose();
MenuButton.prototype.createItems = oldCreateItems;
});
QUnit.test('should add or remove role menu for accessibility purpose', function(assert) {
const player = TestHelpers.makePlayer();
const menuButton = new MenuButton(player);
menuButton.createItems = () => [];
menuButton.update();
assert.equal(menuButton.menu.contentEl_.hasAttribute('role'), false, 'the menu does not have a role attribute when it contains no menu items');
menuButton.createItems = () => [new MenuItem(player, { label: 'menu-item' })];
menuButton.update();
assert.equal(menuButton.menu.contentEl_.hasAttribute('role'), true, 'the menu has a role attribute when it contains menu items');
assert.strictEqual(menuButton.menu.contentEl_.getAttribute('role'), 'menu', 'the menu role is `menu`');
menuButton.dispose();
player.dispose();
});
QUnit.test('should remove old event listeners when the menu item adds to the new menu', function(assert) {
const player = TestHelpers.makePlayer();
const menuButton = new MenuButton(player, {});
const oldMenu = new Menu(player, { menuButton });
const newMenu = new Menu(player, { menuButton });
oldMenu.addItem('MenuItem');
const menuItem = oldMenu.children()[0];
assert.ok(menuItem instanceof MenuItem, '`menuItem` should be the instanceof of `MenuItem`');
/**
* A reusable collection of assertions.
*/
function validateMenuEventListeners(watchedMenu) {
const eventData = DomData.get(menuItem.eventBusEl_);
// `MenuButton`.`unpressButton` will be called when triggering click event on the menu item.
const unpressButtonSpy = sinon.spy(menuButton, 'unpressButton');
// `MenuButton`.`focus` will be called when triggering click event on the menu item.
const focusSpy = sinon.spy(menuButton, 'focus');
// `Menu`.`children` will be called when triggering blur event on the menu item.
const menuChildrenSpy = sinon.spy(watchedMenu, 'children');
assert.strictEqual(eventData.handlers.blur.length, 1, 'the number of blur listeners is one');
// The number of click listeners is two because `ClickableComponent`
// adds the click event listener during the construction and
// `MenuItem` inherits from `ClickableComponent`.
assert.strictEqual(eventData.handlers.click.length, 2, 'the number of click listeners is two');
const clickListenerAddedByMenu = eventData.handlers.click[1];
assert.strictEqual(
typeof clickListenerAddedByMenu.calledOnce,
'undefined',
'previous click listener wrapped in the spy should be removed'
);
const clickListenerSpy = eventData.handlers.click[1] = sinon.spy(clickListenerAddedByMenu);
TestHelpers.triggerDomEvent(menuItem.el(), 'blur');
assert.ok(menuChildrenSpy.calledOnce, '`watchedMenu`.`children` has been called');
TestHelpers.triggerDomEvent(menuItem.el(), 'click');
assert.ok(clickListenerSpy.calledOnce, 'click event listener should be called');
assert.strictEqual(clickListenerSpy.getCall(0).args[0].target, menuItem.el(), 'event target should be the `menuItem`');
assert.ok(unpressButtonSpy.calledOnce, '`menuButton`.`unpressButtion` has been called');
assert.ok(focusSpy.calledOnce, '`menuButton`.`focus` has been called');
unpressButtonSpy.restore();
focusSpy.restore();
menuChildrenSpy.restore();
}
validateMenuEventListeners(oldMenu);
newMenu.addItem(menuItem);
validateMenuEventListeners(newMenu);
const focusSpy = sinon.spy(menuButton, 'focus');
const captionMenuItem = new CaptionSettingsMenuItem(player, {
kind: 'subtitles'
});
newMenu.addItem(captionMenuItem);
TestHelpers.triggerDomEvent(captionMenuItem.el(), 'click');
assert.ok(!focusSpy.called, '`menuButton`.`focus` should never be called');
focusSpy.restore();
player.dispose();
newMenu.dispose();
oldMenu.dispose();
menuButton.dispose();
});