import '../../../dist/zn.min.js'; import { aTimeout, expect, fixture, html } from '@open-wc/testing'; import { locationScopedKey } from './tabs-navigation'; import type ZnTabs from './tabs.component'; describe('', () => { it('should render a component', async () => { const el = await fixture(html` `); expect(el).to.exist; }); it('does not register tabs belonging to a nested zn-page', async () => { const el = await fixture(html`
Outer Home
Overview Content Details Content
`); await aTimeout(60); el.setActiveTab('outer-second', false, false); await aTimeout(20); // A menu selection bubbling out of the page (e.g. an ellipses action menu) // makes the outer tabs re-register; it must not claim the page's nav items. const page = el.querySelector('zn-page')!; page.dispatchEvent(new CustomEvent('zn-menu-select', { bubbles: true, composed: true })); await aTimeout(250); const navbar = page.shadowRoot!.querySelector('zn-navbar')!; const navItems = Array.from(navbar.shadowRoot!.querySelectorAll('li:not(.more)')); navItems[1].click(); await aTimeout(40); navItems[0].click(); await aTimeout(40); const outerHome = el.querySelector('.outer-home')!; const outerSecond = el.querySelector('#outer-second')!; expect(outerSecond.hasAttribute('selected')).to.equal(true); expect(outerHome.hasAttribute('selected')).to.equal(false); const selectedPagePanel = page.shadowRoot!.querySelector('#content > div[selected]')!; expect(selectedPagePanel.id).to.equal(''); }); describe('scroll position', () => { const panels = html`
  • First
  • Second
  • First panel
    Second panel
    `; const openSecondTab = async (el: ZnTabs) => { el.querySelector('zn-navbar')!.querySelectorAll('li')[1].click(); await aTimeout(40); expect(el.getAttribute('active')).to.equal('second'); }; it('opens a newly selected tab at the top of its own scroller', async () => { // zn-tabs is display:contents, so #content only has a height to overflow // when an ancestor gives it one. const wrapper = await fixture(html`
    ${panels}
    `); const el = wrapper.querySelector('zn-tabs')!; await aTimeout(40); const content = el.shadowRoot!.querySelector('#content')!; content.scrollTop = 500; expect(content.scrollTop, 'the content never scrolled').to.be.greaterThan(0); await openSecondTab(el); expect(content.scrollTop).to.equal(0); }); it('opens a newly selected tab at the top of an enclosing scroller', async () => { // Unconstrained, the panels grow instead of scrolling and something further // out - an app shell, an outer page - is what the reader has scrolled. const wrapper = await fixture(html`
    ${panels}
    `); const el = wrapper.querySelector('zn-tabs')!; await aTimeout(40); const content = el.shadowRoot!.querySelector('#content')!; wrapper.scrollTop = 500; expect(wrapper.scrollTop, 'the enclosing scroller never scrolled').to.be.greaterThan(0); expect(content.scrollTop, 'the panels scrolled themselves').to.equal(0); await openSecondTab(el); expect(wrapper.scrollTop).to.equal(0); }); }); describe('selection persistence', () => { const storeKey = 'tabs-navigation-test'; const originalHref = window.location.href; let locationCount = 0; const renderTabs = () => fixture(html`
  • First
  • Second
  • First panel
    Second panel
    `); // Each test runs on its own location so a stored selection, and whether that // location may restore one, cannot leak between them. const navigateTo = (name: string) => window.history.pushState({}, '', `?tabs-test=${name}`); const returnWithHistory = () => window.dispatchEvent(new PopStateEvent('popstate')); beforeEach(() => { locationCount += 1; navigateTo(`case-${locationCount}`); sessionStorage.removeItem(`zntab:${storeKey}`); }); afterEach(() => window.history.replaceState({}, '', originalHref)); it('restores the tab a location was left on when returning to it', async () => { const el = await renderTabs(); await aTimeout(40); el.querySelector('zn-navbar')!.querySelectorAll('li')[1].click(); await aTimeout(40); expect(el.getAttribute('active')).to.equal('second'); el.remove(); returnWithHistory(); const restored = await renderTabs(); await aTimeout(40); expect(restored.getAttribute('active')).to.equal('second'); }); it('starts from the default tab when navigating to the location', async () => { const first = await renderTabs(); await aTimeout(40); first.querySelector('zn-navbar')!.querySelectorAll('li')[1].click(); await aTimeout(40); first.remove(); // Leave and navigate back, rather than returning through history. const stored = window.location.search; navigateTo('elsewhere'); window.history.pushState({}, '', stored); const el = await renderTabs(); await aTimeout(40); expect(el.getAttribute('active')).to.equal('first'); }); it('stores tab changes made outside the navigation', async () => { const el = await renderTabs(); await aTimeout(40); el.nextTab(); await aTimeout(40); expect(el.getAttribute('active')).to.equal('second'); el.remove(); returnWithHistory(); const restored = await renderTabs(); await aTimeout(40); expect(restored.getAttribute('active')).to.equal('second'); }); it('steps back through each tab that was opened', async () => { const el = await renderTabs(); await aTimeout(40); const items = el.querySelector('zn-navbar')!.querySelectorAll('li'); items[1].click(); await aTimeout(40); expect(el.getAttribute('active')).to.equal('second'); await new Promise(resolve => { window.addEventListener('popstate', () => resolve(), {once: true}); window.history.back(); }); await aTimeout(40); expect(el.getAttribute('active')).to.equal('first'); }); it('forgets the selection once the location is navigated away from', async () => { const el = await renderTabs(); await aTimeout(40); el.querySelector('zn-navbar')!.querySelectorAll('li')[1].click(); await aTimeout(40); const stored = window.location.search; el.remove(); navigateTo('departed'); await aTimeout(40); expect(sessionStorage.getItem(`zntab:${storeKey}@${window.location.pathname}${stored}`)).to.equal(null); window.history.replaceState({}, '', stored); returnWithHistory(); const returned = await renderTabs(); await aTimeout(40); expect(returned.getAttribute('active')).to.equal('first'); }); it('keeps a session selection out of local storage', async () => { const el = await renderTabs(); await aTimeout(40); el.querySelector('zn-navbar')!.querySelectorAll('li')[1].click(); await aTimeout(40); expect(localStorage.getItem(`zntab:${storeKey}`)).to.equal(null); expect(sessionStorage.getItem(`zntab:${locationScopedKey(storeKey)}`)).to.contain('second'); }); }); });