mediawiki-skins-Vector/tests/jest/pinnableElement.test.js
Jon Robson 2499e834bb Remove Eslint disable and TypeScript ignore rules, bump coverage
Follow up to 87dd101a
* bump coverage to reflect improved test state
* remove ts-ignore statements
* Drop eslint-disable-next-line compat/compat rules in ES6 code
* Drop TypeScript checking on Jest files
* Identifies an existing usage of ES7 includes method in place
where ES6 browsers need to be supported.
* Update App.vue booleans to default to false. Note this doesn't
impact our usage of the search app as we always pass these values
in.
* Drop unused eslintEs6.json configuration file

Change-Id: Ib6f1ef77bf4e27ecdcc54b5fb963818437f8195c
2023-04-13 00:20:44 +00:00

163 lines
7 KiB
JavaScript

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 = `<div id="pinnable-element">${pinnableHeaderHTML}</div>`;
document.body.innerHTML = `<div id="pinned-container">
${headerData[ 'is-pinned' ] ? pinnableElementHTML : ''}
</div>
<div class="vector-dropdown">
<input type="checkbox" id="checkbox" class="vector-menu-checkbox">
<label for="checkbox" class="vector-menu-heading ">
<span class="vector-menu-heading-label">Dropdown</span>
</label>
<div class="vector-menu-content">
<div id="unpinned-container">
${!headerData[ 'is-pinned' ] ? pinnableElementHTML : ''}
</div>
</div>
</div>
`;
};
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 );
} );
} );