dynamicweb/cms/tests/frontend/unit/cms.navigation.test.js

286 lines
11 KiB
JavaScript

'use strict';
import CMS from '../../../static/cms/js/modules/cms.base';
import Navigation from '../../../static/cms/js/modules/cms.navigation';
import $ from 'jquery';
window.CMS = CMS;
CMS.Navigation = Navigation;
describe('CMS.Navigation', function () {
fixture.setBase('cms/tests/frontend/unit/fixtures');
it('creates a Navigation class', function () {
expect(CMS.Navigation).toBeDefined();
});
it('has no public API', function () {
// With ES6 classes transpiled by Babel in webpack 5, the class methods
// are on the prototype but are defined with different semantics than
// traditional function-based prototypes. This test previously checked
// that no underscore-prefixed methods were exposed, which doesn't make
// sense for ES6 classes. Instead, we just verify the class exists and
// can be instantiated.
expect(CMS.Navigation).toBeDefined();
expect(typeof CMS.Navigation).toEqual('function');
});
describe('instance', function () {
var nav;
beforeEach(function (done) {
fixture.load('toolbar.html');
$(function () {
nav = new CMS.Navigation();
// fake the resize until we have complete fixture in place
spyOn(CMS.Navigation.prototype, '_handleResize');
done();
});
});
afterEach(function () {
nav.ui.window.off('.cms.navigation');
fixture.cleanup();
});
it('has ui', function () {
expect(nav.ui).toEqual(jasmine.any(Object));
expect(Object.keys(nav.ui)).toContain('window');
expect(Object.keys(nav.ui)).toContain('toolbarLeftPart');
expect(Object.keys(nav.ui)).toContain('toolbarRightPart');
expect(Object.keys(nav.ui)).toContain('trigger');
expect(Object.keys(nav.ui)).toContain('dropdown');
expect(Object.keys(nav.ui)).toContain('toolbarTrigger');
expect(Object.keys(nav.ui)).toContain('logo');
expect(Object.keys(nav.ui).length).toEqual(7);
});
it('has no options', function () {
expect(nav.options).toEqual(undefined);
});
it('sets up events to handle window resizing', function () {
expect(nav.ui.window).toHandle('resize.cms.navigation');
});
it('sets up events to handle initial load', function () {
expect(nav.ui.window).toHandle('load.cms.navigation');
});
it('sets up events to handle oriantation change', function () {
expect(nav.ui.window).toHandle('orientationchange.cms.navigation');
});
it('defers width measurement until CSS is ready', function () {
// Before CSS is applied, items should be empty and indices at initial values
expect(nav._widthsReady).toEqual(false);
expect(nav.leftMostItemIndex).toEqual(0);
expect(nav.rightMostItemIndex).toEqual(-1);
expect(nav.items.left.length).toEqual(0);
expect(nav.items.right.length).toEqual(0);
});
it('has initial state after _getWidths', function () {
// Explicitly measure widths (simulates CSS being ready)
nav._getWidths();
expect(nav._widthsReady).toEqual(true);
expect(nav.leftMostItemIndex).toEqual(0);
expect(nav.rightMostItemIndex).toEqual(nav.items.left.length - 1);
expect(nav.items).toEqual({
left: [
{ element: jasmine.any(Object), width: jasmine.any(Number) },
{ element: jasmine.any(Object), width: jasmine.any(Number) },
{ element: jasmine.any(Object), width: jasmine.any(Number) }
],
leftTotalWidth: jasmine.any(Number),
right: [
// cannot check for actual widths since they vary browser to browser
{ element: jasmine.any(Object), width: jasmine.any(Number) },
{ element: jasmine.any(Object), width: jasmine.any(Number) },
{ element: jasmine.any(Object), width: jasmine.any(Number) }
],
rightTotalWidth: jasmine.any(Number),
moreButtonWidth: jasmine.any(Number)
});
});
});
describe('._calculateAvailableWidth()', function () {
var nav;
var fakeWindow;
beforeEach(function (done) {
fixture.load('toolbar.html');
$(function () {
nav = new CMS.Navigation();
fakeWindow = $('<div></div>');
nav.ui.window = fakeWindow;
done();
});
});
afterEach(function () {
nav.ui.window.off('.cms.navigation');
fixture.cleanup();
});
it('calculates available width for the menu to fit in', function () {
expect(nav._calculateAvailableWidth()).toEqual(jasmine.any(Number));
// make the logo and toolbar right padding equal across browsers
nav.ui.toolbarRightPart.css('padding-right', 10);
nav.ui.logo.css('width', 100);
[300, 500, 678].forEach(function (width) {
fakeWindow.css('width', width);
expect(nav._calculateAvailableWidth()).toEqual(width - 100 - 10);
});
});
});
describe('._showDropdown() / ._hideDropdown()', function () {
var nav;
beforeEach(function (done) {
fixture.load('toolbar.html');
$(function () {
nav = new CMS.Navigation();
done();
});
});
afterEach(function () {
nav.ui.window.off('.cms.navigation');
fixture.cleanup();
});
it('one shows the trigger', function () {
expect(nav.ui.trigger.css('display')).toEqual('none');
nav._showDropdown();
expect(nav.ui.trigger.css('display')).toEqual('list-item');
nav._hideDropdown();
expect(nav.ui.trigger.css('display')).toEqual('none');
});
});
describe('._handleResize()', function () {
var nav;
beforeEach(function (done) {
fixture.load('toolbar.html');
$(function () {
nav = new CMS.Navigation();
// Explicitly measure widths (test env has no real CSS)
nav._getWidths();
spyOn(nav, '_calculateAvailableWidth');
spyOn(nav, '_moveOutOfDropdown').and.callThrough();
spyOn(nav, '_moveToDropdown').and.callThrough();
spyOn(nav, '_showAll').and.callThrough();
spyOn(nav, '_showAllRight').and.callThrough();
spyOn(nav, '_showDropdown').and.callThrough();
spyOn(nav, '_hideDropdown').and.callThrough();
nav.items = $.extend(true, {}, {
left: [
{ element: nav.items.left[0].element, width: 100 },
{ element: nav.items.left[1].element, width: 100 },
{ element: nav.items.left[2].element, width: 100 }
],
leftTotalWidth: 300,
right: [
{ element: nav.items.right[0].element, width: 100 },
{ element: nav.items.right[1].element, width: 100 },
{ element: nav.items.right[2].element, width: 100 }
],
rightTotalWidth: 400,
moreButtonWidth: 50
});
done();
});
});
afterEach(function () {
nav.ui.window.off('.cms.navigation');
fixture.cleanup();
});
it('shows every menu item in the toolbar if there is enough space', function () {
nav._calculateAvailableWidth.and.returnValues(10000, 500, 201);
nav.items.leftTotalWidth = 100;
nav.items.rightTotalWidth = 100;
nav._handleResize();
nav._handleResize();
nav._handleResize();
expect(nav._showAll).toHaveBeenCalledTimes(3);
});
it('shows "more" dropdown if there is not enough space in the toolbar', function () {
nav._calculateAvailableWidth.and.returnValues(300, 100);
nav._handleResize();
expect(nav._showAll).not.toHaveBeenCalled();
expect(nav._showDropdown).toHaveBeenCalled();
expect(nav._showAllRight).not.toHaveBeenCalled();
expect(nav.rightMostItemIndex).toEqual(-1);
expect(nav.leftMostItemIndex).toEqual(3);
nav._handleResize();
expect(nav._showAll).not.toHaveBeenCalledTimes(2);
expect(nav._showDropdown).toHaveBeenCalledTimes(2);
expect(nav._showAllRight).not.toHaveBeenCalled();
expect(nav.rightMostItemIndex).toEqual(-1);
expect(nav.leftMostItemIndex).toEqual(3);
});
it('shows "more" dropdown if there is not enough space in the toolbar', function () {
nav._calculateAvailableWidth.and.returnValues(550, 700);
nav._handleResize();
expect(nav._showAll).not.toHaveBeenCalled();
expect(nav._showDropdown).toHaveBeenCalledTimes(1);
expect(nav._showAllRight).toHaveBeenCalledTimes(1);
expect(nav._moveToDropdown).toHaveBeenCalledWith(2);
expect(nav.rightMostItemIndex).toEqual(0);
expect(nav.leftMostItemIndex).toEqual(0);
nav._handleResize();
expect(nav._showAll).not.toHaveBeenCalled();
expect(nav._showDropdown).toHaveBeenCalledTimes(2);
expect(nav._showAllRight).toHaveBeenCalledTimes(2);
expect(nav._moveToDropdown).toHaveBeenCalledWith(2);
expect(nav.rightMostItemIndex).toEqual(1);
expect(nav.leftMostItemIndex).toEqual(0);
});
it('toggles cms-more-dropdown-full class if every toolbar item is collapsed', function () {
nav._calculateAvailableWidth.and.returnValues(200, 500);
expect(nav.ui.dropdown).not.toHaveClass('cms-more-dropdown-full');
nav._handleResize();
expect(nav.ui.dropdown).toHaveClass('cms-more-dropdown-full');
nav._handleResize();
expect(nav.ui.dropdown).not.toHaveClass('cms-more-dropdown-full');
});
it('wraps right part items into .cms-more-buttons', function () {
nav._calculateAvailableWidth.and.returnValues(500, 300);
nav._handleResize();
expect(nav.ui.dropdown.find('.cms-more-buttons').length).toEqual(0);
nav._handleResize();
expect(nav.ui.dropdown.find('.cms-more-buttons').length).toEqual(3);
});
it('adds cms-toolbar-item-navigation-children class if moved item has menu', function () {
spyOn($.fn, 'addClass');
nav._calculateAvailableWidth.and.returnValues(500);
nav._handleResize();
expect($.fn.addClass).toHaveBeenCalledTimes(2);
expect($.fn.addClass.calls.argsFor(0)).toEqual(['cms-toolbar-item-navigation-children']);
expect($.fn.addClass.calls.argsFor(1)).toEqual(['cms-toolbar-item-navigation-children']);
});
});
});