From 3ea39841c8049525e31e9f4d6300f0c60cdb42de Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 24 Jan 2023 13:33:51 +0100 Subject: Adding upstream version 5.2.3+dfsg. Signed-off-by: Daniel Baumann --- js/tests/unit/tab.spec.js | 1101 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1101 insertions(+) create mode 100644 js/tests/unit/tab.spec.js (limited to 'js/tests/unit/tab.spec.js') diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js new file mode 100644 index 0000000..e0c7d86 --- /dev/null +++ b/js/tests/unit/tab.spec.js @@ -0,0 +1,1101 @@ +import Tab from '../../src/tab' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' + +describe('Tab', () => { + let fixtureEl + + beforeAll(() => { + fixtureEl = getFixture() + }) + + afterEach(() => { + clearFixture() + }) + + describe('VERSION', () => { + it('should return plugin version', () => { + expect(Tab.VERSION).toEqual(jasmine.any(String)) + }) + }) + + describe('constructor', () => { + it('should take care of element either passed as a CSS selector or DOM element', () => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const tabEl = fixtureEl.querySelector('[href="#home"]') + const tabBySelector = new Tab('[href="#home"]') + const tabByElement = new Tab(tabEl) + + expect(tabBySelector._element).toEqual(tabEl) + expect(tabByElement._element).toEqual(tabEl) + }) + + it('Do not Throw exception if not parent', () => { + fixtureEl.innerHTML = [ + fixtureEl.innerHTML = '
' + ].join('') + const navEl = fixtureEl.querySelector('.nav-link') + + expect(() => { + new Tab(navEl) // eslint-disable-line no-new + }).not.toThrowError(TypeError) + }) + }) + + describe('show', () => { + it('should activate element by tab id (using buttons, the preferred semantic way)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') + resolve() + }) + + tab.show() + }) + }) + + it('should activate element by tab id (using links for tabs - not ideal, but still supported)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') + resolve() + }) + + tab.show() + }) + }) + + it('should activate element by tab id in ordered list', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
    ', + '
  1. ', + '
  2. ', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) + + tab.show() + }) + }) + + it('should activate element by tab id in nav list', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) + + tab.show() + }) + }) + + it('should activate element by tab id in list group', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + ' ', + '
', + '
', + '
', + '
', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) + + tab.show() + }) + }) + + it('should not fire shown when show is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' + + const navEl = fixtureEl.querySelector('.nav > div') + const tab = new Tab(navEl) + const expectDone = () => { + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + } + + navEl.addEventListener('show.bs.tab', ev => { + ev.preventDefault() + expectDone() + }) + + navEl.addEventListener('shown.bs.tab', () => { + reject(new Error('should not trigger shown event')) + }) + + tab.show() + }) + }) + + it('should not fire shown when tab is already active', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerActive = fixtureEl.querySelector('button.active') + const tab = new Tab(triggerActive) + + triggerActive.addEventListener('shown.bs.tab', () => { + reject(new Error('should not trigger shown event')) + }) + + tab.show() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + }) + }) + + it('show and shown events should reference correct relatedTarget', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') + const secondTab = new Tab(secondTabTrigger) + + secondTabTrigger.addEventListener('show.bs.tab', ev => { + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') + }) + + secondTabTrigger.addEventListener('shown.bs.tab', ev => { + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') + expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true') + expect(fixtureEl.querySelector('button:not(.active)').getAttribute('aria-selected')).toEqual('false') + resolve() + }) + + secondTab.show() + }) + }) + + it('should fire hide and hidden events', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const triggerList = fixtureEl.querySelectorAll('button') + const firstTab = new Tab(triggerList[0]) + const secondTab = new Tab(triggerList[1]) + + let hideCalled = false + triggerList[0].addEventListener('shown.bs.tab', () => { + secondTab.show() + }) + + triggerList[0].addEventListener('hide.bs.tab', ev => { + hideCalled = true + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') + }) + + triggerList[0].addEventListener('hidden.bs.tab', ev => { + expect(hideCalled).toBeTrue() + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') + resolve() + }) + + firstTab.show() + }) + }) + + it('should not fire hidden when hide is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const triggerList = fixtureEl.querySelectorAll('button') + const firstTab = new Tab(triggerList[0]) + const secondTab = new Tab(triggerList[1]) + const expectDone = () => { + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + } + + triggerList[0].addEventListener('shown.bs.tab', () => { + secondTab.show() + }) + + triggerList[0].addEventListener('hide.bs.tab', ev => { + ev.preventDefault() + expectDone() + }) + + triggerList[0].addEventListener('hidden.bs.tab', () => { + reject(new Error('should not trigger hidden')) + }) + + firstTab.show() + }) + }) + + it('should handle removed tabs', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
test 3
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + const btnCloseEl = fixtureEl.querySelector('#btnClose') + const secondNavTab = new Tab(secondNavEl) + + secondNavEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelectorAll('.nav-tab')).toHaveSize(2) + resolve() + }) + + btnCloseEl.addEventListener('click', () => { + const linkEl = btnCloseEl.parentNode + const liEl = linkEl.parentNode + const tabId = linkEl.getAttribute('href') + const tabIdEl = fixtureEl.querySelector(tabId) + + liEl.remove() + tabIdEl.remove() + secondNavTab.show() + }) + + btnCloseEl.click() + }) + }) + + it('should not focus on opened tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const firstTab = fixtureEl.querySelector('#home') + firstTab.focus() + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(document.activeElement).toBe(firstTab) + expect(document.activeElement).not.toBe(profileTriggerEl) + resolve() + }) + + tab.show() + }) + }) + }) + + describe('dispose', () => { + it('should dispose a tab', () => { + fixtureEl.innerHTML = '' + + const el = fixtureEl.querySelector('.nav > div') + const tab = new Tab(fixtureEl.querySelector('.nav > div')) + + expect(Tab.getInstance(el)).not.toBeNull() + + tab.dispose() + + expect(Tab.getInstance(el)).toBeNull() + }) + }) + + describe('_activate', () => { + it('should not be called if element argument is null', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl = fixtureEl.querySelector('.nav-link') + const tab = new Tab(tabEl) + const spy = jasmine.createSpy('spy') + + const spyQueue = spyOn(tab, '_queueCallback') + tab._activate(null, spy) + expect(spyQueue).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() + }) + }) + + describe('_setInitialAttributes', () => { + it('should put aria attributes', () => { + fixtureEl.innerHTML = [ + '', + '
', + '
' + ].join('') + + const tabEl = fixtureEl.querySelector('.nav-link') + const parent = fixtureEl.querySelector('.nav') + const children = fixtureEl.querySelectorAll('.nav-link') + const tabPanel = fixtureEl.querySelector('#panel') + const tabPanel2 = fixtureEl.querySelector('#panel2') + + expect(parent.getAttribute('role')).toEqual(null) + expect(tabEl.getAttribute('role')).toEqual(null) + expect(tabPanel.getAttribute('role')).toEqual(null) + const tab = new Tab(tabEl) + tab._setInitialAttributes(parent, children) + + expect(parent.getAttribute('role')).toEqual('tablist') + expect(tabEl.getAttribute('role')).toEqual('tab') + + expect(tabPanel.getAttribute('role')).toEqual('tabpanel') + expect(tabPanel2.getAttribute('role')).toEqual('tabpanel') + expect(tabPanel.hasAttribute('tabindex')).toBeFalse() + expect(tabPanel.hasAttribute('tabindex2')).toBeFalse() + + expect(tabPanel.getAttribute('aria-labelledby')).toEqual('#foo') + expect(tabPanel2.hasAttribute('aria-labelledby')).toBeFalse() + }) + }) + + describe('_keydown', () => { + it('if event is not one of left/right/up/down arrow, ignore it', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl = fixtureEl.querySelector('.nav-link') + const tab = new Tab(tabEl) + + const keydown = createEvent('keydown') + keydown.key = 'Enter' + const spyStop = spyOn(Event.prototype, 'stopPropagation').and.callThrough() + const spyPrevent = spyOn(Event.prototype, 'preventDefault').and.callThrough() + const spyKeydown = spyOn(tab, '_keydown') + const spyGet = spyOn(tab, '_getChildren') + + tabEl.dispatchEvent(keydown) + expect(spyKeydown).toHaveBeenCalled() + expect(spyGet).not.toHaveBeenCalled() + + expect(spyStop).not.toHaveBeenCalled() + expect(spyPrevent).not.toHaveBeenCalled() + }) + + it('if keydown event is right/down arrow, handle it', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl1 = fixtureEl.querySelector('#tab1') + const tabEl2 = fixtureEl.querySelector('#tab2') + const tabEl3 = fixtureEl.querySelector('#tab3') + const tab1 = new Tab(tabEl1) + const tab2 = new Tab(tabEl2) + const tab3 = new Tab(tabEl3) + const spyShow1 = spyOn(tab1, 'show').and.callThrough() + const spyShow2 = spyOn(tab2, 'show').and.callThrough() + const spyShow3 = spyOn(tab3, 'show').and.callThrough() + const spyFocus1 = spyOn(tabEl1, 'focus').and.callThrough() + const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() + const spyFocus3 = spyOn(tabEl3, 'focus').and.callThrough() + + const spyStop = spyOn(Event.prototype, 'stopPropagation').and.callThrough() + const spyPrevent = spyOn(Event.prototype, 'preventDefault').and.callThrough() + + let keydown = createEvent('keydown') + keydown.key = 'ArrowRight' + + tabEl1.dispatchEvent(keydown) + expect(spyShow2).toHaveBeenCalled() + expect(spyFocus2).toHaveBeenCalled() + + keydown = createEvent('keydown') + keydown.key = 'ArrowDown' + + tabEl2.dispatchEvent(keydown) + expect(spyShow3).toHaveBeenCalled() + expect(spyFocus3).toHaveBeenCalled() + + tabEl3.dispatchEvent(keydown) + expect(spyShow1).toHaveBeenCalled() + expect(spyFocus1).toHaveBeenCalled() + + expect(spyStop).toHaveBeenCalledTimes(3) + expect(spyPrevent).toHaveBeenCalledTimes(3) + }) + + it('if keydown event is left arrow, handle it', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl1 = fixtureEl.querySelector('#tab1') + const tabEl2 = fixtureEl.querySelector('#tab2') + const tab1 = new Tab(tabEl1) + const tab2 = new Tab(tabEl2) + const spyShow1 = spyOn(tab1, 'show').and.callThrough() + const spyShow2 = spyOn(tab2, 'show').and.callThrough() + const spyFocus1 = spyOn(tabEl1, 'focus').and.callThrough() + const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() + + const spyStop = spyOn(Event.prototype, 'stopPropagation').and.callThrough() + const spyPrevent = spyOn(Event.prototype, 'preventDefault').and.callThrough() + + let keydown = createEvent('keydown') + keydown.key = 'ArrowLeft' + + tabEl2.dispatchEvent(keydown) + expect(spyShow1).toHaveBeenCalled() + expect(spyFocus1).toHaveBeenCalled() + + keydown = createEvent('keydown') + keydown.key = 'ArrowUp' + + tabEl1.dispatchEvent(keydown) + expect(spyShow2).toHaveBeenCalled() + expect(spyFocus2).toHaveBeenCalled() + + expect(spyStop).toHaveBeenCalledTimes(2) + expect(spyPrevent).toHaveBeenCalledTimes(2) + }) + + it('if keydown event is right arrow and next element is disabled', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl = fixtureEl.querySelector('#tab1') + const tabEl2 = fixtureEl.querySelector('#tab2') + const tabEl3 = fixtureEl.querySelector('#tab3') + const tabEl4 = fixtureEl.querySelector('#tab4') + const tab = new Tab(tabEl) + const tab2 = new Tab(tabEl2) + const tab3 = new Tab(tabEl3) + const tab4 = new Tab(tabEl4) + const spy1 = spyOn(tab, 'show').and.callThrough() + const spy2 = spyOn(tab2, 'show').and.callThrough() + const spy3 = spyOn(tab3, 'show').and.callThrough() + const spy4 = spyOn(tab4, 'show').and.callThrough() + const spyFocus1 = spyOn(tabEl, 'focus').and.callThrough() + const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() + const spyFocus3 = spyOn(tabEl3, 'focus').and.callThrough() + const spyFocus4 = spyOn(tabEl4, 'focus').and.callThrough() + + const keydown = createEvent('keydown') + keydown.key = 'ArrowRight' + + tabEl.dispatchEvent(keydown) + expect(spy1).not.toHaveBeenCalled() + expect(spy2).not.toHaveBeenCalled() + expect(spy3).not.toHaveBeenCalled() + expect(spy4).toHaveBeenCalledTimes(1) + expect(spyFocus1).not.toHaveBeenCalled() + expect(spyFocus2).not.toHaveBeenCalled() + expect(spyFocus3).not.toHaveBeenCalled() + expect(spyFocus4).toHaveBeenCalledTimes(1) + }) + + it('if keydown event is left arrow and next element is disabled', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl = fixtureEl.querySelector('#tab1') + const tabEl2 = fixtureEl.querySelector('#tab2') + const tabEl3 = fixtureEl.querySelector('#tab3') + const tabEl4 = fixtureEl.querySelector('#tab4') + const tab = new Tab(tabEl) + const tab2 = new Tab(tabEl2) + const tab3 = new Tab(tabEl3) + const tab4 = new Tab(tabEl4) + const spy1 = spyOn(tab, 'show').and.callThrough() + const spy2 = spyOn(tab2, 'show').and.callThrough() + const spy3 = spyOn(tab3, 'show').and.callThrough() + const spy4 = spyOn(tab4, 'show').and.callThrough() + const spyFocus1 = spyOn(tabEl, 'focus').and.callThrough() + const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() + const spyFocus3 = spyOn(tabEl3, 'focus').and.callThrough() + const spyFocus4 = spyOn(tabEl4, 'focus').and.callThrough() + + const keydown = createEvent('keydown') + keydown.key = 'ArrowLeft' + + tabEl4.dispatchEvent(keydown) + expect(spy4).not.toHaveBeenCalled() + expect(spy3).not.toHaveBeenCalled() + expect(spy2).not.toHaveBeenCalled() + expect(spy1).toHaveBeenCalledTimes(1) + expect(spyFocus4).not.toHaveBeenCalled() + expect(spyFocus3).not.toHaveBeenCalled() + expect(spyFocus2).not.toHaveBeenCalled() + expect(spyFocus1).toHaveBeenCalledTimes(1) + }) + }) + + describe('jQueryInterface', () => { + it('should create a tab', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('.nav > div') + + jQueryMock.fn.tab = Tab.jQueryInterface + jQueryMock.elements = [div] + + jQueryMock.fn.tab.call(jQueryMock) + + expect(Tab.getInstance(div)).not.toBeNull() + }) + + it('should not re create a tab', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('.nav > div') + const tab = new Tab(div) + + jQueryMock.fn.tab = Tab.jQueryInterface + jQueryMock.elements = [div] + + jQueryMock.fn.tab.call(jQueryMock) + + expect(Tab.getInstance(div)).toEqual(tab) + }) + + it('should call a tab method', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('.nav > div') + const tab = new Tab(div) + + const spy = spyOn(tab, 'show') + + jQueryMock.fn.tab = Tab.jQueryInterface + jQueryMock.elements = [div] + + jQueryMock.fn.tab.call(jQueryMock, 'show') + + expect(Tab.getInstance(div)).toEqual(tab) + expect(spy).toHaveBeenCalled() + }) + + it('should throw error on undefined method', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('.nav > div') + const action = 'undefinedMethod' + + jQueryMock.fn.tab = Tab.jQueryInterface + jQueryMock.elements = [div] + + expect(() => { + jQueryMock.fn.tab.call(jQueryMock, action) + }).toThrowError(TypeError, `No method named "${action}"`) + }) + }) + + describe('getInstance', () => { + it('should return null if there is no instance', () => { + expect(Tab.getInstance(fixtureEl)).toBeNull() + }) + + it('should return this instance', () => { + fixtureEl.innerHTML = '' + + const divEl = fixtureEl.querySelector('.nav > div') + const tab = new Tab(divEl) + + expect(Tab.getInstance(divEl)).toEqual(tab) + expect(Tab.getInstance(divEl)).toBeInstanceOf(Tab) + }) + }) + + describe('getOrCreateInstance', () => { + it('should return tab instance', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('div') + const tab = new Tab(div) + + expect(Tab.getOrCreateInstance(div)).toEqual(tab) + expect(Tab.getInstance(div)).toEqual(Tab.getOrCreateInstance(div, {})) + expect(Tab.getOrCreateInstance(div)).toBeInstanceOf(Tab) + }) + + it('should return new instance when there is no tab instance', () => { + fixtureEl.innerHTML = '' + + const div = fixtureEl.querySelector('div') + + expect(Tab.getInstance(div)).toBeNull() + expect(Tab.getOrCreateInstance(div)).toBeInstanceOf(Tab) + }) + }) + + describe('data-api', () => { + it('should create dynamically a tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') + + secondTabTrigger.addEventListener('shown.bs.tab', () => { + expect(secondTabTrigger).toHaveClass('active') + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) + + secondTabTrigger.click() + }) + }) + + it('selected tab should deactivate previous selected link in dropdown', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const firstLiLinkEl = fixtureEl.querySelector('li:first-child a') + + firstLiLinkEl.click() + expect(firstLiLinkEl).toHaveClass('active') + expect(fixtureEl.querySelector('li:last-child a')).not.toHaveClass('active') + expect(fixtureEl.querySelector('li:last-child .dropdown-menu a:first-child')).not.toHaveClass('active') + }) + + it('selecting a dropdown tab does not activate another', () => { + const nav1 = [ + '' + ].join('') + const nav2 = [ + '' + ].join('') + + fixtureEl.innerHTML = nav1 + nav2 + + const firstDropItem = fixtureEl.querySelector('#nav1 .dropdown-item') + + firstDropItem.click() + expect(firstDropItem).toHaveClass('active') + expect(fixtureEl.querySelector('#nav1 .dropdown-toggle')).toHaveClass('active') + expect(fixtureEl.querySelector('#nav2 .dropdown-toggle')).not.toHaveClass('active') + expect(fixtureEl.querySelector('#nav2 .dropdown-item')).not.toHaveClass('active') + }) + + it('should support li > .dropdown-item', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const dropItems = fixtureEl.querySelectorAll('.dropdown-item') + + dropItems[1].click() + expect(dropItems[0]).not.toHaveClass('active') + expect(dropItems[1]).toHaveClass('active') + expect(fixtureEl.querySelector('.nav-link')).not.toHaveClass('active') + }) + + it('should handle nested tabs', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' ', + '
', + '
Nested Tab1 Content
', + '
Nested Tab2 Content
', + '
', + '
', + '
Tab2 Content
', + '
Tab3 Content
', + '
' + ].join('') + + const tab1El = fixtureEl.querySelector('#tab1') + const tabNested2El = fixtureEl.querySelector('#tabNested2') + const xTab1El = fixtureEl.querySelector('#x-tab1') + + tabNested2El.addEventListener('shown.bs.tab', () => { + expect(xTab1El).toHaveClass('active') + resolve() + }) + + tab1El.addEventListener('shown.bs.tab', () => { + expect(xTab1El).toHaveClass('active') + tabNested2El.click() + }) + + tab1El.click() + }) + }) + + it('should not remove fade class if no active pane is present', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerTabProfileEl = fixtureEl.querySelector('#tab-profile') + const triggerTabHomeEl = fixtureEl.querySelector('#tab-home') + const tabProfileEl = fixtureEl.querySelector('#profile') + const tabHomeEl = fixtureEl.querySelector('#home') + + triggerTabHomeEl.addEventListener('shown.bs.tab', () => { + setTimeout(() => { + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).not.toHaveClass('show') + + expect(tabHomeEl).toHaveClass('fade') + expect(tabHomeEl).toHaveClass('show') + + resolve() + }, 10) + }) + + triggerTabProfileEl.addEventListener('shown.bs.tab', () => { + setTimeout(() => { + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).toHaveClass('show') + triggerTabHomeEl.click() + }, 10) + }) + + triggerTabProfileEl.click() + }) + }) + + it('should add `show` class to tab panes if there is no `.fade` class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + + secondNavEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelectorAll('.tab-content .show')).toHaveSize(1) + resolve() + }) + + secondNavEl.click() + }) + }) + + it('should add show class to tab panes if there is a `.fade` class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + + secondNavEl.addEventListener('shown.bs.tab', () => { + setTimeout(() => { + expect(fixtureEl.querySelectorAll('.show')).toHaveSize(1) + resolve() + }, 10) + }) + + secondNavEl.click() + }) + }) + + it('should prevent default when the trigger is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const tabEl = fixtureEl.querySelector('[href="#test2"]') + const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough() + + tabEl.addEventListener('shown.bs.tab', () => { + expect(tabEl).toHaveClass('active') + expect(spy).toHaveBeenCalled() + resolve() + }) + + tabEl.click() + }) + }) + + it('should not fire shown when tab has disabled attribute', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerDisabled = fixtureEl.querySelector('button[disabled]') + triggerDisabled.addEventListener('shown.bs.tab', () => { + reject(new Error('should not trigger shown event')) + }) + + triggerDisabled.click() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + }) + }) + + it('should not fire shown when tab has disabled class', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerDisabled = fixtureEl.querySelector('a.disabled') + + triggerDisabled.addEventListener('shown.bs.tab', () => { + reject(new Error('should not trigger shown event')) + }) + + triggerDisabled.click() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + }) + }) + }) +}) -- cgit v1.2.3