`);
expect(stub).to.be.calledOnceWithExactly(
`The amount of tabs (1) doesn't match the amount of panels (2).`,
);
stub.restore();
});
});
describe('Tabs ([slot=tab])', () => {
it('adds role=tab', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel
`));
expect(Array.from(el.children).find(child => child.slot === 'tab')).to.have.attribute(
'role',
'tab',
);
});
/**
* Not in scope:
* - has flexible html that allows animations like the material design underline
*/
});
describe('Tab Panels (slot=panel)', () => {
it('are visible when corresponding tab is selected ', async () => {
const el = /** @type {LionTabs} */ (await fixture(basicTabs));
const panels = el.querySelectorAll('[slot=panel]');
el.selectedIndex = 0;
expect(panels[0]).to.be.visible;
expect(panels[1]).to.be.not.visible;
el.selectedIndex = 1;
expect(panels[0]).to.be.not.visible;
expect(panels[1]).to.be.visible;
});
it.skip('have a DOM structure that allows them to be animated ', async () => {});
});
/**
* We will immediately switch content as all our content comes from light dom.
*
* See Note at https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-19
* > It is recommended that tabs activate automatically when they receive focus as long as their
* > associated tab panels are displayed without noticeable latency. This typically requires tab
* > panel content to be preloaded.
*/
describe('User interaction', () => {
it('selects a tab on click', async () => {
const el = /** @type {LionTabs} */ (await fixture(basicTabs));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[1].dispatchEvent(new Event('click'));
expect(el.selectedIndex).to.equal(1);
});
it('selects next tab on [arrow-right] and [arrow-down]', async () => {
const el = /** @type {LionTabs} */ (await fixture(basicTabs));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[0].dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowRight' }));
expect(el.selectedIndex).to.equal(1);
tabs[1].dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowDown' }));
expect(el.selectedIndex).to.equal(2);
});
it('selects previous tab on [arrow-left] and [arrow-up]', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
`));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[1].dispatchEvent(new KeyboardEvent('keyup', { key: 'Home' }));
expect(el.selectedIndex).to.equal(0);
});
it('selects last tab on [end]', async () => {
const el = /** @type {LionTabs} */ (await fixture(basicTabs));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[0].dispatchEvent(new KeyboardEvent('keyup', { key: 'End' }));
expect(el.selectedIndex).to.equal(2);
});
it('selects first tab on [arrow-right] if on last tab', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel 1
panel 2
panel 3
`));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[2].dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowRight' }));
expect(el.selectedIndex).to.equal(0);
});
it('selects last tab on [arrow-left] if on first tab', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel 1
panel 2
panel 3
`));
const tabs = el.querySelectorAll('[slot=tab]');
tabs[0].dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowLeft' }));
expect(el.selectedIndex).to.equal(2);
});
});
describe('Content distribution', () => {
it('should work with append children', async () => {
const el = /** @type {LionTabs} */ (await fixture(basicTabs));
const c = 2;
const n = el.children.length / 2;
for (let i = n + 1; i < n + c + 1; i += 1) {
const tab = document.createElement('button');
tab.setAttribute('slot', 'tab');
tab.innerText = `tab ${i}`;
const panel = document.createElement('panel');
panel.setAttribute('slot', 'panel');
panel.innerText = `panel ${i}`;
el.append(tab);
el.append(panel);
}
el.selectedIndex = el.children.length / 2 - 1;
await el.updateComplete;
const selectedTab = Array.from(el.children).find(
child => child.slot === 'tab' && child.hasAttribute('selected'),
);
expect(selectedTab && selectedTab.textContent).to.equal('tab 5');
const selectedPanel = Array.from(el.children).find(
child => child.slot === 'panel' && child.hasAttribute('selected'),
);
expect(selectedPanel && selectedPanel.textContent).to.equal('panel 5');
});
});
describe('Initializing without Focus', () => {
it('does not focus a tab when setting selectedIndex property', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel 1
panel 2
`));
el.selectedIndex = 1;
expect(el.querySelector('[slot="tab"]:nth-of-type(2)') === document.activeElement).to.be
.false;
});
it('does not focus a tab on firstUpdate', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel 1
panel 2
`));
const tabs = Array.from(el.children).filter(child => child.slot === 'tab');
expect(tabs.some(tab => tab === document.activeElement)).to.be.false;
});
it('focuses on a tab when setting with _setSelectedIndexWithFocus method', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`
panel 1
panel 2
`));
el._setSelectedIndexWithFocus(1);
expect(el.querySelector('[slot="tab"]:nth-of-type(2)') === document.activeElement).to.be.true;
});
});
it('focuses on a tab when the selected tab is changed by user interaction', async () => {
const el = /** @type {LionTabs} */ (await fixture(html`