jest.mock( '../../resources/skins.vector.js/features.js' ); const features = require( '../../resources/skins.vector.js/features.js' ); const mustache = require( 'mustache' ); const fs = require( 'fs' ); const pinnableHeaderTemplate = fs.readFileSync( 'includes/templates/PinnableHeader.mustache', 'utf8' ); const pinnableElement = require( '../../resources/skins.vector.js/pinnableElement.js' ); /** * Mock for matchMedia, which is not included in JSDOM. * https://jestjs.io/docs/26.x/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom */ Object.defineProperty( window, 'matchMedia', { writable: true, value: jest.fn().mockImplementation( ( query ) => ( { matches: false, media: query, onchange: null, addListener: jest.fn(), // deprecated removeListener: jest.fn(), // deprecated addEventListener: jest.fn(), removeEventListener: jest.fn(), dispatchEvent: jest.fn() } ) ) } ); // Mock functionality of features.js let pinnedStatus = false; features.toggle = jest.fn( () => { pinnedStatus = !pinnedStatus; } ); features.isEnabled = jest.fn( () => { return pinnedStatus; } ); const simpleData = { 'is-pinned': false, 'data-feature-name': 'pinned', 'data-pinnable-element-id': 'pinnable-element', label: 'simple pinnable element', 'label-tag-name': 'div', 'pin-label': 'pin', 'unpin-label': 'unpin' }; const movableData = { ...simpleData, ...{ 'data-pinned-container-id': 'pinned-container', 'data-unpinned-container-id': 'unpinned-container' } }; const initializeHTML = ( headerData ) => { pinnedStatus = headerData[ 'is-pinned' ]; const pinnableHeaderHTML = mustache.render( pinnableHeaderTemplate, headerData ); const pinnableElementHTML = `
${ pinnableHeaderHTML }
`; document.body.innerHTML = `
${ headerData[ 'is-pinned' ] ? pinnableElementHTML : '' }
${ !headerData[ 'is-pinned' ] ? pinnableElementHTML : '' }
`; }; describe( 'Pinnable header', () => { test( 'renders', () => { initializeHTML( simpleData ); expect( document.body.innerHTML ).toMatchSnapshot(); } ); test( 'updates pinnable header classes when toggle is pressed', () => { initializeHTML( simpleData ); pinnableElement.initPinnableElement(); const pinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-pin-button' ) ); const unpinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-unpin-button' ) ); const header = /** @type {HTMLElement} */ ( document.querySelector( `.${ simpleData[ 'data-pinnable-element-id' ] }-pinnable-header` ) ); expect( header.classList.contains( pinnableElement.PINNED_HEADER_CLASS ) ).toBe( false ); expect( header.classList.contains( pinnableElement.UNPINNED_HEADER_CLASS ) ).toBe( true ); pinButton.click(); expect( header.classList.contains( pinnableElement.PINNED_HEADER_CLASS ) ).toBe( true ); expect( header.classList.contains( pinnableElement.UNPINNED_HEADER_CLASS ) ).toBe( false ); unpinButton.click(); expect( header.classList.contains( pinnableElement.PINNED_HEADER_CLASS ) ).toBe( false ); expect( header.classList.contains( pinnableElement.UNPINNED_HEADER_CLASS ) ).toBe( true ); } ); test( 'doesnt move pinnable element when data attributes arent defined', () => { initializeHTML( simpleData ); pinnableElement.initPinnableElement(); const pinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-pin-button' ) ); const unpinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-unpin-button' ) ); const pinnableElem = /** @type {HTMLElement} */ ( document.getElementById( simpleData[ 'data-pinnable-element-id' ] ) ); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'unpinned-container' ); pinButton.click(); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'unpinned-container' ); unpinButton.click(); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'unpinned-container' ); } ); test( 'moves pinnable element when data attributes are defined', () => { initializeHTML( movableData ); pinnableElement.initPinnableElement(); const pinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-pin-button' ) ); const unpinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-unpin-button' ) ); const pinnableElem = /** @type {HTMLElement} */ ( document.getElementById( movableData[ 'data-pinnable-element-id' ] ) ); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'unpinned-container' ); pinButton.click(); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'pinned-container' ); unpinButton.click(); expect( pinnableElem.parentElement && pinnableElem.parentElement.id ).toBe( 'unpinned-container' ); } ); test( 'calls features.toggle() when toggle is pressed', () => { initializeHTML( simpleData ); pinnableElement.initPinnableElement(); const pinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-pin-button' ) ); const unpinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-unpin-button' ) ); pinButton.click(); expect( features.toggle ).toHaveBeenCalledTimes( 1 ); expect( features.toggle ).toHaveBeenCalledWith( simpleData[ 'data-feature-name' ] ); features.toggle.mockClear(); unpinButton.click(); expect( features.toggle ).toHaveBeenCalledTimes( 1 ); expect( features.toggle ).toHaveBeenCalledWith( simpleData[ 'data-feature-name' ] ); } ); test( 'isPinned() calls features.isEnabled()', () => { initializeHTML( simpleData ); pinnableElement.initPinnableElement(); const header = /** @type {HTMLElement} */ ( document.querySelector( `.${ simpleData[ 'data-pinnable-element-id' ] }-pinnable-header` ) ); features.isEnabled.mockClear(); pinnableElement.isPinned( header ); expect( features.isEnabled ).toHaveBeenCalledTimes( 1 ); expect( features.isEnabled ).toHaveBeenCalledWith( simpleData[ 'data-feature-name' ] ); } ); test( 'setFocusAfterToggle() sets focus on appropriate element after pinnableElement is toggled', () => { initializeHTML( movableData ); pinnableElement.initPinnableElement(); const dropdownCheckbox = /** @type {HTMLElement} */ ( document.getElementById( 'checkbox' ) ); const pinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-pin-button' ) ); const unpinButton = /** @type {HTMLElement} */ ( document.querySelector( '.vector-pinnable-header-unpin-button' ) ); pinButton.click(); expect( document.activeElement ).toBe( unpinButton ); unpinButton.click(); expect( document.activeElement ).toBe( dropdownCheckbox ); } ); } );