`); let hidePrevented = false; el.addEventListener('nile-hide', (e: Event) => { e.preventDefault(); hidePrevented = true; }); el.hide(); await aTimeout(500); expect(hidePrevented).to.be.true; });
/* Disabled prevents interaction */
it('69. clicking summary does not open when disabled', async () => { const el = await fixture(html`
C
`); el.shadowRoot!.querySelector('summary')!.click(); await el.updateComplete; expect(el.open).to.be.false; });
it('70. clicking summary does not close when disabled', async () => { const el = await fixture(html`
`); const [a, b] = Array.from(c.querySelectorAll('nile-detail')) as NileDetail[]; a.show(); await oneEvent(a, 'nile-after-show'); expect(a.open).to.be.true; expect(b.open).to.be.false; });
it('84. opening one does not close the other', async () => { const c = await fixture(html`
A
B
`); const [a, b] = Array.from(c.querySelectorAll('nile-detail')) as NileDetail[]; b.show(); await oneEvent(b, 'nile-after-show'); expect(a.open).to.be.true; expect(b.open).to.be.true; });
/* DOM lifecycle */
it('85. isConnected is true when in DOM', async () => { const el = await fixture(html``); expect(el.isConnected).to.be.true; });
it('86. isConnected is false after removal', async () => { const el = await fixture(html``); el.remove(); expect(el.isConnected).to.be.false; });
it('87. can be created via document.createElement', async () => { const el = document.createElement('nile-detail') as NileDetail; document.body.appendChild(el); await el.updateComplete; expect(el.shadowRoot).to.not.be.null; document.body.removeChild(el); });
/* Generic HTML attributes pass through */
it('88. class attribute works', async () => { const el = await fixture(html``); expect(el.classList.contains('custom')).to.be.true; });
it('89. id attribute works', async () => { const el = await fixture(html``); expect(el.id).to.equal('d1'); });
it('90. hidden attribute works', async () => { const el = await fixture(html``); expect(el.hidden).to.be.true; });
it('91. data attribute works', async () => { const el = await fixture(html``); expect(el.dataset.section).to.equal('apps'); });
it('92. style attribute works', async () => { const el = await fixture(html``); expect(el.style.marginTop).to.equal('10px'); });
it('93. aria-label passes through', async () => { const el = await fixture(html``); expect(el.getAttribute('aria-label')).to.equal('Section'); });
/* Icon element */
it('94. renders nile-icon by default', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('nile-icon')).to.exist; });
it('95. icon container exists', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__summary-icon')).to.exist; });
/* Open/close sequence */
it('96. open then close returns to original state', async () => { const el = await fixture(html`
C
`); el.show(); await oneEvent(el, 'nile-after-show'); expect(el.open).to.be.true; el.hide(); await oneEvent(el, 'nile-after-hide'); expect(el.open).to.be.false; expect(el.body.hidden).to.be.true; });
it('97. rapid show then hide settles correctly', async () => { const el = await fixture(html`
C
`); el.show(); await aTimeout(50); el.hide(); await oneEvent(el, 'nile-after-hide'); expect(el.open).to.be.false; });
/* Full integration */
it('98. full integration with all properties set', async () => { const el = await fixture(html`
Content
`); expect(el.heading).to.equal('Apps'); expect(el.description).to.equal('Manage'); expect(el.expandIconPlacement).to.equal('left'); expect(el.id).to.equal('p1'); expect(el.open).to.be.false; expect(el.disabled).to.be.false; expect(el.shadowRoot!.querySelector('details')).to.exist; expect(el.shadowRoot!.querySelector('summary')).to.exist; expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.exist; expect(el.querySelector('p')!.textContent).to.equal('Content'); });
it('99. combined disabled and open set at init', async () => { const el = await fixture(html`
C
`); expect(el.open).to.be.true; expect(el.disabled).to.be.true; expect(el.shadowRoot!.querySelector('.detail--open')).to.exist; expect(el.shadowRoot!.querySelector('.detail--disabled')).to.exist; expect(el.shadowRoot!.querySelector('summary')!.getAttribute('tabindex')).to.equal('-1'); });
it('100. dispatchEvent works for custom events', async () => { const el = await fixture(html``); let detail: any; el.addEventListener('custom-event', ((e: CustomEvent) => { detail = e.detail; }) as EventListener); el.dispatchEvent(new CustomEvent('custom-event', { detail: { test: true } })); expect(detail.test).to.be.true; });
/* Partial / missing properties — user does not pass everything */
it('101. works with no properties at all', async () => { const el = await fixture(html``); expect(el).to.exist; expect(el.open).to.be.false; expect(el.heading).to.equal(''); expect(el.description).to.equal(''); expect(el.disabled).to.be.false; expect(el.shadowRoot!.querySelector('details')).to.exist; });
it('102. works with only heading, no description', async () => { const el = await fixture(html``); expect(el.heading).to.equal('Section'); expect(el.shadowRoot!.querySelector('.detail__description')).to.be.null; expect(el.shadowRoot!.querySelector('.detail__heading-text')!.textContent).to.equal('Section'); });
it('103. works with only description, no heading', async () => { const el = await fixture(html``); expect(el.heading).to.equal(''); expect(el.description).to.equal('Some info'); expect(el.shadowRoot!.querySelector('.detail__heading-text')!.textContent).to.equal(''); expect(el.shadowRoot!.querySelector('.detail__description')!.textContent).to.equal('Some info'); });
it('104. works with only open, no heading or content', async () => { const el = await fixture(html``); expect(el.open).to.be.true; expect(el.heading).to.equal(''); expect(el.body.hidden).to.be.false; });
it('105. works with only disabled, no heading or content', async () => { const el = await fixture(html``); expect(el.disabled).to.be.true; expect(el.shadowRoot!.querySelector('.detail--disabled')).to.exist; });
it('106. works with content but no heading or description', async () => { const el = await fixture(html`
Just content
`); expect(el.heading).to.equal(''); expect(el.querySelector('p')!.textContent).to.equal('Just content'); });
it('107. works with only expandIconPlacement set', async () => { const el = await fixture(html``); expect(el.expandIconPlacement).to.equal('left'); expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.exist; });
it('108. works with heading and open, no content', async () => { const el = await fixture(html``); expect(el.open).to.be.true; expect(el.heading).to.equal('Empty'); expect(el.children.length).to.equal(0); });
it('109. works with empty string heading attribute', async () => { const el = await fixture(html``); expect(el.heading).to.equal(''); expect(el.shadowRoot!.querySelector('.detail__heading-text')!.textContent).to.equal(''); });
it('110. works with only slotted heading, no heading property', async () => { const el = await fixture(html`
Custom Header
`); expect(el.heading).to.equal(''); expect(el.querySelector('[slot="header-description"]')).to.exist; });
it('111. works with only slotted icon, no other props', async () => { const el = await fixture(html`→`); expect(el.querySelector('[slot="icon"]')!.textContent).to.equal('→'); });
it('112. works with disabled and content but no heading', async () => { const el = await fixture(html`
Locked
`); expect(el.disabled).to.be.true; expect(el.querySelector('p')!.textContent).to.equal('Locked'); const result = await el.show(); expect(result).to.be.undefined; expect(el.open).to.be.false; });
it('113. works with open and disabled but no content', async () => { const el = await fixture(html``); expect(el.open).to.be.true; expect(el.disabled).to.be.true; expect(el.children.length).to.equal(0); });
/* User can pass anything inside the content */
it('114. accepts plain text as content', async () => { const el = await fixture(html`Hello World`); expect(el.textContent).to.contain('Hello World'); });
it('115. accepts a paragraph as content', async () => { const el = await fixture(html`
Paragraph
`); expect(el.querySelector('p')!.textContent).to.equal('Paragraph'); });
it('116. accepts multiple paragraphs as content', async () => { const el = await fixture(html`
One
Two
Three
`); expect(el.querySelectorAll('p').length).to.equal(3); });
it('117. accepts a table as content', async () => { const el = await fixture(html`
Cell
`); expect(el.querySelector('table')).to.exist; expect(el.querySelector('td')!.textContent).to.equal('Cell'); });
it('118. accepts a form as content', async () => { const el = await fixture(html``); expect(el.querySelector('form')).to.exist; expect(el.querySelector('input')).to.exist; expect(el.querySelector('button')!.textContent).to.equal('Save'); });
it('119. accepts an image as content', async () => { const el = await fixture(html``); expect(el.querySelector('img')).to.exist; expect(el.querySelector('img')!.alt).to.equal('pixel'); });
it('120. accepts an unordered list as content', async () => { const el = await fixture(html`
A
B
C
`); expect(el.querySelectorAll('li').length).to.equal(3); });
it('121. accepts an ordered list as content', async () => { const el = await fixture(html`
First
Second
`); expect(el.querySelector('ol')).to.exist; expect(el.querySelectorAll('li').length).to.equal(2); });
it('122. accepts a video element as content', async () => { const el = await fixture(html``); expect(el.querySelector('video')).to.exist; });
it('123. accepts an iframe as content', async () => { const el = await fixture(html``); expect(el.querySelector('iframe')).to.exist; });
it('124. accepts deeply nested HTML as content', async () => { const el = await fixture(html`
Deep
`); expect(el.querySelector('article p')!.textContent).to.equal('Deep'); });
it('125. accepts a canvas element as content', async () => { const el = await fixture(html``); expect(el.querySelector('canvas')).to.exist; });
it('126. accepts links as content', async () => { const el = await fixture(html`Link 1Link 2`); expect(el.querySelectorAll('a').length).to.equal(2); });
it('127. accepts code blocks as content', async () => { const el = await fixture(html`
const x = 1;
`); expect(el.querySelector('code')!.textContent).to.equal('const x = 1;'); });
it('128. accepts styled divs as content', async () => { const el = await fixture(html`
Red box
`); const div = el.querySelector('div')!; expect(div.style.background).to.equal('red'); expect(div.textContent).to.equal('Red box'); });
it('129. accepts SVG as content', async () => { const el = await fixture(html``); expect(el.querySelector('svg')).to.exist; expect(el.querySelector('circle')).to.exist; });
it('130. accepts another web component as content', async () => { const el = await fixture(html`