import { expect, fixture as _fixture } from '@open-wc/testing'; import { html } from 'lit/static-html.js'; import '@lion/ui/define/lion-collapsible.js'; /** * @typedef {import('../src/LionCollapsible').LionCollapsible} LionCollapsible * @typedef {import('@lion/core').TemplateResult} TemplateResult */ const fixture = /** @type {(arg: TemplateResult) => Promise} */ (_fixture); const collapsibleTemplate = html`
Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods.
`; let isCollapsibleOpen = false; /** @param {boolean} state */ const collapsibleToggle = state => { isCollapsibleOpen = state; }; const defaultCollapsible = html` ${collapsibleTemplate} `; const collapsibleWithEvents = html` collapsibleToggle(/** @type {LionCollapsible} */ (e.target)?.opened) } > ${collapsibleTemplate} `; /** * @param {LionCollapsible} el */ function getProtectedMembers(el) { return { // @ts-ignore contentHeight: el._contentHeight, }; } describe('', () => { describe('Collapsible', () => { it('sets opened to false by default', async () => { const collapsible = await fixture(defaultCollapsible); expect(collapsible.opened).to.equal(false); }); it('has [opened] on current expanded invoker which serves as styling hook', async () => { const collapsible = await fixture(defaultCollapsible); collapsible.opened = true; await collapsible.updateComplete; expect(collapsible).to.have.attribute('opened'); }); it('should return content node height before and after collapsing', async () => { const collapsible = await fixture(defaultCollapsible); const collHeight1 = getProtectedMembers(collapsible); expect(collHeight1.contentHeight).to.equal('0px'); collapsible.show(); await collapsible.updateComplete; const collHeight2 = getProtectedMembers(collapsible); expect(collHeight2.contentHeight).to.equal('32px'); }); }); describe('User interaction', () => { it('opens a invoker on click', async () => { const collapsible = await fixture(defaultCollapsible); const invoker = collapsible.querySelector('[slot=invoker]'); invoker?.dispatchEvent(new Event('click')); expect(collapsible.opened).to.equal(true); }); it('should toggle the content using `toggle()`', async () => { const collapsible = await fixture(defaultCollapsible); collapsible.toggle(); expect(collapsible.opened).to.equal(true); }); it('should expand and collapse the content using `show()` and `hide()`', async () => { const collapsible = await fixture(defaultCollapsible); collapsible.show(); expect(collapsible.opened).to.equal(true); collapsible.hide(); expect(collapsible.opened).to.equal(false); }); it('should listen to the open and close state change', async () => { const collapsible = await fixture(collapsibleWithEvents); collapsible.show(); await collapsible.updateComplete; expect(isCollapsibleOpen).to.equal(true); collapsible.hide(); await collapsible.updateComplete; expect(isCollapsibleOpen).to.equal(false); }); }); describe('Accessibility', () => { it('[collapsed] is a11y AXE accessible', async () => { const collapsible = await fixture(defaultCollapsible); await expect(collapsible).to.be.accessible(); }); it('[expanded] is a11y AXE accessible', async () => { const collapsible = await fixture(defaultCollapsible); collapsible.show(); await expect(collapsible).to.be.accessible(); }); describe('Invoker', () => { it('links id of content items to invoker via [aria-controls]', async () => { const collapsibleElement = await fixture(defaultCollapsible); const invoker = collapsibleElement.querySelector('[slot=invoker]'); const content = collapsibleElement.querySelector('[slot=content]'); expect(invoker?.getAttribute('aria-controls')).to.equal(content?.id); }); it('adds aria-expanded="false" to invoker when its content is not expanded', async () => { const collapsibleElement = await fixture(defaultCollapsible); const invoker = collapsibleElement.querySelector('[slot=invoker]'); expect(invoker).to.have.attribute('aria-expanded', 'false'); }); it('adds aria-expanded="true" to invoker when its content is expanded', async () => { const collapsibleElement = await fixture(defaultCollapsible); const invoker = collapsibleElement.querySelector('[slot=invoker]'); collapsibleElement.opened = true; await collapsibleElement.updateComplete; expect(invoker).to.have.attribute('aria-expanded', 'true'); }); }); describe('Contents', () => { it('adds aria-labelledby referring to invoker id', async () => { const collapsibleElement = await fixture(defaultCollapsible); const invoker = collapsibleElement.querySelector('[slot=invoker]'); const content = collapsibleElement.querySelector('[slot=content]'); expect(content).to.have.attribute('aria-labelledby', invoker?.id); }); }); }); });