import { expect, fixture, html, elementUpdated } from '@open-wc/testing'; import './nile-button'; import NileButton from './nile-button'; describe('NileButton', () => { // === RENDERING TESTS === 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!.tagName).to.equal('BUTTON'); }); it('4. should render an anchor element when href is set', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.tagName).to.equal('A'); }); it('5. should render slot content', async () => { const el = await fixture(html`Click Me`); expect(el.textContent!.trim()).to.equal('Click Me'); }); it('6. should render prefix slot', async () => { const el = await fixture(html`PLabel`); const prefixSlot = el.shadowRoot!.querySelector('slot[name="prefix"]'); expect(prefixSlot).to.exist; }); it('7. should render suffix slot', async () => { const el = await fixture(html`SLabel`); const suffixSlot = el.shadowRoot!.querySelector('slot[name="suffix"]'); expect(suffixSlot).to.exist; }); it('8. should render default slot for label', async () => { const el = await fixture(html``); const labelSlot = el.shadowRoot!.querySelector('slot:not([name])'); expect(labelSlot).to.exist; }); // === DEFAULT PROPERTIES === it('9. should have variant default to primary', async () => { const el = await fixture(html``); expect(el.variant).to.equal('primary'); }); it('10. should have size default to md', async () => { const el = await fixture(html``); expect(el.size).to.equal('md'); }); it('11. should have type default to button', async () => { const el = await fixture(html``); expect(el.type).to.equal('button'); }); it('12. should have disabled default to false', async () => { const el = await fixture(html``); expect(el.disabled).to.be.false; }); it('13. should have loading default to false', async () => { const el = await fixture(html``); expect(el.loading).to.be.false; }); it('14. should have caret default to false', async () => { const el = await fixture(html``); expect(el.caret).to.be.false; }); it('15. should have outline default to false', async () => { const el = await fixture(html``); expect(el.outline).to.be.false; }); it('16. should have pill default to false', async () => { const el = await fixture(html``); expect(el.pill).to.be.false; }); it('17. should have circle default to false', async () => { const el = await fixture(html``); expect(el.circle).to.be.false; }); it('18. should have name default to empty string', async () => { const el = await fixture(html``); expect(el.name).to.equal(''); }); it('19. should have value default to empty string', async () => { const el = await fixture(html``); expect(el.value).to.equal(''); }); it('20. should have href default to empty string', async () => { const el = await fixture(html``); expect(el.href).to.equal(''); }); it('21. should have hideBorder default to false', async () => { const el = await fixture(html``); expect(el.hideBorder).to.be.false; }); it('22. should have title default to empty string', async () => { const el = await fixture(html``); expect(el.title).to.equal(''); }); // === VARIANT TESTS === it('23. should apply primary variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--primary')).to.be.true; }); it('24. should apply secondary variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--secondary')).to.be.true; }); it('25. should apply tertiary variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--tertiary')).to.be.true; }); it('26. should apply caution variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--caution')).to.be.true; }); it('27. should apply ghost variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--ghost')).to.be.true; }); it('28. should apply destructive variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--destructive')).to.be.true; }); it('29. should apply secondary-grey variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--secondary-grey')).to.be.true; }); it('30. should apply secondary-blue variant class', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--secondary-blue')).to.be.true; }); it('31. should reflect variant attribute', async () => { const el = await fixture(html``); expect(el.getAttribute('variant')).to.equal('caution'); }); // === DISABLED STATE === it('32. should be disabled when disabled property is set', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.hasAttribute('disabled')).to.be.true; }); it('33. 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('34. 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('35. should apply disabled class when disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--disabled')).to.be.true; }); it('36. 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('37. should have tabindex 0 when not disabled', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.getAttribute('tabindex')).to.equal('0'); }); it('38. should prevent click events when disabled', async () => { const el = await fixture(html``); let clicked = false; el.addEventListener('click', () => (clicked = true)); el.click(); expect(clicked).to.be.false; }); it('39. should reflect disabled attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('disabled')).to.be.true; }); // === LOADING STATE === it('40. should show spinner when loading', async () => { const el = await fixture(html``); const spinner = el.shadowRoot!.querySelector('nile-spinner'); expect(spinner).to.exist; }); it('41. should not show spinner when not loading', async () => { const el = await fixture(html``); const spinner = el.shadowRoot!.querySelector('nile-spinner'); expect(spinner).to.be.null; }); it('42. should apply loading class when loading', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--loading')).to.be.true; }); it('43. should prevent click when loading', async () => { const el = await fixture(html``); let clicked = false; el.addEventListener('click', () => (clicked = true)); el.click(); expect(clicked).to.be.false; }); it('44. should reflect loading attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('loading')).to.be.true; }); // === CARET === it('45. should show caret icon when caret is true', async () => { const el = await fixture(html``); const caret = el.shadowRoot!.querySelector('nile-icon[part="caret"]'); expect(caret).to.exist; }); it('46. should not show caret icon when caret is false', async () => { const el = await fixture(html``); const caret = el.shadowRoot!.querySelector('nile-icon[part="caret"]'); expect(caret).to.be.null; }); it('47. should apply caret class when caret is set', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--caret')).to.be.true; }); // === PILL === it('48. should apply pill class when pill is true', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--pill')).to.be.true; }); it('49. should reflect pill attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('pill')).to.be.true; }); // === CIRCLE === it('50. should apply circle class when circle is true', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--circle')).to.be.true; }); it('51. should reflect circle attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('circle')).to.be.true; }); // === OUTLINE === it('52. should apply outline class when outline is true', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--outline')).to.be.true; }); it('53. should apply standard class when outline is false', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--standard')).to.be.true; }); // === LINK MODE (href) === it('54. should set href attribute on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.getAttribute('href')).to.equal('https://example.com'); }); it('55. should set target on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.getAttribute('target')).to.equal('_blank'); }); it('56. should set role=button on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.getAttribute('role')).to.equal('button'); }); it('57. should set rel attribute on anchor', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.getAttribute('rel')).to.equal('noreferrer noopener'); }); it('58. should set download attribute on anchor when provided', async () => { const el = await fixture(html``); const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.getAttribute('download')).to.equal('file.pdf'); }); // === BUTTON TYPE === it('59. should set button type attribute', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.getAttribute('type')).to.equal('submit'); }); it('60. should support type=reset', async () => { const el = await fixture(html``); expect(el.type).to.equal('reset'); }); it('61. should set name attribute on button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.getAttribute('name')).to.equal('myButton'); }); it('62. should set value attribute on button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.getAttribute('value')).to.equal('myValue'); }); // === EVENTS === it('63. should emit nile-focus when focused', 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('64. should emit nile-blur when blurred', 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('65. should emit nile-init on connectedCallback', async () => { let initEmitted = false; const container = await fixture(html`
`); const el = document.createElement('nile-button') as NileButton; el.addEventListener('nile-init', () => (initEmitted = true)); container.appendChild(el); await el.updateComplete; expect(initEmitted).to.be.true; }); it('66. should emit nile-destroy on disconnectedCallback', async () => { const el = await fixture(html``); let destroyEmitted = false; el.addEventListener('nile-destroy', () => (destroyEmitted = true)); el.remove(); expect(destroyEmitted).to.be.true; }); // === FOCUS/BLUR METHODS === it('67. should focus programmatically', async () => { const el = await fixture(html`Test`); el.focus(); await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--focused')).to.be.true; }); it('68. should blur programmatically', async () => { const el = await fixture(html`Test`); el.focus(); await el.updateComplete; el.blur(); await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--focused')).to.be.false; }); it('69. should click programmatically', async () => { const el = await fixture(html`Test`); let clicked = false; el.addEventListener('click', () => (clicked = true)); el.click(); expect(clicked).to.be.true; }); // === VALIDATION === it('70. should set custom validation message', async () => { const el = await fixture(html``); const form = document.createElement('form'); form.appendChild(el); document.body.appendChild(form); el.setCustomValidity('Invalid'); expect(el.validationMessage).to.equal('Invalid'); el.setCustomValidity(''); expect(el.validationMessage).to.equal(''); document.body.removeChild(form); }); it('71. should check validity', async () => { const el = await fixture(html``); expect(el.checkValidity()).to.be.true; }); it('72. should report validity', async () => { const el = await fixture(html``); expect(el.reportValidity()).to.be.true; }); it('73. should get validity state', async () => { const el = await fixture(html``); expect(el.validity).to.exist; expect(el.validity.valid).to.be.true; }); // === FORM INTEGRATION === it('74. should return null getForm when not in a form', async () => { const el = await fixture(html``); expect(el.getForm()).to.be.null; }); it('75. should set formAction property', async () => { const el = await fixture(html``); expect(el.formAction).to.equal('/submit'); }); it('76. should set formMethod property', async () => { const el = await fixture(html``); expect(el.formMethod).to.equal('post'); }); it('77. should set formNoValidate property', async () => { const el = await fixture(html``); expect(el.formNoValidate).to.be.true; }); it('78. should set formTarget property', async () => { const el = await fixture(html``); expect(el.formTarget).to.equal('_blank'); }); it('79. should set formEnctype property', async () => { const el = await fixture(html``); expect(el.formEnctype).to.equal('multipart/form-data'); }); // === HIDE BORDER === it('80. should apply hideborder class when hide-border is set', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--hideborder')).to.be.true; }); it('81. should reflect hide-border attribute', async () => { const el = await fixture(html``); expect(el.hasAttribute('hide-border')).to.be.true; }); // === TITLE === it('82. should set title on internal button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.getAttribute('title')).to.equal('My Title'); }); // === DYNAMIC PROPERTY CHANGES === it('83. should update variant dynamically', async () => { const el = await fixture(html``); el.variant = 'secondary'; await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--secondary')).to.be.true; }); it('84. should update disabled dynamically', async () => { const el = await fixture(html``); el.disabled = true; await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.hasAttribute('disabled')).to.be.true; }); it('85. should update loading dynamically', async () => { const el = await fixture(html``); el.loading = true; await el.updateComplete; const spinner = el.shadowRoot!.querySelector('nile-spinner'); expect(spinner).to.exist; }); it('86. should update caret dynamically', async () => { const el = await fixture(html``); el.caret = true; await el.updateComplete; const caret = el.shadowRoot!.querySelector('nile-icon[part="caret"]'); expect(caret).to.exist; }); it('87. should update pill dynamically', async () => { const el = await fixture(html``); el.pill = true; await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--pill')).to.be.true; }); it('88. should update circle dynamically', async () => { const el = await fixture(html``); el.circle = true; await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--circle')).to.be.true; }); it('89. should update outline dynamically', async () => { const el = await fixture(html``); el.outline = true; await el.updateComplete; const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--outline')).to.be.true; }); it('90. should switch from button to anchor when href is set dynamically', async () => { const el = await fixture(html``); el.href = 'https://example.com'; await el.updateComplete; const anchor = el.shadowRoot!.querySelector('.button'); expect(anchor!.tagName).to.equal('A'); }); // === CSS PARTS === it('91. should have base part on button', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('[part~="base"]'); expect(button).to.exist; }); it('92. should have prefix part', async () => { const el = await fixture(html``); const prefix = el.shadowRoot!.querySelector('[part~="prefix"]'); expect(prefix).to.exist; }); it('93. should have label part', async () => { const el = await fixture(html``); const label = el.shadowRoot!.querySelector('[part~="label"]'); expect(label).to.exist; }); it('94. should have suffix part', async () => { const el = await fixture(html``); const suffix = el.shadowRoot!.querySelector('[part~="suffix"]'); expect(suffix).to.exist; }); it('95. should have caret part when caret is set', async () => { const el = await fixture(html``); const caret = el.shadowRoot!.querySelector('[part~="caret"]'); expect(caret).to.exist; }); // === COMBINED STATES === it('96. should handle disabled and loading together', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--disabled')).to.be.true; expect(button!.classList.contains('button--loading')).to.be.true; }); it('97. should handle pill and outline together', async () => { const el = await fixture(html``); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--pill')).to.be.true; expect(button!.classList.contains('button--outline')).to.be.true; }); it('98. should show caret on link button', async () => { const el = await fixture(html``); const caret = el.shadowRoot!.querySelector('nile-icon[part="caret"]'); expect(caret).to.exist; }); it('99. should show spinner on link button when loading', async () => { const el = await fixture(html``); const spinner = el.shadowRoot!.querySelector('nile-spinner'); expect(spinner).to.exist; }); it('100. should handle all visual modifiers simultaneously', async () => { const el = await fixture( html`` ); const button = el.shadowRoot!.querySelector('.button'); expect(button!.classList.contains('button--destructive')).to.be.true; expect(button!.classList.contains('button--pill')).to.be.true; expect(button!.classList.contains('button--outline')).to.be.true; expect(button!.classList.contains('button--caret')).to.be.true; expect(button!.classList.contains('button--loading')).to.be.true; expect(button!.classList.contains('button--disabled')).to.be.true; }); // === SIZE (kb/specs/nile-button.md) === describe('size', () => { const SIZES = ['sm', 'md', 'lg', 'xl'] as const; const HEIGHT: Record = { sm: 36, md: 40, lg: 44, xl: 48 }; const FONT: Record = { sm: 14, md: 14, lg: 16, xl: 16 }; const CIRCLE: Record = { sm: 36, md: 38, lg: 44, xl: 48 }; // wtr loads no theme stylesheet, so token-driven geometry resolves to `auto`. Supply the // nxtgen tokens the spec maps to (values from demo/nxtgen.css) on an ancestor; custom // properties inherit into the shadow root. const TOKENS = [ '--ng-height-36px: 36px', '--ng-height-38px: 38px', '--ng-height-40px: 40px', '--ng-height-44px: 44px', '--ng-height-48px: 48px', '--ng-font-size-text-sm: 14px', '--ng-font-size-text-md: 16px', '--ng-line-height-text-sm: 20px', '--ng-line-height-text-md: 24px', '--ng-spacing-xs: 4px', '--ng-spacing-sm: 6px', '--ng-spacing-md: 8px', '--ng-spacing-md-alt: 10px', '--ng-spacing-lg: 12px', '--ng-spacing-lg-alt: 14px', '--ng-spacing-xl: 16px', '--ng-spacing-xl-alt: 18px', '--ng-spacing-5: 20px', ].join('; '); const base = (el: NileButton) => el.shadowRoot!.querySelector('[part="base"]') as HTMLElement; async function themed(markup: ReturnType) { const wrap = await fixture(html`
${markup}
`); const el = wrap.querySelector('nile-button') as NileButton; await el.updateComplete; return el; } it('101. defaults size to md', async () => { const el = await fixture(html``); expect(el.size).to.equal('md'); }); it('102. reflects the default size to the size attribute', async () => { const el = await fixture(html``); expect(el.getAttribute('size')).to.equal('md'); }); it('103. renders button--md on part base by default', async () => { const el = await fixture(html``); expect(base(el).classList.contains('button--md')).to.be.true; }); SIZES.forEach((size, i) => { it(`${104 + i}. renders button--${size} when size="${size}" is set as an attribute`, async () => { const el = await fixture(html`Label`); expect(el.size).to.equal(size); expect(base(el).classList.contains(`button--${size}`)).to.be.true; }); }); SIZES.forEach((size, i) => { it(`${108 + i}. applies only one size class for size="${size}"`, async () => { const el = await fixture(html`Label`); const others = SIZES.filter(s => s !== size).filter(s => base(el).classList.contains(`button--${s}`)); expect(others).to.deep.equal([]); }); }); it('112. updates class and reflected attribute when size is set via property', async () => { const el = await fixture(html`Label`); el.size = 'xl'; await el.updateComplete; expect(el.getAttribute('size')).to.equal('xl'); expect(base(el).classList.contains('button--xl')).to.be.true; expect(base(el).classList.contains('button--md')).to.be.false; }); it('113. updates when the size attribute changes', async () => { const el = await fixture(html`Label`); el.setAttribute('size', 'lg'); await el.updateComplete; expect(el.size).to.equal('lg'); expect(base(el).classList.contains('button--lg')).to.be.true; expect(base(el).classList.contains('button--sm')).to.be.false; }); it('114. falls back to button--md for an unknown size', async () => { const el = await fixture(html`Label`); expect(base(el).classList.contains('button--md')).to.be.true; expect(base(el).classList.contains('button--huge')).to.be.false; }); it('115. falls back to md height for an unknown size', async () => { const el = await themed(html`Label`); expect(base(el).getBoundingClientRect().height).to.equal(40); }); it('116. renders 40px high with no size set (no regression)', async () => { const el = await themed(html`Label`); expect(base(el).getBoundingClientRect().height).to.equal(40); }); SIZES.forEach((size, i) => { it(`${117 + i}. renders ${HEIGHT[size]}px high for size="${size}"`, async () => { const el = await themed(html`Label`); expect(base(el).getBoundingClientRect().height).to.equal(HEIGHT[size]); }); }); SIZES.forEach((size, i) => { it(`${121 + i}. uses ${FONT[size]}px text for size="${size}"`, async () => { const el = await themed(html`Label`); expect(getComputedStyle(base(el)).fontSize).to.equal(`${FONT[size]}px`); }); }); SIZES.forEach((size, i) => { it(`${125 + i}. renders a ${CIRCLE[size]}px circle for size="${size}"`, async () => { const el = await themed(html`A`); const rect = base(el).getBoundingClientRect(); expect(base(el).classList.contains('button--circle')).to.be.true; expect(base(el).classList.contains(`button--${size}`)).to.be.true; expect([rect.width, rect.height]).to.deep.equal([CIRCLE[size], CIRCLE[size]]); }); }); SIZES.forEach((size, i) => { it(`${129 + i}. composes pill with size="${size}"`, async () => { const el = await themed(html`Label`); expect(base(el).classList.contains('button--pill')).to.be.true; expect(base(el).classList.contains(`button--${size}`)).to.be.true; expect(base(el).getBoundingClientRect().height).to.equal(HEIGHT[size]); }); }); SIZES.forEach((size, i) => { it(`${133 + i}. composes loading with size="${size}"`, async () => { const el = await themed(html`Label`); expect(base(el).classList.contains('button--loading')).to.be.true; expect(base(el).classList.contains(`button--${size}`)).to.be.true; expect(el.shadowRoot!.querySelector('nile-spinner')).to.exist; expect(base(el).getBoundingClientRect().height).to.equal(HEIGHT[size]); }); }); it('137. composes caret and outline with a non-default size', async () => { const el = await themed(html`Label`); expect(base(el).classList.contains('button--caret')).to.be.true; expect(base(el).classList.contains('button--outline')).to.be.true; expect(base(el).getBoundingClientRect().height).to.equal(44); }); ['primary', 'secondary', 'tertiary', 'destructive'].forEach((variant, i) => { it(`${138 + i}. composes variant="${variant}" with size="xl"`, async () => { const el = await themed(html`Label`); expect(base(el).classList.contains(`button--${variant}`)).to.be.true; expect(base(el).getBoundingClientRect().height).to.equal(48); }); }); it('142. applies size to the link (href) rendering', async () => { const el = await themed(html`Label`); expect(base(el).tagName).to.equal('A'); expect(base(el).classList.contains('button--sm')).to.be.true; expect(base(el).getBoundingClientRect().height).to.equal(36); }); }); });