2016-08-04 17:49:32 +02:00
|
|
|
/* eslint-env qunit */
|
2019-08-01 20:26:59 +02:00
|
|
|
import DomData from '../../src/js/utils/dom-data';
|
2015-04-14 22:08:32 +02:00
|
|
|
import MenuButton from '../../src/js/menu/menu-button.js';
|
2019-01-25 21:26:36 +02:00
|
|
|
import Menu from '../../src/js/menu/menu.js';
|
|
|
|
import CaptionSettingsMenuItem from '../../src/js/control-bar/text-track-controls/caption-settings-menu-item';
|
2019-01-08 21:14:46 +02:00
|
|
|
import MenuItem from '../../src/js/menu/menu-item.js';
|
2015-03-26 06:43:41 +02:00
|
|
|
import TestHelpers from './test-helpers.js';
|
2016-03-25 20:16:56 +02:00
|
|
|
import * as Events from '../../src/js/utils/events.js';
|
2019-01-25 21:26:36 +02:00
|
|
|
import sinon from 'sinon';
|
2015-03-26 06:43:41 +02:00
|
|
|
|
2016-08-04 17:49:32 +02:00
|
|
|
QUnit.module('MenuButton');
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
QUnit.test('should not throw an error when there is no children', function(assert) {
|
|
|
|
assert.expect(0);
|
2016-08-04 17:49:32 +02:00
|
|
|
const player = TestHelpers.makePlayer();
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2016-08-04 17:49:32 +02:00
|
|
|
const menuButton = new MenuButton(player);
|
|
|
|
const el = menuButton.el();
|
2016-03-29 22:09:10 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
Events.trigger(el, 'click');
|
|
|
|
} catch (error) {
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.ok(!error, 'click should not throw anything');
|
2016-03-29 22:09:10 +02:00
|
|
|
}
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2016-03-29 22:09:10 +02:00
|
|
|
player.dispose();
|
2019-03-18 21:49:48 +02:00
|
|
|
menuButton.dispose();
|
2016-03-29 22:09:10 +02:00
|
|
|
});
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
QUnit.test('should place title list item into ul', function(assert) {
|
2016-08-04 17:49:32 +02:00
|
|
|
const player = TestHelpers.makePlayer();
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2016-08-04 17:49:32 +02:00
|
|
|
const menuButton = new MenuButton(player, {
|
|
|
|
title: 'testTitle'
|
2014-03-26 10:40:14 +03:00
|
|
|
});
|
|
|
|
|
2016-08-04 17:49:32 +02:00
|
|
|
const menuContentElement = menuButton.el().getElementsByTagName('UL')[0];
|
|
|
|
const titleElement = menuContentElement.children[0];
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.ok(titleElement.innerHTML === 'TestTitle', 'title element placed in ul');
|
2014-03-26 10:40:14 +03:00
|
|
|
|
2018-01-30 20:26:21 +02:00
|
|
|
menuButton.dispose();
|
2014-03-26 10:40:14 +03:00
|
|
|
player.dispose();
|
2016-03-25 20:16:56 +02:00
|
|
|
});
|
|
|
|
|
2021-05-11 00:28:31 +02:00
|
|
|
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();
|
|
|
|
});
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
QUnit.test('clicking should display the menu', function(assert) {
|
|
|
|
assert.expect(6);
|
2016-03-25 20:16:56 +02:00
|
|
|
|
2016-08-04 17:49:32 +02:00
|
|
|
const player = TestHelpers.makePlayer();
|
2016-03-25 20:16:56 +02:00
|
|
|
|
|
|
|
// Make sure there's some content in the menu, even if it's just a title!
|
2016-08-04 17:49:32 +02:00
|
|
|
const menuButton = new MenuButton(player, {
|
|
|
|
title: 'testTitle'
|
2016-03-25 20:16:56 +02:00
|
|
|
});
|
2017-02-08 08:24:30 +02:00
|
|
|
const el = menuButton.menuButton_.el();
|
2016-03-25 20:16:56 +02:00
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.ok(menuButton.menu !== undefined, 'menu is created');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'menu defaults to hidden');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
|
|
|
Events.trigger(el, 'click');
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), true, 'clicking on the menu button shows the menu');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
|
|
|
Events.trigger(el, 'click');
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'clicking again on the menu button hides the menu');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
|
|
|
menuButton.disable();
|
|
|
|
|
|
|
|
Events.trigger(el, 'click');
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), false, 'disable() prevents clicking from showing the menu');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
|
|
|
menuButton.enable();
|
|
|
|
|
|
|
|
Events.trigger(el, 'click');
|
|
|
|
|
2016-08-12 19:51:31 +02:00
|
|
|
assert.equal(menuButton.menu.hasClass('vjs-lock-showing'), true, 'enable() allows clicking to show the menu');
|
2016-03-25 20:16:56 +02:00
|
|
|
|
2018-01-30 20:26:21 +02:00
|
|
|
menuButton.dispose();
|
2016-03-25 20:16:56 +02:00
|
|
|
player.dispose();
|
|
|
|
});
|
2019-01-08 21:14:46 +02:00
|
|
|
|
|
|
|
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' });
|
|
|
|
|
2019-04-29 18:01:37 +02:00
|
|
|
const oldCreateItems = MenuButton.prototype.createItems;
|
|
|
|
|
2019-01-08 21:14:46 +02:00
|
|
|
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');
|
2019-03-18 21:49:48 +02:00
|
|
|
|
|
|
|
menuButton.dispose();
|
|
|
|
menuItem1.dispose();
|
|
|
|
menuItem2.dispose();
|
|
|
|
player.dispose();
|
2019-04-29 18:01:37 +02:00
|
|
|
|
|
|
|
MenuButton.prototype.createItems = oldCreateItems;
|
2019-01-08 21:14:46 +02:00
|
|
|
});
|
2019-01-25 21:26:36 +02:00
|
|
|
|
2022-04-15 18:56:29 +02:00
|
|
|
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();
|
|
|
|
});
|
|
|
|
|
2019-01-25 21:26:36 +02:00
|
|
|
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) {
|
2019-08-01 20:26:59 +02:00
|
|
|
const eventData = DomData.get(menuItem.eventBusEl_);
|
2019-01-25 21:26:36 +02:00
|
|
|
// `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');
|
|
|
|
|
2019-05-30 17:16:51 +02:00
|
|
|
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
|
2019-01-25 21:26:36 +02:00
|
|
|
// `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);
|
2019-03-18 21:49:48 +02:00
|
|
|
|
2019-01-25 21:26:36 +02:00
|
|
|
TestHelpers.triggerDomEvent(captionMenuItem.el(), 'click');
|
|
|
|
assert.ok(!focusSpy.called, '`menuButton`.`focus` should never be called');
|
|
|
|
|
|
|
|
focusSpy.restore();
|
2019-03-18 21:49:48 +02:00
|
|
|
|
|
|
|
player.dispose();
|
|
|
|
newMenu.dispose();
|
|
|
|
oldMenu.dispose();
|
|
|
|
menuButton.dispose();
|
2019-01-25 21:26:36 +02:00
|
|
|
});
|