import { expect, html } from '@open-wc/testing'; import { GlobalOverlayController } from '../src/GlobalOverlayController.js'; import { overlays } from '../src/overlays.js'; function getRootNode() { return document.querySelector('.global-overlays'); } function getRenderedContainers() { const rootNode = getRootNode(); return rootNode ? Array.from(rootNode.children) : []; } function getRenderedContainer(index) { return getRenderedContainers()[index]; } function getRenderedOverlay(index) { const container = getRenderedContainer(index); return container ? container.children[0] : null; } function cleanup() { document.body.removeAttribute('style'); overlays.teardown(); } describe('Managed GlobalOverlayController', () => { afterEach(cleanup); describe('hasBackdrop', () => { it('adds and stacks backdrops if .hasBackdrop is enabled', async () => { const ctrl0 = overlays.add( new GlobalOverlayController({ hasBackdrop: true, contentTemplate: () => html`

Content0

`, }), ); await ctrl0.show(); expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); const ctrl1 = overlays.add( new GlobalOverlayController({ hasBackdrop: false, contentTemplate: () => html`

Content1

`, }), ); await ctrl1.show(); expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); expect(ctrl1.backdropNode).to.be.undefined; const ctrl2 = overlays.add( new GlobalOverlayController({ hasBackdrop: true, contentTemplate: () => html`

Content2

`, }), ); await ctrl2.show(); expect(ctrl0.backdropNode).to.have.class('global-overlays__backdrop'); expect(ctrl1.backdropNode).to.be.undefined; expect(ctrl2.backdropNode).to.have.class('global-overlays__backdrop'); }); }); describe('isBlocking', () => { it('prevents showing of other overlays', async () => { const ctrl0 = overlays.add( new GlobalOverlayController({ isBlocking: false, contentTemplate: () => html`

Content0

`, }), ); await ctrl0.show(); const ctrl1 = overlays.add( new GlobalOverlayController({ isBlocking: false, contentTemplate: () => html`

Content1

`, }), ); await ctrl1.show(); const ctrl2 = overlays.add( new GlobalOverlayController({ isBlocking: true, contentTemplate: () => html`

Content2

`, }), ); await ctrl2.show(); const ctrl3 = overlays.add( new GlobalOverlayController({ isBlocking: false, contentTemplate: () => html`

Content3

`, }), ); await ctrl3.show(); expect(getRenderedOverlay(0)).to.not.be.displayed; expect(getRenderedOverlay(1)).to.not.be.displayed; expect(getRenderedOverlay(2)).to.be.displayed; expect(getRenderedOverlay(3)).to.not.be.displayed; }); it('keeps backdrop status when used in combination with blocking', async () => { const ctrl0 = overlays.add( new GlobalOverlayController({ isBlocking: false, hasBackdrop: true, contentTemplate: () => html`

Content0

`, }), ); await ctrl0.show(); const ctrl1 = overlays.add( new GlobalOverlayController({ isBlocking: false, hasBackdrop: true, contentTemplate: () => html`

Content1

`, }), ); await ctrl1.show(); await ctrl1.hide(); expect(ctrl0.hasActiveBackdrop).to.be.true; expect(ctrl1.hasActiveBackdrop).to.be.false; await ctrl1.show(); expect(ctrl0.hasActiveBackdrop).to.be.true; expect(ctrl1.hasActiveBackdrop).to.be.true; }); }); describe('trapsKeyboardFocus (for a11y)', () => { it('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => { const ctrl = overlays.add( new GlobalOverlayController({ trapsKeyboardFocus: true, contentTemplate: () => html`

Content

`, }), ); const sibling1 = document.createElement('div'); const sibling2 = document.createElement('div'); document.body.insertBefore(sibling1, getRootNode()); document.body.appendChild(sibling2); await ctrl.show(); [sibling1, sibling2].forEach(sibling => { expect(sibling).to.have.attribute('aria-hidden', 'true'); expect(sibling).to.have.attribute('inert'); }); expect(getRenderedOverlay(0).hasAttribute('aria-hidden')).to.be.false; expect(getRenderedOverlay(0).hasAttribute('inert')).to.be.false; await ctrl.hide(); [sibling1, sibling2].forEach(sibling => { expect(sibling).to.not.have.attribute('aria-hidden'); expect(sibling).to.not.have.attribute('inert'); }); // cleanup document.body.removeChild(sibling1); document.body.removeChild(sibling2); }); /** * style.userSelect: * - chrome: 'none' * - rest: undefined * * style.pointerEvents: * - chrome: auto * - IE11: visiblePainted */ it('disables pointer events and selection on inert elements', async () => { const ctrl = overlays.add( new GlobalOverlayController({ trapsKeyboardFocus: true, contentTemplate: () => html`

Content

`, }), ); // show+hide are needed to create a root node await ctrl.show(); await ctrl.hide(); const sibling1 = document.createElement('div'); const sibling2 = document.createElement('div'); document.body.insertBefore(sibling1, getRootNode()); document.body.appendChild(sibling2); await ctrl.show(); [sibling1, sibling2].forEach(sibling => { expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['none', undefined]); expect(window.getComputedStyle(sibling).pointerEvents).to.equal('none'); }); expect(window.getComputedStyle(getRenderedOverlay(0)).userSelect).to.be.oneOf([ 'auto', undefined, ]); expect(window.getComputedStyle(getRenderedOverlay(0)).pointerEvents).to.be.oneOf([ 'auto', 'visiblePainted', ]); await ctrl.hide(); [sibling1, sibling2].forEach(sibling => { expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['auto', undefined]); expect(window.getComputedStyle(sibling).pointerEvents).to.be.oneOf([ 'auto', 'visiblePainted', ]); }); // cleanup document.body.removeChild(sibling1); document.body.removeChild(sibling2); }); it('keeps focus within overlay with multiple overlays with all traps on true', async () => { const ctrl0 = overlays.add( new GlobalOverlayController({ trapsKeyboardFocus: true, contentTemplate: () => html`
Link0
`, }), ); const ctrl1 = overlays.add( new GlobalOverlayController({ trapsKeyboardFocus: true, contentTemplate: () => html`
Link1
`, }), ); await ctrl0.show(); await ctrl1.show(); expect(ctrl0.hasActiveTrapsKeyboardFocus).to.be.false; expect(ctrl1.hasActiveTrapsKeyboardFocus).to.be.true; await ctrl1.hide(); expect(ctrl0.hasActiveTrapsKeyboardFocus).to.be.true; expect(ctrl1.hasActiveTrapsKeyboardFocus).to.be.false; }); }); });