import { expect, fixture, html } from '@open-wc/testing'; import './nile-icon-button'; import NileIconButton from './nile-icon-button'; describe('NileIconButton', () => { it('1. should render without errors', async () => { const el = await fixture(html``); expect(el).to.exist; }); it('2. should have a shadow root', async () => { const el = await fixture(html``); expect(el.shadowRoot).to.not.be.null; }); it('3. should render a button element by default', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button).to.exist; }); it('4. should render an anchor when href is set', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor).to.exist; }); it('5. should render a nile-icon inside', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon).to.exist; }); it('6. should have disabled default to false', async () => { const el = await fixture(html``); expect(el.disabled).to.be.false; }); it('7. should have label default to empty string', async () => { const el = await fixture(html``); expect(el.label).to.equal(''); }); it('8. should have ishovered default to false', async () => { const el = await fixture(html``); expect(el.ishovered).to.be.false; }); it('9. should set name on nile-icon', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('name')).to.equal('close'); }); it('10. should set library on nile-icon', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('library')).to.equal('system'); }); it('11. should set src on nile-icon', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('src')).to.equal('/icon.svg'); }); it('12. should set aria-label from label property', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('aria-label')).to.equal('Close'); }); it('13. should have icon-button class on button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.icon-button'); expect(button).to.exist; }); it('14. should apply disabled class when disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.icon-button--disabled'); expect(button).to.exist; }); it('15. should have aria-disabled true when disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('aria-disabled')).to.equal('true'); }); it('16. should have aria-disabled false when not disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('aria-disabled')).to.equal('false'); }); it('17. should have tabindex 0 when enabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('tabindex')).to.equal('0'); }); it('18. should have tabindex -1 when disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('tabindex')).to.equal('-1'); }); it('19. should have type=button on button element', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('type')).to.equal('button'); }); it('20. should have role=button on button element', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('role')).to.equal('button'); }); it('21. should emit nile-focus on focus', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); let focusEmitted = false; el.addEventListener('nile-focus', () => (focusEmitted = true)); button!.dispatchEvent(new FocusEvent('focus')); expect(focusEmitted).to.be.true; }); it('22. should emit nile-blur on blur', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); let blurEmitted = false; el.addEventListener('nile-blur', () => (blurEmitted = true)); button!.dispatchEvent(new FocusEvent('blur')); expect(blurEmitted).to.be.true; }); it('23. should apply focused class on focus', async () => { const el = await fixture(html``); el.focus(); await el.updateComplete; const button = el.shadowRoot!.querySelector('.icon-button--focused'); expect(button).to.exist; }); it('24. should remove focused class on blur', async () => { const el = await fixture(html``); el.focus(); await el.updateComplete; el.blur(); await el.updateComplete; const button = el.shadowRoot!.querySelector('.icon-button--focused'); expect(button).to.be.null; }); it('25. should have base part on button', async () => { const el = await fixture(html``); const base = el.shadowRoot!.querySelector('[part="base"]'); expect(base).to.exist; }); it('26. should set href on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('https://example.com'); }); it('27. should set target on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('target')).to.equal('_blank'); }); it('28. should set download on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('download')).to.equal('file.pdf'); }); it('29. should set rel on anchor with target', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('rel')).to.equal('noreferrer noopener'); }); it('30. should reflect disabled attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('disabled')).to.be.true; }); it('31. should update disabled dynamically', async () => { const el = await fixture(html``); el.disabled = true; await el.updateComplete; const button = el.shadowRoot!.querySelector('.icon-button--disabled'); expect(button).to.exist; }); it('32. should update name dynamically', async () => { const el = await fixture(html``); el.name = 'arrow-left'; await el.updateComplete; const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('name')).to.equal('arrow-left'); }); it('33. should update label dynamically', async () => { const el = await fixture(html``); el.label = 'Open'; await el.updateComplete; const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('aria-label')).to.equal('Open'); }); it('34. should update color dynamically', async () => { const el = await fixture(html``); el.color = 'blue'; await el.updateComplete; expect(el.color).to.equal('blue'); }); it('35. should switch from button to anchor when href is set', async () => { const el = await fixture(html``); el.href = 'https://example.com'; await el.updateComplete; const anchor = el.shadowRoot!.querySelector('a'); expect(anchor).to.exist; }); it('36. nile-icon should have aria-hidden true', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('aria-hidden')).to.equal('true'); }); it('37. nile-icon should have icon-button__icon class', async () => { const el = await fixture(html``); const icon = el.shadowRoot!.querySelector('.icon-button__icon'); expect(icon).to.exist; }); it('38. should handle click programmatically', async () => { const el = await fixture(html``); let clicked = false; el.addEventListener('click', () => (clicked = true)); el.click(); expect(clicked).to.be.true; }); it('39. should prevent click when disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button') as HTMLButtonElement; let defaultPrevented = false; button.addEventListener('click', (e: MouseEvent) => { defaultPrevented = e.defaultPrevented; }); button.click(); // The handleClick method prevents and stops propagation when disabled }); it('40. should set ishovered on mouseover', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); button!.dispatchEvent(new MouseEvent('mouseover')); await el.updateComplete; expect(el.ishovered).to.be.true; }); it('41. should clear ishovered on mouseleave', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); button!.dispatchEvent(new MouseEvent('mouseover')); await el.updateComplete; button!.dispatchEvent(new MouseEvent('mouseleave')); await el.updateComplete; expect(el.ishovered).to.be.false; }); it('42. should reflect ishovered attribute', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); button!.dispatchEvent(new MouseEvent('mouseover')); await el.updateComplete; expect(el.hasAttribute('ishovered')).to.be.true; }); it('43. should reflect color attribute', async () => { const el = await fixture(html``); expect(el.getAttribute('color')).to.equal('red'); }); it('44. should be instance of NileIconButton', async () => { const el = await fixture(html``); expect(el).to.be.instanceOf(NileIconButton); }); it('45. should have correct tag name', async () => { const el = await fixture(html``); expect(el.tagName.toLowerCase()).to.equal('nile-icon-button'); }); it('46. should have static styles', async () => { expect(NileIconButton.styles).to.exist; }); it('47. should be a defined custom element', async () => { expect(customElements.get('nile-icon-button')).to.exist; }); it('48. should handle undefined name', async () => { const el = await fixture(html``); expect(el.name).to.be.undefined; }); it('49. should handle undefined library', async () => { const el = await fixture(html``); expect(el.library).to.be.undefined; }); it('50. should handle undefined src', async () => { const el = await fixture(html``); expect(el.src).to.be.undefined; }); it('51. should handle undefined href', async () => { const el = await fixture(html``); expect(el.href).to.be.undefined; }); it('52. should handle undefined target', async () => { const el = await fixture(html``); expect(el.target).to.be.undefined; }); it('53. should handle undefined download', async () => { const el = await fixture(html``); expect(el.download).to.be.undefined; }); it('54. should render button element as base', async () => { const el = await fixture(html``); const base = el.shadowRoot!.querySelector('[part="base"]'); expect(base!.tagName).to.equal('BUTTON'); }); it('55. should render anchor element as base when href set', async () => { const el = await fixture(html``); const base = el.shadowRoot!.querySelector('[part="base"]'); expect(base!.tagName).to.equal('A'); }); it('56. should focus programmatically', async () => { const el = await fixture(html``); el.focus(); await el.updateComplete; const focused = el.shadowRoot!.querySelector('.icon-button--focused'); expect(focused).to.exist; }); it('57. should blur programmatically', async () => { const el = await fixture(html``); el.focus(); await el.updateComplete; el.blur(); await el.updateComplete; const focused = el.shadowRoot!.querySelector('.icon-button--focused'); expect(focused).to.be.null; }); it('58. should not have disabled class when not disabled', async () => { const el = await fixture(html``); const disabled = el.shadowRoot!.querySelector('.icon-button--disabled'); expect(disabled).to.be.null; }); it('59. should handle multiple icon buttons independently', async () => { const container = await fixture(html`
`); const buttons = container.querySelectorAll('nile-icon-button'); expect(buttons.length).to.equal(2); expect((buttons[0] as NileIconButton).label).to.equal('Close'); expect((buttons[1] as NileIconButton).label).to.equal('Edit'); }); it('60. should not have any slots', async () => { const el = await fixture(html``); const slots = el.shadowRoot!.querySelectorAll('slot'); expect(slots.length).to.equal(0); }); it('61. icon should be inside button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); const icon = button!.querySelector('nile-icon'); expect(icon).to.exist; }); it('62. icon should be inside anchor when href set', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); const icon = anchor!.querySelector('nile-icon'); expect(icon).to.exist; }); it('63. should handle name property update', async () => { const el = await fixture(html``); el.name = 'search'; await el.updateComplete; const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('name')).to.equal('search'); }); it('64. should handle library property update', async () => { const el = await fixture(html``); el.library = 'custom'; await el.updateComplete; const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('library')).to.equal('custom'); }); it('65. should handle toggling disabled', async () => { const el = await fixture(html``); el.disabled = true; await el.updateComplete; expect(el.shadowRoot!.querySelector('.icon-button--disabled')).to.exist; el.disabled = false; await el.updateComplete; expect(el.shadowRoot!.querySelector('.icon-button--disabled')).to.be.null; }); it('66. should handle color property', async () => { const el = await fixture(html``); expect(el.color).to.equal('red'); }); it('67. should handle undefined color', async () => { const el = await fixture(html``); expect(el.color).to.be.undefined; }); it('68. should handle setting all properties', async () => { const el = await fixture(html` `); expect(el.name).to.equal('close'); expect(el.library).to.equal('system'); expect(el.label).to.equal('Close'); expect(el.color).to.equal('red'); expect(el.disabled).to.be.true; }); it('69. should handle creation via createElement', async () => { const el = document.createElement('nile-icon-button') as NileIconButton; document.body.appendChild(el); await el.updateComplete; expect(el.shadowRoot!.querySelector('.icon-button')).to.exist; document.body.removeChild(el); }); it('70. shadow root mode should be open', async () => { const el = await fixture(html``); expect(el.shadowRoot!.mode).to.equal('open'); }); it('71. should have render method', async () => { const el = await fixture(html``); expect(el.render).to.be.a('function'); }); it('72. should handle data attributes', async () => { const el = await fixture(html``); expect(el.getAttribute('data-action')).to.equal('close'); }); it('73. should handle class attribute', async () => { const el = await fixture(html``); expect(el.classList.contains('custom')).to.be.true; }); it('74. should handle id attribute', async () => { const el = await fixture(html``); expect(el.id).to.equal('btn1'); }); it('75. button should have exactly one child (nile-icon)', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); const icons = button!.querySelectorAll('nile-icon'); expect(icons.length).to.equal(1); }); it('76. anchor should have exactly one child (nile-icon)', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); const icons = anchor!.querySelectorAll('nile-icon'); expect(icons.length).to.equal(1); }); // Various href configurations it('77. should handle absolute href', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('https://example.com/path'); }); it('78. should handle relative href', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('/path'); }); it('79. should handle hash href', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('#section'); }); // Label combinations it('80. should handle long label', async () => { const longLabel = 'A'.repeat(200); const el = await fixture(html``); const button = el.shadowRoot!.querySelector('button'); expect(button!.getAttribute('aria-label')).to.equal(longLabel); }); it('81. should handle special characters in label', async () => { const el = await fixture(html``); expect(el.label).to.contain('&'); }); // Disabled + href it('82. should handle disabled with href', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('aria-disabled')).to.equal('true'); expect(anchor!.getAttribute('tabindex')).to.equal('-1'); }); // Multiple renders it('83. should handle multiple rapid property changes', async () => { const el = await fixture(html``); el.name = 'a'; el.name = 'b'; el.name = 'c'; await el.updateComplete; const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('name')).to.equal('c'); }); it('84. should maintain structure after requestUpdate', async () => { const el = await fixture(html``); el.requestUpdate(); await el.updateComplete; expect(el.shadowRoot!.querySelector('.icon-button')).to.exist; }); it('85. should handle being inside a form', async () => { const container = await fixture(html`
`); const btn = container.querySelector('nile-icon-button') as NileIconButton; expect(btn.shadowRoot!.querySelector('.icon-button')).to.exist; }); it('86. should handle being inside a nile-button container', async () => { const container = await fixture(html`
`); const btn = container.querySelector('nile-icon-button') as NileIconButton; expect(btn.name).to.equal('x'); }); it('87. should handle hidden attribute', async () => { const el = await fixture(html``); expect(el.hidden).to.be.true; }); it('88. should handle style attribute', async () => { const el = await fixture(html``); expect(el.style.opacity).to.equal('0.5'); }); it('89. should have no text content', async () => { const el = await fixture(html``); expect(el.textContent!.trim()).to.equal(''); }); it('90. should have updateComplete promise', async () => { const el = await fixture(html``); expect(el.updateComplete).to.be.a('promise'); }); it('91. should resolve updateComplete', async () => { const el = await fixture(html``); const result = await el.updateComplete; expect(result).to.not.be.undefined; }); it('92. should be connected after fixture', async () => { const el = await fixture(html``); expect(el.isConnected).to.be.true; }); it('93. should be disconnected after removal', async () => { const el = await fixture(html``); el.remove(); expect(el.isConnected).to.be.false; }); it('94. button should have nodeType ELEMENT_NODE', async () => { const el = await fixture(html``); expect(el.nodeType).to.equal(Node.ELEMENT_NODE); }); it('95. shadowRoot host should be the element', async () => { const el = await fixture(html``); expect(el.shadowRoot!.host).to.equal(el); }); // Comprehensive combos it('96. name + library + label + disabled', async () => { const el = await fixture(html` `); expect(el.disabled).to.be.true; const icon = el.shadowRoot!.querySelector('nile-icon'); expect(icon!.getAttribute('name')).to.equal('close'); expect(icon!.getAttribute('library')).to.equal('system'); }); it('97. name + href + target + label', async () => { const el = await fixture(html` `); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('https://example.com'); expect(anchor!.getAttribute('target')).to.equal('_blank'); }); it('98. should handle name + color + label', async () => { const el = await fixture(html` `); expect(el.name).to.equal('edit'); expect(el.color).to.equal('blue'); expect(el.label).to.equal('Edit'); }); it('99. should handle all link properties', async () => { const el = await fixture(html` `); const anchor = el.shadowRoot!.querySelector('a'); expect(anchor!.getAttribute('href')).to.equal('https://example.com/file'); expect(anchor!.getAttribute('target')).to.equal('_blank'); expect(anchor!.getAttribute('download')).to.equal('file.pdf'); }); it('100. should handle switching from anchor to button', async () => { const el = await fixture(html``); expect(el.shadowRoot!.querySelector('a')).to.exist; el.href = undefined; await el.updateComplete; expect(el.shadowRoot!.querySelector('button')).to.exist; }); });