import '../../../dist/zn.min.js'; import {aTimeout, expect, fixture, html, waitUntil} from '@open-wc/testing'; import {render} from 'lit'; import type ZnNavbar from './navbar.component'; describe('', () => { it('should render a component', async () => { const el = await fixture(html` `); expect(el).to.exist; }); it('does not move Lit-owned light DOM items when the parent rerenders', async () => { const host = document.createElement('div'); document.body.append(host); try { render(html`
  • One
  • `, host); await aTimeout(20); render(html`
  • One
  • Two
  • `, host); await aTimeout(20); const navbar = host.querySelector('zn-navbar')!; const shadowItems = navbar.shadowRoot!.querySelectorAll('li[tab]'); const lightItems = navbar.querySelectorAll('li[tab]'); expect(lightItems.length).to.equal(2); expect(shadowItems.length).to.equal(2); expect(shadowItems[0]).to.not.equal(lightItems[0]); expect(shadowItems[1].textContent?.trim()).to.equal('Two'); } finally { render(html``, host); host.remove(); } }); it('reserves at least 200px for visible nav items when expandables need space', async () => { const el = await fixture(html`
  • One
  • Two
  • Three
  • Four
  • `); await aTimeout(150); const nav = el.shadowRoot!.querySelector('ul.navbar')!; const expandable = el.shadowRoot!.querySelector('.expandables')!; const items = Array.from(nav.querySelectorAll(':scope > li:not(.more)')); Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 500}); Object.defineProperty(expandable, 'offsetWidth', {configurable: true, get: () => 400}); Object.defineProperty(expandable, 'getBoundingClientRect', { configurable: true, value: () => ({width: 400}) }); items.forEach(item => { Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 120}); Object.defineProperty(item, 'getBoundingClientRect', { configurable: true, value: () => ({width: 120}) }); }); el.handleResize(); expect(getComputedStyle(nav).minWidth).to.equal('200px'); expect(items[0].classList.contains('hidden')).to.equal(false); expect(items[1].classList.contains('hidden')).to.equal(true); }); it('accounts for open fill expandables when collapsing nav items', async () => { const el = await fixture(html`
  • One
  • Two
  • Three
  • Four
  • `); await aTimeout(150); const nav = el.shadowRoot!.querySelector('ul.navbar')!; const expandable = el.shadowRoot!.querySelector('.expandables')!; const items = Array.from(nav.querySelectorAll(':scope > li:not(.more)')); Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 1000}); Object.defineProperty(expandable, 'offsetWidth', {configurable: true, get: () => 40}); Object.defineProperty(expandable, 'getBoundingClientRect', { configurable: true, value: () => ({width: 40}) }); items.forEach(item => { Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 120}); Object.defineProperty(item, 'getBoundingClientRect', { configurable: true, value: () => ({width: 120}) }); }); el.handleResize(); expect(items[0].classList.contains('hidden')).to.equal(false); expect(items[1].classList.contains('hidden')).to.equal(true); }); it('reserves nav padding and the more button before leaving items visible', async () => { const el = await fixture(html`
  • One
  • Two
  • Three
  • `); await aTimeout(150); const nav = el.shadowRoot!.querySelector('ul.navbar')!; const more = nav.querySelector(':scope > li.more')!; const items = Array.from(nav.querySelectorAll(':scope > li:not(.more)')); nav.style.paddingLeft = '20px'; nav.style.paddingRight = '20px'; Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 290}); Object.defineProperty(more, 'offsetWidth', {configurable: true, get: () => 60}); Object.defineProperty(more, 'getBoundingClientRect', { configurable: true, value: () => ({width: 60}) }); items.forEach(item => { Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 120}); Object.defineProperty(item, 'getBoundingClientRect', { configurable: true, value: () => ({width: 120}) }); }); el.handleResize(); expect(items[0].classList.contains('hidden')).to.equal(false); expect(items[1].classList.contains('hidden')).to.equal(true); expect(nav.classList.contains('has-hidden')).to.equal(true); }); it('rounds the last visible nav item when items are hidden behind more', async () => { const el = await fixture(html`
  • One
  • Two
  • Three
  • `); await aTimeout(150); const nav = el.shadowRoot!.querySelector('ul.navbar')!; const more = nav.querySelector(':scope > li.more')!; const items = Array.from(nav.querySelectorAll(':scope > li:not(.more)')); Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 250}); Object.defineProperty(more, 'offsetWidth', {configurable: true, get: () => 60}); Object.defineProperty(more, 'getBoundingClientRect', { configurable: true, value: () => ({width: 60}) }); items.forEach(item => { Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 100}); Object.defineProperty(item, 'getBoundingClientRect', { configurable: true, value: () => ({width: 100}) }); }); el.handleResize(); expect(nav.classList.contains('has-hidden')).to.equal(true); expect(items[0].classList.contains('last-visible')).to.equal(true); expect(items[1].classList.contains('hidden')).to.equal(true); expect(getComputedStyle(items[0]).borderTopRightRadius).to.equal('6px'); }); it('keeps the left border when only the more button is visible', async () => { const el = await fixture(html`
  • One
  • Two
  • `); await aTimeout(150); const nav = el.shadowRoot!.querySelector('ul.navbar')!; const more = nav.querySelector(':scope > li.more')!; const items = Array.from(nav.querySelectorAll(':scope > li:not(.more)')); Object.defineProperty(el, 'offsetWidth', {configurable: true, get: () => 100}); Object.defineProperty(more, 'offsetWidth', {configurable: true, get: () => 60}); Object.defineProperty(more, 'getBoundingClientRect', { configurable: true, value: () => ({width: 60}) }); items.forEach(item => { Object.defineProperty(item, 'offsetWidth', {configurable: true, get: () => 150}); Object.defineProperty(item, 'getBoundingClientRect', { configurable: true, value: () => ({width: 150}) }); }); el.handleResize(); expect(nav.classList.contains('has-hidden')).to.equal(true); expect(nav.classList.contains('more-only')).to.equal(true); expect(items.every(item => item.classList.contains('hidden'))).to.equal(true); expect(getComputedStyle(more).borderLeftWidth).to.equal('1px'); expect(getComputedStyle(more).borderTopLeftRadius).to.equal('6px'); }); describe('hide-one', () => { it('hides when only one item is present', async () => { const el = await fixture(html`
  • Only
  • `); await aTimeout(0); expect(getComputedStyle(el).display).to.equal('none'); }); it('reveals when a second item is added dynamically', async () => { const el = await fixture(html`
  • First
  • `); await aTimeout(0); expect(getComputedStyle(el).display).to.equal('none'); const li = document.createElement('li'); li.setAttribute('tab-uri', '/two'); li.textContent = 'Second'; el.addItem(li, false); await waitUntil(() => getComputedStyle(el).display !== 'none', 'navbar should become visible after second item added'); }); it('hides again when items drop back to one', async () => { const el = await fixture(html`
  • First
  • `); const second = document.createElement('li'); second.setAttribute('tab-uri', '/two'); second.textContent = 'Second'; el.addItem(second, false); await waitUntil(() => getComputedStyle(el).display !== 'none', 'navbar should become visible after second item added'); second.remove(); await waitUntil(() => getComputedStyle(el).display === 'none', 'navbar should hide after dropping back to one item'); }); }); });