describe('Drilldown Menu', function() { var plugin; var $html; var template = ``; var templateWithToggler = `
`; afterEach(function() { plugin.destroy(); document.activeElement.blur(); $html.remove(); }); describe('constructor()', function() { it('stores the element and plugin options', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); plugin.$element.should.be.an('object'); plugin.options.should.be.an('object'); }); }); describe('init()', function() { it('stores additional elements', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); plugin.$submenuAnchors.should.be.an('object'); plugin.$submenus.should.be.an('object'); plugin.$menuItems.should.be.an('object'); }); }); describe('prepareMenu()', function() { it('wraps the submenus', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); }); it('adds ARIA attributes', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); plugin.$element.should.have.attr('role', 'tree'); plugin.$element.find('[data-submenu]').each(function() { $(this).should.have.attr('role', 'group'); $(this).should.have.attr('aria-hidden', 'true'); }); plugin.$element.find('.is-drilldown-submenu-parent').each(function() { $(this).should.have.attr('aria-haspopup', 'true'); $(this).should.have.attr('aria-expanded', 'false'); $(this).should.have.attr('aria-label', $(this).children('a').first().text()); }); plugin.$element.find('li:not(.js-drilldown-back)').each(function() { $(this).should.have.attr('role', 'treeitem'); }); }); }); describe('show()', function() { it('shows the given submenu', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(0).find('ul').should.have.class('is-active'); }); it('toggles ARIA attributes', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); $html.find('li.is-drilldown-submenu-parent').eq(0).should.have.attr('aria-expanded', 'true'); $html.find('li.is-drilldown-submenu-parent').eq(0).children('ul').should.have.attr('aria-hidden', 'false'); }); it('fires open.zf.drilldown event', function(done) { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.on('open.zf.drilldown', function() { // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(0).find('ul').should.have.class('is-active'); done(); }); plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); }); }); describe('hide()', function() { it('hides the given submenu', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open it first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); plugin._hide($html.find('li.is-drilldown-submenu-parent').eq(0).children('ul')); // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(0).children('ul').should.have.class('is-closing'); }); it('toggles ARIA attributes', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open it first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); plugin._hide($html.find('li.is-drilldown-submenu-parent').eq(0).children('ul')); $html.find('li.is-drilldown-submenu-parent').eq(0).should.have.attr('aria-expanded', 'false'); $html.find('li.is-drilldown-submenu-parent').eq(0).children('ul').should.have.attr('aria-hidden', 'true'); }); it('fires hide.zf.drilldown event', function(done) { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open it first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(0)); $html.on('hide.zf.drilldown', function() { // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(0).children('ul').should.have.class('is-closing'); done(); }); plugin._hide($html.find('li.is-drilldown-submenu-parent').eq(0).children('ul')); }); }); describe('hideAll()', function() { it('hides all submenus', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open one first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(2)); plugin._hideAll(); $html.find('ul[data-submenu].is-active').each(function() { // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $(this).should.have.class('is-closing'); }); }); it('fires closed.zf.drilldown event', function(done) { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open one first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(2)); $html.one('closed.zf.drilldown', function() { $html.find('ul[data-submenu].is-active').each(function() { // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $(this).should.have.class('is-closing'); }); done(); }); plugin._hideAll(); }); }); describe('back()', function() { it('hides current submenu', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open one first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(1)); $html.find('li.is-drilldown-submenu-parent').eq(1).children('ul').children('.js-drilldown-back').trigger('click'); // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(1).children('ul').should.have.class('is-closing'); }); it('shows parent submenu', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open one first plugin._show($html.find('li.is-drilldown-submenu-parent').eq(1)); $html.find('li.is-drilldown-submenu-parent').eq(1).children('ul').children('.js-drilldown-back').trigger('click'); // Checking with .be.hidden is not possible because they don't have display: block but z-index: -1 $html.find('li.is-drilldown-submenu-parent').eq(0).children('ul').should.have.class('is-active'); }); }); describe('toggle events', function () { var $trigger, $target, $wrapper, togglerPlugin; beforeEach(function () { $html = $(templateWithToggler).appendTo('body'); $trigger = $html.find('#trigger'); $target = $html.find('#target'); $target = $html.find('#target'); togglerPlugin = new Foundation.Toggler($target, {}); plugin = new Foundation.Drilldown($html.find('[data-drilldown]'), { autoHeight: true }); $wrapper = $html.find('.is-drilldown'); }); it('correctly resize when opened', function () { // Open the Drilldown $trigger.focus().trigger('click'); // 3 items (including the back button) is around 115px height $wrapper.height().should.be.within(110, 120); }); it('correctly resize when closed', function () { // Open then close the Drilldown $trigger.focus().trigger('click'); $trigger.focus().trigger('click'); $wrapper.height().should.be.equal(0); }); it('correctly resize when reopened on a submenu', function () { // Open the Drilldown $trigger.focus().trigger('click'); // Show a submenu with a smaller height plugin._showMenu($html.find('#Menu-1A')); // Close then reopen the the Drilldown $trigger.focus().trigger('click'); $trigger.focus().trigger('click'); // 2 items (including the back button) is around 75px height $wrapper.height().should.be.within(70, 80); }); afterEach(function () { togglerPlugin.destroy(); }); }); describe('keyboard events', function() { // Currently not testable, as triggered event won't move on focus it.skip('does not trap focus on root element going down', function() { $html = $(template).appendTo('body'); let $dummyElement = $('Dummy').appendTo('body'); // Dummy target to see if focus is not trapped plugin = new Foundation.Drilldown($html, {}); // Focus last element $dummyElement.focus(); $html.find('> li:last-child > a').trigger(window.mockKeyboardEvent('TAB')); document.activeElement.should.not.be.equal($html.find('> li:last-child > a')[0]); $dummyElement.remove(); }); // Currently not testable, as triggered event won't move on focus it.skip('does not trap focus on root element going up', function() { let $dummyElement = $('Dummy').appendTo('body'); // Dummy target to see if focus is not trapped $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Focus first element $dummyElement.focus(); $html.find('> li:first-child > a').trigger(window.mockKeyboardEvent('TAB', {shift: true})); document.activeElement.should.not.be.equal($html.find('> li:first-child > a')[0]); $dummyElement.remove(); }); it('closes current sub menu using ESC', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open it first plugin._show($html.find('> li:nth-child(1)')) $html.find('> li:nth-child(1) > ul > li:first-child > a').focus() .trigger(window.mockKeyboardEvent('ESCAPE')); $html.find('> li:nth-child(1) > ul').should.have.class('is-closing'); }); it('moves focus to next element on TAB', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.find('> li:nth-child(1) > a').focus() .trigger(window.mockKeyboardEvent('TAB')); document.activeElement.should.be.equal($html.find('> li:nth-child(2) > a')[0]); }); it('moves focus to previous element on TAB', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.find('> li:nth-child(2) > a').focus() .trigger(window.mockKeyboardEvent('TAB', {shift: true})); document.activeElement.should.be.equal($html.find('> li:nth-child(1) > a')[0]); }); it('moves focus to next element on ARROW_DOWN', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.find('> li:nth-child(1) > a').focus() .trigger(window.mockKeyboardEvent('ARROW_DOWN')); document.activeElement.should.be.equal($html.find('> li:nth-child(2) > a')[0]); }); it('moves focus to previous element on ARROW_UP', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.find('> li:nth-child(2) > a').focus() .trigger(window.mockKeyboardEvent('ARROW_UP')); document.activeElement.should.be.equal($html.find('> li:nth-child(1) > a')[0]); }); it('opens child element on ARROW_RIGHT', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); $html.find('> li:nth-child(1) > a').focus() .trigger(window.mockKeyboardEvent('ARROW_RIGHT')); $html.find('> li:nth-child(1) > ul').should.have.class('is-active'); }); it('focuses parent link if parentLink is true', function(done) { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {parentLink: true}); $html.find('> li:nth-child(1) > a').focus() .trigger(window.mockKeyboardEvent('ARROW_RIGHT')); setTimeout(function() { // Timeout to make sure transition has ended $html.find('> li:nth-child(1) > ul > li[data-is-parent-link] a')[0].should.be.equal(document.activeElement); done(); }, 500); }); it('closes child element on ARROW_LEFT', function() { $html = $(template).appendTo('body'); plugin = new Foundation.Drilldown($html, {}); // Open it first plugin._show($html.find('> li:nth-child(1)')) $html.find('> li:nth-child(1) > ul > li:first-child > a').focus() .trigger(window.mockKeyboardEvent('ARROW_LEFT')); $html.find('> li:nth-child(1) > ul').should.have.class('is-closing'); }); }); });