UNPKG

@carbon/ibm-products-web-components

Version:

Carbon for IBM Products Web Components

253 lines (250 loc) 15 kB
/** * Copyright IBM Corp. 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { describe, it, expect, afterEach } from 'vitest'; import { fixture, oneEvent, html } from '@open-wc/testing'; import { SIDE_PANEL_SIZE, SIDE_PANEL_PLACEMENT } from './defs.js'; import { prefix } from '../../globals/settings.js'; import './side-panel.js'; import { getContent, getSlug, getActionToolbarItems, getSubTitle, getActionItems } from './_story-assets/index.js'; import '@carbon/web-components/es-custom/components/text-input/index.js'; import '@carbon/web-components/es-custom/components/slug/index.js'; /** * Copyright IBM Corp. 2024, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const defaultProps = { animateTitle: true, includeOverlay: true, slideIn: false, selectorInitialFocus: '', label: '', open: true, placement: SIDE_PANEL_PLACEMENT.RIGHT, preventCloseOnClickOutside: false, selectorPageContent: '', size: SIDE_PANEL_SIZE.MEDIUM, title: 'Side panel title', condensedActions: false, }; const blockClass = `${prefix}--side-panel`; const template = (props = defaultProps, children = getContent(1)) => html ` <c4p-side-panel ?animate-title=${props.animateTitle} ?include-overlay=${props.includeOverlay && !props.slideIn} selector-initial-focus=${props.selectorInitialFocus} label-text="${props.label}" ?open=${props.open} placement=${props.placement} ?prevent-close-on-click-outside=${props.preventCloseOnClickOutside} selector-page-content=${props.selectorPageContent} size=${props.size} ?slide-in=${props.slideIn} .title=${props.title} > ${children} </c4p-side-panel> `; describe('c4p-side-panel', () => { it('should render a side panel', async () => { const sidePanel = (await fixture(template())); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeTruthy(); expect(sidePanel).toBeDefined(); }); it('should render a side panel on the left', async () => { var _a, _b, _c; const sidePanel = (await fixture(template(Object.assign(Object.assign({}, defaultProps), { placement: SIDE_PANEL_PLACEMENT.LEFT })))); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.placement).toBe('left'); const dialogShadowEl = (_b = (_a = sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`.${blockClass}`)) === null || _b === void 0 ? void 0 : _b[0]; if (dialogShadowEl) { const transform = (_c = window.getComputedStyle(dialogShadowEl)) === null || _c === void 0 ? void 0 : _c.transform; expect(transform).toBe('matrix(1, 0, 0, 1, -414, 0)'); } }); it('should render a side panel on the right', async () => { var _a, _b, _c; const sidePanel = (await fixture(template())); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.placement).toBe('right'); const dialogShadowEl = (_b = (_a = sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`.${blockClass}`)) === null || _b === void 0 ? void 0 : _b[0]; if (dialogShadowEl) { const transform = (_c = window.getComputedStyle(dialogShadowEl)) === null || _c === void 0 ? void 0 : _c.transform; expect(transform).toBe('matrix(1, 0, 0, 1, 414, 0)'); } }); it('should render a side panel with overlay and close when clicked outside', async () => { var _a, _b; const sidePanel = (await fixture(template())); // Expect the side panel has include-overlay attribute expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.includeOverlay).toBeTruthy(); // get the overlay element by class .c4p--side-panel__overlay const overlayElement = (_b = (_a = sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`.${blockClass}__overlay`)) === null || _b === void 0 ? void 0 : _b[0]; // expect the element is present expect(overlayElement).toBeDefined(); // ensure its tab index is -1 expect(overlayElement === null || overlayElement === void 0 ? void 0 : overlayElement.getAttribute('tabindex')).toBe('-1'); // ensure open attribute present expect(overlayElement === null || overlayElement === void 0 ? void 0 : overlayElement.hasAttribute('open')).toBeTruthy(); // ensure the preventCloseOnClickOutside property is disabled expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.preventCloseOnClickOutside).toBeFalsy(); // add event listener `cds-custom-side-panel-beingclosed` event const eventBeforeClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-beingclosed` sidePanel.constructor.eventBeforeClose); // add event listener `cds-custom-side-panel-closed` event const eventClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-closed` sidePanel.constructor.eventClose); // dispatch `cds-custom-side-panel-beingclosed` and `cds-custom-side-panel-closed` events on overlay element click overlayElement === null || overlayElement === void 0 ? void 0 : overlayElement.dispatchEvent(new Event('click')); // listen to `cds-custom-side-panel-beingclosed` and `cds-custom-side-panel-closed` event // and take the details of events const { detail: beforeCloseDetail } = await eventBeforeClose; const { detail: closeDetail } = await eventClose; // make sure both events are triggered by overlay element expect(beforeCloseDetail === null || beforeCloseDetail === void 0 ? void 0 : beforeCloseDetail.triggeredBy).toBe(overlayElement); expect(closeDetail === null || closeDetail === void 0 ? void 0 : closeDetail.triggeredBy).toBe(overlayElement); // expect the side panel is closed expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeFalsy(); // expect overlay also closed expect(overlayElement === null || overlayElement === void 0 ? void 0 : overlayElement.hasAttribute('open')).toBeFalsy(); }); it('should close side panel on escape keydown', async () => { const sidePanel = (await fixture(template())); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeTruthy(); // add event listener `cds-custom-side-panel-beingclosed` event const eventBeforeClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-beingclosed` sidePanel.constructor.eventBeforeClose); // add event listener `cds-custom-side-panel-closed` event const eventClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-closed` sidePanel.constructor.eventClose); // press the escape key document === null || document === void 0 ? void 0 : document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' })); // listen to `cds-custom-side-panel-beingclosed` and `cds-custom-side-panel-closed` event // and take the details of events const { detail: beforeCloseDetail } = await eventBeforeClose; const { detail: closeDetail } = await eventClose; // make sure both events are triggered from document expect(beforeCloseDetail === null || beforeCloseDetail === void 0 ? void 0 : beforeCloseDetail.triggeredBy).toBe(document); expect(closeDetail === null || closeDetail === void 0 ? void 0 : closeDetail.triggeredBy).toBe(document); // expect the side panel is closed expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeFalsy(); }); it('should close side panel on the close button click', async () => { var _a; const sidePanel = (await fixture(template())); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeTruthy(); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.closeIconDescription).toBe('Close'); // get the close button const closeButton = (_a = sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('cds-custom-icon-button'); // ensure the close button is present expect(closeButton).toBeDefined(); // add event listener `cds-custom-side-panel-beingclosed` event const eventBeforeClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-beingclosed` sidePanel.constructor.eventBeforeClose); // add event listener `cds-custom-side-panel-closed` event const eventClose = oneEvent(sidePanel, // getting event name ie., `cds-custom-side-panel-closed` sidePanel.constructor.eventClose); // click on the close button closeButton === null || closeButton === void 0 ? void 0 : closeButton.dispatchEvent(new Event('click')); // listen to `cds-custom-side-panel-beingclosed` and `cds-custom-side-panel-closed` event // and take the details of events const { detail: beforeCloseDetail } = await eventBeforeClose; const { detail: closeDetail } = await eventClose; // make sure both events are triggered by overlay element expect(beforeCloseDetail === null || beforeCloseDetail === void 0 ? void 0 : beforeCloseDetail.triggeredBy).toBe(closeButton); expect(closeDetail === null || closeDetail === void 0 ? void 0 : closeDetail.triggeredBy).toBe(closeButton); // expect the side panel is closed expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeFalsy(); }); it('should render a slug', async () => { const sidePanel = (await fixture(template(defaultProps, getSlug(1)))); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeTruthy(); // ensure there is a slug present expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel._hasSlug).toBeTruthy(); // locate slug element const slug = sidePanel.querySelector('cds-custom-slug'); // expect the slug element is present expect(slug).toBeDefined(); // expect the default slug size is xs expect(slug.size).toBe('xs'); }); it('should render navigation button', async () => { const sidePanel = (await fixture(template(defaultProps, getActionToolbarItems(1)))); expect(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.open).toBeTruthy(); // get the copy button const copyButton = Array.prototype.find.call(sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.querySelectorAll('cds-custom-button'), (el) => el.innerHTML === 'Copy'); // expect copy button to be present expect(copyButton).toBeDefined(); }); it('should render a slide-in side panel', async () => { var _a, _b; const sidePanel = (await fixture(template(Object.assign(Object.assign({}, defaultProps), { slideIn: true })))); expect(sidePanel.slideIn).toBeTruthy(); expect(sidePanel.includeOverlay).toBeFalsy(); // try to get the overlay element by class .c4p--side-panel__overlay const overlayElement = (_b = (_a = sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`.${blockClass}__overlay`)) === null || _b === void 0 ? void 0 : _b[0]; // expect the element is not present expect(overlayElement).not.toBeDefined(); }); it('should call the eventNavigateBack callback', async () => { var _a; const prevStep = () => { var _a; (_a = document .querySelector(`${prefix}-side-panel`)) === null || _a === void 0 ? void 0 : _a.setAttribute('current-step', '1'); }; const sidePanel = (await fixture(html `<c4p-side-panel ?animate-title=${defaultProps.animateTitle} ?condensed-actions=${defaultProps.condensedActions} current-step="1" ?include-overlay=${defaultProps.includeOverlay && !defaultProps.slideIn} selector-initial-focus=${defaultProps.selectorInitialFocus} label-text="${defaultProps.label}" ?open=${defaultProps.open} placement=${defaultProps.placement} ?prevent-close-on-click-outside=${defaultProps.preventCloseOnClickOutside} selector-page-content=${defaultProps.selectorPageContent} size=${defaultProps.size} ?slide-in=${defaultProps.slideIn} .title=${defaultProps.title} @c4p-side-panel-navigate-back=${prevStep} >${getContent(1)}</<c4p-side-panel`)); const backButton = (_a = sidePanel.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`.${prefix}--side-panel__navigation-back-button`); // create event listener const eventNavigateBack = oneEvent(sidePanel, sidePanel.constructor.eventNavigateBack); // dispatch the event from click of back button backButton === null || backButton === void 0 ? void 0 : backButton.dispatchEvent(new Event('click')); // expect the detail object of eventNavigateBack method const { detail } = await eventNavigateBack; expect(detail).toBeDefined(); }); it('should render subtitle text', async () => { const sidePanel = (await fixture(template(defaultProps, getSubTitle(1)))); const subTitleText = sidePanel === null || sidePanel === void 0 ? void 0 : sidePanel.querySelector(`.${prefix}--side-panel__subtitle-text`); expect(subTitleText).toBeDefined(); }); it('should render at least one action item', async () => { const sidePanel = (await fixture(template(defaultProps, getActionItems(1)))); const actionItems = sidePanel.querySelectorAll(`.${prefix}--action-set__action-button`); expect(actionItems).toHaveLength(1); }); it('should render only 3 action items even if too many items exists', async () => { const sidePanel = (await fixture(template(defaultProps, getActionItems(6)))); const actionItems = sidePanel.querySelectorAll(`.${prefix}--action-set__action-button`); expect(actionItems).toHaveLength(3); }); afterEach(() => { // Clears the DOM after each test document.body.innerHTML = ''; }); }); //# sourceMappingURL=side-panel.test.js.map