import { expect, fixture, html, oneEvent, aTimeout } from '@open-wc/testing'; import './nile-detail'; import type { NileDetail } from './nile-detail'; describe('NileDetail', () => { /* Rendering & Structure */ it('1. renders without errors', async () => { const el = await fixture(html``); expect(el).to.exist; }); it('2. has shadow root', async () => { const el = await fixture(html``); expect(el.shadowRoot).to.not.be.null; }); it('3. is registered as custom element', async () => { expect(customElements.get('nile-detail')).to.exist; }); it('4. tag name is nile-detail', async () => { const el = await fixture(html``); expect(el.tagName.toLowerCase()).to.equal('nile-detail'); }); it('5. uses native details element', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('details')).to.exist; }); it('6. uses native summary element', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')).to.exist; }); it('7. has static styles', async () => { expect((await import('./nile-detail')).NileDetail.styles).to.exist; }); it('8. shadow mode is open', async () => { const el = await fixture(html``); expect(el.shadowRoot!.mode).to.equal('open'); }); /* Default property values */ it('9. open defaults to false', async () => { const el = await fixture(html``); expect(el.open).to.be.false; }); it('10. heading defaults to empty string', async () => { const el = await fixture(html``); expect(el.heading).to.equal(''); }); it('11. description defaults to empty string', async () => { const el = await fixture(html``); expect(el.description).to.equal(''); }); it('12. expandIconPlacement defaults to right', async () => { const el = await fixture(html``); expect(el.expandIconPlacement).to.equal('right'); }); it('13. disabled defaults to false', async () => { const el = await fixture(html``); expect(el.disabled).to.be.false; }); /* Attribute reflection */ it('14. open attribute reflects to property', async () => { const el = await fixture(html``); expect(el.open).to.be.true; }); it('15. heading attribute reflects to property', async () => { const el = await fixture(html``); expect(el.heading).to.equal('Applications'); }); it('16. description attribute reflects to property', async () => { const el = await fixture(html``); expect(el.description).to.equal('Manage your apps'); }); it('17. disabled attribute reflects to property', async () => { const el = await fixture(html``); expect(el.disabled).to.be.true; }); it('18. expandIconPlacement attribute reflects to property', async () => { const el = await fixture(html``); expect(el.expandIconPlacement).to.equal('left'); }); it('19. setting open property reflects to attribute', async () => { const el = await fixture(html``); el.open = true; await el.updateComplete; expect(el.hasAttribute('open')).to.be.true; }); it('20. removing open attribute sets property to false', async () => { const el = await fixture(html``); el.removeAttribute('open'); await el.updateComplete; expect(el.open).to.be.false; }); /* Heading and description rendering */ it('21. renders heading text in the header', async () => { const el = await fixture(html``); const text = el.shadowRoot!.querySelector('.detail__heading-text'); expect(text!.textContent).to.equal('Settings'); }); it('22. renders description when provided', async () => { const el = await fixture(html``); const desc = el.shadowRoot!.querySelector('.detail__description'); expect(desc).to.exist; expect(desc!.textContent).to.equal('Subtitle here'); }); it('23. does not render description when empty', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__description')).to.be.null; }); it('24. updates heading dynamically', async () => { const el = await fixture(html``); el.heading = 'New'; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail__heading-text')!.textContent).to.equal('New'); }); it('25. updates description dynamically', async () => { const el = await fixture(html``); el.description = 'New'; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail__description')!.textContent).to.equal('New'); }); /* CSS classes driven by state */ it('26. adds detail--open class when open', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail--open')).to.exist; }); it('27. no detail--open class when closed', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail--open')).to.be.null; }); it('28. adds detail--disabled class when disabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail--disabled')).to.exist; }); it('29. no detail--disabled class when enabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail--disabled')).to.be.null; }); it('30. adds detail__header--icon-left when expandIconPlacement is left', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.exist; }); it('31. no detail__header--icon-left when expandIconPlacement is right', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.be.null; }); /* Accessibility — ARIA & keyboard */ it('32. summary has aria-label matching heading', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('aria-label')).to.equal('Apps'); }); it('33. summary has aria-label matching heading and description', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('aria-label')).to.equal('Apps, Manage apps'); }); it('34. summary has aria-disabled false when enabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('aria-disabled')).to.equal('false'); }); it('35. summary has aria-disabled true when disabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('aria-disabled')).to.equal('true'); }); it('36. summary has tabindex 0 when enabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('tabindex')).to.equal('0'); }); it('37. summary has tabindex -1 when disabled', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('tabindex')).to.equal('-1'); }); it('38. label slot exists', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('slot[name="label"]')).to.exist; }); it('39. summary has aria-expanded false when closed', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('summary')!.getAttribute('aria-expanded')).to.equal('false'); }); it('40. summary-icon container has aria-hidden true', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__summary-icon')!.getAttribute('aria-hidden')).to.equal('true'); }); /* Parts */ it('41. exposes base part', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('[part="base"]')!.tagName.toLowerCase()).to.equal('details'); }); it('42. exposes header part', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('[part="header"]')!.tagName.toLowerCase()).to.equal('summary'); }); it('43. exposes summary-icon part', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('[part="summary-icon"]')).to.exist; }); it('44. exposes content part on body', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('[part="content"]')).to.exist; }); /* Slots */ it('45. has header-actions slot', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('slot[name="header-actions"]')).to.exist; }); it('46. has expand-icon slot', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('slot[name="expand-icon"]')).to.exist; }); it('47. has default slot for content', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('slot:not([name])')).to.exist; }); it('48. user can slot custom heading markup', async () => { const el = await fixture(html`
Custom
`); expect(el.querySelector('[slot="header-description"]')).to.exist; }); it('49. user can slot custom icon', async () => { const el = await fixture(html``); expect(el.querySelector('[slot="icon"]')).to.exist; }); it('50. default slot receives content', async () => { const el = await fixture(html`

Some content

`); expect(el.querySelector('p')!.textContent).to.equal('Some content'); }); /* Body visibility after first render */ it('51. body is hidden when initially closed', async () => { const el = await fixture(html``); expect(el.body.hidden).to.be.true; }); it('52. body is visible when initially open', async () => { const el = await fixture(html``); expect(el.body.hidden).to.be.false; }); it('53. body height is 0 when initially closed', async () => { const el = await fixture(html``); expect(el.body.style.height).to.equal('0px'); }); it('54. body height is auto when initially open', async () => { const el = await fixture(html``); expect(el.body.style.height).to.equal('auto'); }); /* show() and hide() methods */ it('55. show method exists', async () => { const el = await fixture(html``); expect(el.show).to.be.a('function'); }); it('56. hide method exists', async () => { const el = await fixture(html``); expect(el.hide).to.be.a('function'); }); it('57. show() opens a closed detail', async () => { const el = await fixture(html`

Content

`); el.show(); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); it('58. hide() closes an open detail', async () => { const el = await fixture(html`

Content

`); el.hide(); const ev = await oneEvent(el, 'nile-after-hide'); expect(ev).to.exist; expect(el.open).to.be.false; }); it('59. show() is no-op when already open', async () => { const el = await fixture(html`

C

`); const result = await el.show(); expect(result).to.be.undefined; expect(el.open).to.be.true; }); it('60. hide() is no-op when already closed', async () => { const el = await fixture(html`

C

`); const result = await el.hide(); expect(result).to.be.undefined; expect(el.open).to.be.false; }); it('61. show() is no-op when disabled', async () => { const el = await fixture(html`

C

`); const result = await el.show(); expect(result).to.be.undefined; expect(el.open).to.be.false; }); it('62. hide() is no-op when disabled', async () => { const el = await fixture(html`

C

`); const result = await el.hide(); expect(result).to.be.undefined; expect(el.open).to.be.true; }); /* Events — nile-show, nile-after-show, nile-hide, nile-after-hide */ it('63. emits nile-show when opening', async () => { const el = await fixture(html`

C

`); setTimeout(() => el.show()); const ev = await oneEvent(el, 'nile-show'); expect(ev).to.exist; }); it('64. emits nile-after-show after open animation', async () => { const el = await fixture(html`

C

`); setTimeout(() => el.show()); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; }); it('65. emits nile-hide when closing', async () => { const el = await fixture(html`

C

`); setTimeout(() => el.hide()); const ev = await oneEvent(el, 'nile-hide'); expect(ev).to.exist; }); it('66. emits nile-after-hide after close animation', async () => { const el = await fixture(html`

C

`); setTimeout(() => el.hide()); const ev = await oneEvent(el, 'nile-after-hide'); expect(ev).to.exist; }); /* Cancelable events */ it('67. canceling nile-show emits prevented event', async () => { const el = await fixture(html`

C

`); let showPrevented = false; el.addEventListener('nile-show', (e: Event) => { e.preventDefault(); showPrevented = true; }); el.show(); await aTimeout(500); expect(showPrevented).to.be.true; }); it('68. canceling nile-hide emits prevented event', async () => { const el = await fixture(html`

C

`); 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`

C

`); el.shadowRoot!.querySelector('summary')!.click(); await el.updateComplete; expect(el.open).to.be.true; }); it('71. enabling a disabled detail allows interaction again', async () => { const el = await fixture(html`

C

`); el.disabled = false; await el.updateComplete; el.show(); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); /* Dynamic state changes */ it('72. toggling open on then off removes detail--open class', async () => { const el = await fixture(html`

C

`); el.open = true; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail--open')).to.exist; el.open = false; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail--open')).to.be.null; }); it('73. toggling disabled on then off removes detail--disabled class', async () => { const el = await fixture(html``); el.disabled = true; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail--disabled')).to.exist; el.disabled = false; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail--disabled')).to.be.null; }); it('74. switching expandIconPlacement from right to left updates class', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.be.null; el.expandIconPlacement = 'left'; await el.updateComplete; expect(el.shadowRoot!.querySelector('.detail__header--icon-left')).to.exist; }); it('75. native details open attribute updates when open changes', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('details')!.open).to.be.false; el.open = true; await el.updateComplete; }); /* Keyboard interaction */ it('76. Enter key on summary opens the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); it('77. Space key on summary opens the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); it('78. Enter key on summary closes an open detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-hide'); expect(ev).to.exist; expect(el.open).to.be.false; }); it('79. ArrowDown key opens the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); it('80. ArrowUp key closes the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-hide'); expect(ev).to.exist; expect(el.open).to.be.false; }); it('81. ArrowRight key opens the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-show'); expect(ev).to.exist; expect(el.open).to.be.true; }); it('82. ArrowLeft key closes the detail', async () => { const el = await fixture(html`

C

`); const summary = el.shadowRoot!.querySelector('summary')!; summary.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true, composed: true })); const ev = await oneEvent(el, 'nile-after-hide'); expect(ev).to.exist; expect(el.open).to.be.false; }); /* Multiple instances are independent */ it('83. two details operate independently', async () => { const c = await fixture(html`

A

B

`); 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`pixel`); 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`
  1. First
  2. 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`

Inner content

`); const inner = el.querySelector('nile-detail') as NileDetail; expect(inner).to.exist; expect(inner.heading).to.equal('Inner'); }); it('131. accepts mixed content types together', async () => { const el = await fixture(html`

Text

img
  • Item
Cell
`); expect(el.querySelector('p')).to.exist; expect(el.querySelector('img')).to.exist; expect(el.querySelector('ul')).to.exist; expect(el.querySelector('table')).to.exist; }); it('132. accepts empty content gracefully', async () => { const el = await fixture(html``); expect(el).to.exist; expect(el.children.length).to.equal(0); }); it('133. accepts content with data attributes', async () => { const el = await fixture(html`
Item
`); const div = el.querySelector('div')!; expect(div.dataset.id).to.equal('123'); expect(div.dataset.type).to.equal('card'); }); it('134. accepts input elements and they remain functional', async () => { const el = await fixture(html``); const input = el.querySelector('input')! as HTMLInputElement; input.value = 'typed'; expect(input.value).to.equal('typed'); }); it('135. accepts textarea as content', async () => { const el = await fixture(html``); expect(el.querySelector('textarea')!.value).to.equal('Some notes'); }); it('136. accepts select dropdown as content', async () => { const el = await fixture(html``); expect(el.querySelectorAll('option').length).to.equal(2); }); it('137. accepts checkbox inputs as content', async () => { const el = await fixture(html``); const cb = el.querySelector('input[type="checkbox"]') as HTMLInputElement; expect(cb.checked).to.be.true; }); it('138. accepts radio buttons as content', async () => { const el = await fixture(html``); expect(el.querySelectorAll('input[type="radio"]').length).to.equal(2); }); it('139. accepts definition list as content', async () => { const el = await fixture(html`
Term
Definition
`); expect(el.querySelector('dt')!.textContent).to.equal('Term'); expect(el.querySelector('dd')!.textContent).to.equal('Definition'); }); it('140. content with event listeners still works', async () => { const el = await fixture(html``); let clicked = false; el.querySelector('#btn')!.addEventListener('click', () => { clicked = true; }); (el.querySelector('#btn') as HTMLElement).click(); expect(clicked).to.be.true; }); });