diff options
Diffstat (limited to 'js/tests/unit')
25 files changed, 1096 insertions, 709 deletions
diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index cdda997c90..210ae9a25e 100644 --- a/js/tests/unit/alert.spec.js +++ b/js/tests/unit/alert.spec.js @@ -25,7 +25,7 @@ describe('Alert', () => { }) it('should return version', () => { - expect(typeof Alert.VERSION).toEqual('string') + expect(Alert.VERSION).toEqual(jasmine.any(String)) }) describe('DATA_KEY', () => { @@ -45,7 +45,7 @@ describe('Alert', () => { const button = document.querySelector('button') button.click() - expect(document.querySelectorAll('.alert').length).toEqual(0) + expect(document.querySelectorAll('.alert')).toHaveSize(0) }) it('should close an alert without instantiating it manually with the parent selector', () => { @@ -58,7 +58,7 @@ describe('Alert', () => { const button = document.querySelector('button') button.click() - expect(document.querySelectorAll('.alert').length).toEqual(0) + expect(document.querySelectorAll('.alert')).toHaveSize(0) }) }) @@ -71,7 +71,7 @@ describe('Alert', () => { const alert = new Alert(alertEl) alertEl.addEventListener('closed.bs.alert', () => { - expect(document.querySelectorAll('.alert').length).toEqual(0) + expect(document.querySelectorAll('.alert')).toHaveSize(0) expect(spy).not.toHaveBeenCalled() done() }) @@ -90,7 +90,7 @@ describe('Alert', () => { }) alertEl.addEventListener('closed.bs.alert', () => { - expect(document.querySelectorAll('.alert').length).toEqual(0) + expect(document.querySelectorAll('.alert')).toHaveSize(0) done() }) @@ -179,6 +179,34 @@ describe('Alert', () => { expect(Alert.getInstance(alertEl)).not.toBeNull() expect(fixtureEl.querySelector('.alert')).not.toBeNull() }) + + it('should throw an error on undefined method', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + const action = 'undefinedMethod' + + jQueryMock.fn.alert = Alert.jQueryInterface + jQueryMock.elements = [div] + + expect(() => { + jQueryMock.fn.alert.call(jQueryMock, action) + }).toThrowError(TypeError, `No method named "${action}"`) + }) + + it('should throw an error on protected method', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + const action = '_getConfig' + + jQueryMock.fn.alert = Alert.jQueryInterface + jQueryMock.elements = [div] + + expect(() => { + jQueryMock.fn.alert.call(jQueryMock, action) + }).toThrowError(TypeError, `No method named "${action}"`) + }) }) describe('getInstance', () => { @@ -197,7 +225,7 @@ describe('Alert', () => { const div = fixtureEl.querySelector('div') - expect(Alert.getInstance(div)).toEqual(null) + expect(Alert.getInstance(div)).toBeNull() }) }) @@ -218,7 +246,7 @@ describe('Alert', () => { const div = fixtureEl.querySelector('div') - expect(Alert.getInstance(div)).toEqual(null) + expect(Alert.getInstance(div)).toBeNull() expect(Alert.getOrCreateInstance(div)).toBeInstanceOf(Alert) }) }) diff --git a/js/tests/unit/base-component.spec.js b/js/tests/unit/base-component.spec.js index b8ec83f122..9e0b872d49 100644 --- a/js/tests/unit/base-component.spec.js +++ b/js/tests/unit/base-component.spec.js @@ -37,7 +37,7 @@ describe('Base Component', () => { describe('Static Methods', () => { describe('VERSION', () => { it('should return version', () => { - expect(typeof DummyClass.VERSION).toEqual('string') + expect(DummyClass.VERSION).toEqual(jasmine.any(String)) }) }) @@ -48,6 +48,13 @@ describe('Base Component', () => { }) describe('NAME', () => { + it('should throw an Error if it is not initialized', () => { + expect(() => { + // eslint-disable-next-line no-unused-expressions + BaseComponent.NAME + }).toThrowError(Error) + }) + it('should return plugin NAME', () => { expect(DummyClass.NAME).toEqual(name) }) @@ -59,6 +66,7 @@ describe('Base Component', () => { }) }) }) + describe('Public Methods', () => { describe('constructor', () => { it('should accept element, either passed as a CSS selector or DOM element', () => { @@ -74,7 +82,19 @@ describe('Base Component', () => { expect(elInstance._element).toEqual(el) expect(selectorInstance._element).toEqual(fixtureEl.querySelector('#bar')) }) + + it('should not initialize and add element record to Data (caching), if argument `element` is not an HTML element', () => { + fixtureEl.innerHTML = '' + + const el = fixtureEl.querySelector('#foo') + const elInstance = new DummyClass(el) + const selectorInstance = new DummyClass('#bar') + + expect(elInstance._element).not.toBeDefined() + expect(selectorInstance._element).not.toBeDefined() + }) }) + describe('dispose', () => { it('should dispose an component', () => { createInstance() @@ -123,9 +143,10 @@ describe('Base Component', () => { const div = fixtureEl.querySelector('div') - expect(DummyClass.getInstance(div)).toEqual(null) + expect(DummyClass.getInstance(div)).toBeNull() }) }) + describe('getOrCreateInstance', () => { it('should return an instance', () => { createInstance() @@ -139,7 +160,7 @@ describe('Base Component', () => { fixtureEl.innerHTML = '<div id="foo"></div>' element = fixtureEl.querySelector('#foo') - expect(DummyClass.getInstance(element)).toEqual(null) + expect(DummyClass.getInstance(element)).toBeNull() expect(DummyClass.getOrCreateInstance(element)).toBeInstanceOf(DummyClass) }) }) diff --git a/js/tests/unit/button.spec.js b/js/tests/unit/button.spec.js index e24ff5cb0f..30e62f0b3f 100644 --- a/js/tests/unit/button.spec.js +++ b/js/tests/unit/button.spec.js @@ -45,19 +45,19 @@ describe('Button', () => { const divTest = fixtureEl.querySelector('.test') const btnTestParent = fixtureEl.querySelector('.testParent') - expect(btn.classList.contains('active')).toEqual(false) + expect(btn).not.toHaveClass('active') btn.click() - expect(btn.classList.contains('active')).toEqual(true) + expect(btn).toHaveClass('active') btn.click() - expect(btn.classList.contains('active')).toEqual(false) + expect(btn).not.toHaveClass('active') divTest.click() - expect(btnTestParent.classList.contains('active')).toEqual(true) + expect(btnTestParent).toHaveClass('active') }) }) @@ -69,12 +69,12 @@ describe('Button', () => { const button = new Button(btnEl) expect(btnEl.getAttribute('aria-pressed')).toEqual('false') - expect(btnEl.classList.contains('active')).toEqual(false) + expect(btnEl).not.toHaveClass('active') button.toggle() expect(btnEl.getAttribute('aria-pressed')).toEqual('true') - expect(btnEl.classList.contains('active')).toEqual(true) + expect(btnEl).toHaveClass('active') }) }) @@ -121,7 +121,7 @@ describe('Button', () => { jQueryMock.fn.button.call(jQueryMock, 'toggle') expect(Button.getInstance(btnEl)).not.toBeNull() - expect(btnEl.classList.contains('active')).toEqual(true) + expect(btnEl).toHaveClass('active') }) it('should just create a button instance without calling toggle', () => { @@ -135,7 +135,7 @@ describe('Button', () => { jQueryMock.fn.button.call(jQueryMock) expect(Button.getInstance(btnEl)).not.toBeNull() - expect(btnEl.classList.contains('active')).toEqual(false) + expect(btnEl).not.toHaveClass('active') }) }) @@ -155,7 +155,7 @@ describe('Button', () => { const div = fixtureEl.querySelector('div') - expect(Button.getInstance(div)).toEqual(null) + expect(Button.getInstance(div)).toBeNull() }) }) @@ -176,7 +176,7 @@ describe('Button', () => { const div = fixtureEl.querySelector('div') - expect(Button.getInstance(div)).toEqual(null) + expect(Button.getInstance(div)).toBeNull() expect(Button.getOrCreateInstance(div)).toBeInstanceOf(Button) }) }) diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index a138f3ad55..ce9cd0fbcd 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -143,7 +143,7 @@ describe('Carousel', () => { carouselEl.addEventListener('keydown', event => { expect(carousel._keydown).toHaveBeenCalled() - expect(event.defaultPrevented).toEqual(false) + expect(event.defaultPrevented).toBeFalse() done() }) @@ -235,9 +235,7 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl, { wrap: true }) - const getActiveId = () => { - return carouselEl.querySelector('.carousel-item.active').getAttribute('id') - } + const getActiveId = () => carouselEl.querySelector('.carousel-item.active').getAttribute('id') carouselEl.addEventListener('slid.bs.carousel', event => { const activeId = getActiveId() @@ -285,7 +283,7 @@ describe('Carousel', () => { carousel.prev() setTimeout(() => { - expect(firstElement.classList.contains('active')).toEqual(true) + expect(firstElement).toHaveClass('active') done() }, 10) }) @@ -368,7 +366,7 @@ describe('Carousel', () => { spyOn(carousel, '_slide').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', event => { - expect(item.classList.contains('active')).toEqual(true) + expect(item).toHaveClass('active') expect(carousel._slide).toHaveBeenCalledWith('right') expect(event.direction).toEqual('right') stylesCarousel.remove() @@ -413,7 +411,7 @@ describe('Carousel', () => { spyOn(carousel, '_slide').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', event => { - expect(item.classList.contains('active')).toEqual(false) + expect(item).not.toHaveClass('active') expect(carousel._slide).toHaveBeenCalledWith('left') expect(event.direction).toEqual('left') stylesCarousel.remove() @@ -453,7 +451,7 @@ describe('Carousel', () => { spyOn(carousel, '_slide').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', event => { - expect(item.classList.contains('active')).toEqual(true) + expect(item).toHaveClass('active') expect(carousel._slide).toHaveBeenCalledWith('right') expect(event.direction).toEqual('right') delete document.documentElement.ontouchstart @@ -492,7 +490,7 @@ describe('Carousel', () => { spyOn(carousel, '_slide').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', event => { - expect(item.classList.contains('active')).toEqual(false) + expect(item).not.toHaveClass('active') expect(carousel._slide).toHaveBeenCalledWith('left') expect(event.direction).toEqual('left') delete document.documentElement.ontouchstart @@ -632,7 +630,7 @@ describe('Carousel', () => { const doneTest = () => { setTimeout(() => { - expect(slidEvent).toEqual(false) + expect(slidEvent).toBeFalse() done() }, 20) } @@ -665,7 +663,7 @@ describe('Carousel', () => { const onSlide = event => { expect(event.direction).toEqual('left') - expect(event.relatedTarget.classList.contains('carousel-item')).toEqual(true) + expect(event.relatedTarget).toHaveClass('carousel-item') expect(event.from).toEqual(0) expect(event.to).toEqual(1) @@ -700,7 +698,7 @@ describe('Carousel', () => { const onSlid = event => { expect(event.direction).toEqual('left') - expect(event.relatedTarget.classList.contains('carousel-item')).toEqual(true) + expect(event.relatedTarget).toHaveClass('carousel-item') expect(event.from).toEqual(0) expect(event.to).toEqual(1) @@ -761,9 +759,9 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) carouselEl.addEventListener('slid.bs.carousel', () => { - expect(firstIndicator.classList.contains('active')).toEqual(false) - expect(firstIndicator.hasAttribute('aria-current')).toEqual(false) - expect(secondIndicator.classList.contains('active')).toEqual(true) + expect(firstIndicator).not.toHaveClass('active') + expect(firstIndicator.hasAttribute('aria-current')).toBeFalse() + expect(secondIndicator).toHaveClass('active') expect(secondIndicator.getAttribute('aria-current')).toEqual('true') done() }) @@ -859,7 +857,7 @@ describe('Carousel', () => { expect(carousel.cycle).toHaveBeenCalledWith(true) expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(true) + expect(carousel._isPaused).toBeTrue() }) it('should not call cycle if nothing is in transition', () => { @@ -885,7 +883,7 @@ describe('Carousel', () => { expect(carousel.cycle).not.toHaveBeenCalled() expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(true) + expect(carousel._isPaused).toBeTrue() }) it('should not set is paused at true if an event is passed', () => { @@ -910,7 +908,7 @@ describe('Carousel', () => { carousel.pause(event) expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(false) + expect(carousel._isPaused).toBeFalse() }) }) @@ -1153,6 +1151,7 @@ describe('Carousel', () => { }) }) }) + describe('rtl function', () => { it('"_directionToOrder" and "_orderToDirection" must return the right results', () => { fixtureEl.innerHTML = '<div></div>' @@ -1175,7 +1174,7 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - expect(isRTL()).toEqual(true, 'rtl has to be true') + expect(isRTL()).toBeTrue() expect(carousel._directionToOrder('left')).toEqual('prev') expect(carousel._directionToOrder('prev')).toEqual('prev') @@ -1292,7 +1291,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() }) }) @@ -1313,7 +1312,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() expect(Carousel.getOrCreateInstance(div)).toBeInstanceOf(Carousel) }) @@ -1322,7 +1321,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() const carousel = Carousel.getOrCreateInstance(div, { interval: 1 }) @@ -1431,7 +1430,7 @@ describe('Carousel', () => { ' <div class="carousel-item">item 3</div>', ' </div>', ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></button>', - ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></div>', + ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></button>', '</div>' ].join('') @@ -1441,7 +1440,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) @@ -1454,8 +1453,8 @@ describe('Carousel', () => { ' <div id="item2" class="carousel-item">item 2</div>', ' <div class="carousel-item">item 3</div>', ' </div>', - ' <a class="carousel-control-prev" href="#myCarousel" role="button" data-bs-slide="prev"></button>', - ' <a id="next" class="carousel-control-next" href="#myCarousel" role="button" data-bs-slide="next"></div>', + ' <a class="carousel-control-prev" href="#myCarousel" role="button" data-bs-slide="prev"></a>', + ' <a id="next" class="carousel-control-next" href="#myCarousel" role="button" data-bs-slide="next"></a>', '</div>' ].join('') @@ -1465,7 +1464,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) @@ -1488,7 +1487,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) @@ -1521,8 +1520,8 @@ describe('Carousel', () => { ' <div id="item2" class="carousel-item">item 2</div>', ' <div class="carousel-item">item 3</div>', ' </div>', - ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></div>', - ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></div>', + ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></button>', + ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></button>', '</div>' ].join('') diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index 89d20a6d87..327a68449b 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -159,8 +159,8 @@ describe('Collapse', () => { })) collapseEl2.addEventListener('shown.bs.collapse', () => { - expect(collapseEl2.classList.contains('show')).toEqual(true) - expect(collapseEl1.classList.contains('show')).toEqual(false) + expect(collapseEl2).toHaveClass('show') + expect(collapseEl1).not.toHaveClass('show') done() }) @@ -212,7 +212,7 @@ describe('Collapse', () => { expect(collapseEl.style.height).toEqual('0px') }) collapseEl.addEventListener('shown.bs.collapse', () => { - expect(collapseEl.classList.contains('show')).toEqual(true) + expect(collapseEl).toHaveClass('show') expect(collapseEl.style.height).toEqual('') done() }) @@ -232,7 +232,7 @@ describe('Collapse', () => { expect(collapseEl.style.width).toEqual('0px') }) collapseEl.addEventListener('shown.bs.collapse', () => { - expect(collapseEl.classList.contains('show')).toEqual(true) + expect(collapseEl).toHaveClass('show') expect(collapseEl.style.width).toEqual('') done() }) @@ -257,8 +257,8 @@ describe('Collapse', () => { }) el1.addEventListener('shown.bs.collapse', () => { - expect(el1.classList.contains('show')).toEqual(true) - expect(el2.classList.contains('show')).toEqual(true) + expect(el1).toHaveClass('show') + expect(el2).toHaveClass('show') done() }) @@ -268,31 +268,31 @@ describe('Collapse', () => { it('should be able to handle toggling of other children siblings', done => { fixtureEl.innerHTML = [ '<div id="parentGroup" class="accordion">', - ' <div id="parentHeader" class="accordion-header">', - ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" role="button" class="accordion-toggle">Parent</button>', - ' </div>', - ' <div id="parentContent" class="accordion-collapse collapse" aria-labelledby="parentHeader" data-bs-parent="#parentGroup">', - ' <div class="accordion-body">', - ' <div id="childGroup" class="accordion">', - ' <div class="accordion-item">', - ' <div id="childHeader1" class="accordion-header">', - ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 1</button>', - ' </div>', - ' <div id="childContent1" class="accordion-collapse collapse" aria-labelledby="childHeader1" data-bs-parent="#childGroup">', - ' <div>content</div>', - ' </div>', - ' </div>', - ' <div class="accordion-item">', - ' <div id="childHeader2" class="accordion-header">', - ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 2</button>', - ' </div>', - ' <div id="childContent2" class="accordion-collapse collapse" aria-labelledby="childHeader2" data-bs-parent="#childGroup">', - ' <div>content</div>', - ' </div>', - ' </div>', - ' </div>', + ' <div id="parentHeader" class="accordion-header">', + ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" role="button" class="accordion-toggle">Parent</button>', + ' </div>', + ' <div id="parentContent" class="accordion-collapse collapse" aria-labelledby="parentHeader" data-bs-parent="#parentGroup">', + ' <div class="accordion-body">', + ' <div id="childGroup" class="accordion">', + ' <div class="accordion-item">', + ' <div id="childHeader1" class="accordion-header">', + ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 1</button>', + ' </div>', + ' <div id="childContent1" class="accordion-collapse collapse" aria-labelledby="childHeader1" data-bs-parent="#childGroup">', + ' <div>content</div>', + ' </div>', + ' </div>', + ' <div class="accordion-item">', + ' <div id="childHeader2" class="accordion-header">', + ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 2</button>', + ' </div>', + ' <div id="childContent2" class="accordion-collapse collapse" aria-labelledby="childHeader2" data-bs-parent="#childGroup">', + ' <div>content</div>', + ' </div>', + ' </div>', ' </div>', - ' </div>', + ' </div>', + ' </div>', '</div>' ].join('') @@ -307,46 +307,47 @@ describe('Collapse', () => { const childCollapseEl2 = el('#childContent2') parentCollapseEl.addEventListener('shown.bs.collapse', () => { - expect(parentCollapseEl.classList.contains('show')).toEqual(true) + expect(parentCollapseEl).toHaveClass('show') childBtn1.click() }) childCollapseEl1.addEventListener('shown.bs.collapse', () => { - expect(childCollapseEl1.classList.contains('show')).toEqual(true) + expect(childCollapseEl1).toHaveClass('show') childBtn2.click() }) childCollapseEl2.addEventListener('shown.bs.collapse', () => { - expect(childCollapseEl2.classList.contains('show')).toEqual(true) - expect(childCollapseEl1.classList.contains('show')).toEqual(false) + expect(childCollapseEl2).toHaveClass('show') + expect(childCollapseEl1).not.toHaveClass('show') done() }) parentBtn.click() }) + it('should not change tab tabpanels descendants on accordion', done => { fixtureEl.innerHTML = [ '<div class="accordion" id="accordionExample">', - ' <div class="accordion-item">', - ' <h2 class="accordion-header" id="headingOne">', - ' <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">', - ' Accordion Item #1', - ' </button>', - ' </h2>', - ' <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">', - ' <div class="accordion-body">', - ' <nav>', - ' <div class="nav nav-tabs" id="nav-tab" role="tablist">', - ' <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>', - ' <button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>', - ' </div>', - ' </nav>', - ' <div class="tab-content" id="nav-tabContent">', - ' <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">Home</div>', - ' <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">Profile</div>', - ' </div>', + ' <div class="accordion-item">', + ' <h2 class="accordion-header" id="headingOne">', + ' <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">', + ' Accordion Item #1', + ' </button>', + ' </h2>', + ' <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">', + ' <div class="accordion-body">', + ' <nav>', + ' <div class="nav nav-tabs" id="nav-tab" role="tablist">', + ' <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>', + ' <button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>', ' </div>', + ' </nav>', + ' <div class="tab-content" id="nav-tabContent">', + ' <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">Home</div>', + ' <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">Profile</div>', ' </div>', ' </div>', - ' </div>' + ' </div>', + ' </div>', + '</div>' ].join('') const el = fixtureEl.querySelector('#collapseOne') @@ -359,7 +360,7 @@ describe('Collapse', () => { }) el.addEventListener('shown.bs.collapse', () => { - expect(activeTabPane.classList.contains('show')).toEqual(true) + expect(activeTabPane).toHaveClass('show') times++ if (times === 2) { done() @@ -440,7 +441,7 @@ describe('Collapse', () => { }) collapseEl.addEventListener('hidden.bs.collapse', () => { - expect(collapseEl.classList.contains('show')).toEqual(false) + expect(collapseEl).not.toHaveClass('show') expect(collapseEl.style.height).toEqual('') done() }) @@ -489,7 +490,7 @@ describe('Collapse', () => { collapse.dispose() - expect(Collapse.getInstance(collapseEl)).toEqual(null) + expect(Collapse.getInstance(collapseEl)).toBeNull() }) }) @@ -508,8 +509,8 @@ describe('Collapse', () => { spyOn(Event.prototype, 'preventDefault').and.callThrough() triggerEl.addEventListener('click', event => { - expect(event.target.isEqualNode(nestedTriggerEl)).toEqual(true) - expect(event.delegateTarget.isEqualNode(triggerEl)).toEqual(true) + expect(event.target.isEqualNode(nestedTriggerEl)).toBeTrue() + expect(event.delegateTarget.isEqualNode(triggerEl)).toBeTrue() expect(Event.prototype.preventDefault).toHaveBeenCalled() done() }) @@ -530,9 +531,9 @@ describe('Collapse', () => { collapse2.addEventListener('shown.bs.collapse', () => { expect(trigger.getAttribute('aria-expanded')).toEqual('true') - expect(trigger.classList.contains('collapsed')).toEqual(false) - expect(collapse1.classList.contains('show')).toEqual(true) - expect(collapse1.classList.contains('show')).toEqual(true) + expect(trigger).not.toHaveClass('collapsed') + expect(collapse1).toHaveClass('show') + expect(collapse1).toHaveClass('show') done() }) @@ -552,9 +553,9 @@ describe('Collapse', () => { collapse2.addEventListener('hidden.bs.collapse', () => { expect(trigger.getAttribute('aria-expanded')).toEqual('false') - expect(trigger.classList.contains('collapsed')).toEqual(true) - expect(collapse1.classList.contains('show')).toEqual(false) - expect(collapse1.classList.contains('show')).toEqual(false) + expect(trigger).toHaveClass('collapsed') + expect(collapse1).not.toHaveClass('show') + expect(collapse1).not.toHaveClass('show') done() }) @@ -575,8 +576,8 @@ describe('Collapse', () => { collapseTest1.addEventListener('shown.bs.collapse', () => { expect(link1.getAttribute('aria-expanded')).toEqual('true') expect(link2.getAttribute('aria-expanded')).toEqual('true') - expect(link1.classList.contains('collapsed')).toEqual(false) - expect(link2.classList.contains('collapsed')).toEqual(false) + expect(link1).not.toHaveClass('collapsed') + expect(link2).not.toHaveClass('collapsed') done() }) @@ -597,8 +598,8 @@ describe('Collapse', () => { collapseTest1.addEventListener('hidden.bs.collapse', () => { expect(link1.getAttribute('aria-expanded')).toEqual('false') expect(link2.getAttribute('aria-expanded')).toEqual('false') - expect(link1.classList.contains('collapsed')).toEqual(true) - expect(link2.classList.contains('collapsed')).toEqual(true) + expect(link1).toHaveClass('collapsed') + expect(link2).toHaveClass('collapsed') done() }) @@ -625,12 +626,12 @@ describe('Collapse', () => { const collapseTwo = fixtureEl.querySelector('#collapseTwo') collapseOne.addEventListener('shown.bs.collapse', () => { - expect(collapseOne.classList.contains('show')).toEqual(true) - expect(collapseTwo.classList.contains('show')).toEqual(false) + expect(collapseOne).toHaveClass('show') + expect(collapseTwo).not.toHaveClass('show') collapseTwo.addEventListener('shown.bs.collapse', () => { - expect(collapseOne.classList.contains('show')).toEqual(false) - expect(collapseTwo.classList.contains('show')).toEqual(true) + expect(collapseOne).not.toHaveClass('show') + expect(collapseTwo).toHaveClass('show') done() }) @@ -650,8 +651,8 @@ describe('Collapse', () => { const collapseEl = fixtureEl.querySelector('#collapsediv1') collapseEl.addEventListener('shown.bs.collapse', () => { - expect(collapseEl.classList.contains('show')).toEqual(true) - expect(target.checked).toEqual(true) + expect(collapseEl).toHaveClass('show') + expect(target.checked).toBeTrue() done() }) @@ -684,21 +685,21 @@ describe('Collapse', () => { const collapseTwoEl = fixtureEl.querySelector('#collapseTwo') collapseOneEl.addEventListener('shown.bs.collapse', () => { - expect(collapseOneEl.classList.contains('show')).toEqual(true) - expect(triggerEl.classList.contains('collapsed')).toEqual(false) + expect(collapseOneEl).toHaveClass('show') + expect(triggerEl).not.toHaveClass('collapsed') expect(triggerEl.getAttribute('aria-expanded')).toEqual('true') - expect(collapseTwoEl.classList.contains('show')).toEqual(false) - expect(triggerTwoEl.classList.contains('collapsed')).toEqual(true) + expect(collapseTwoEl).not.toHaveClass('show') + expect(triggerTwoEl).toHaveClass('collapsed') expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('false') collapseTwoEl.addEventListener('shown.bs.collapse', () => { - expect(collapseOneEl.classList.contains('show')).toEqual(false) - expect(triggerEl.classList.contains('collapsed')).toEqual(true) + expect(collapseOneEl).not.toHaveClass('show') + expect(triggerEl).toHaveClass('collapsed') expect(triggerEl.getAttribute('aria-expanded')).toEqual('false') - expect(collapseTwoEl.classList.contains('show')).toEqual(true) - expect(triggerTwoEl.classList.contains('collapsed')).toEqual(false) + expect(collapseTwoEl).toHaveClass('show') + expect(triggerTwoEl).not.toHaveClass('collapsed') expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -733,21 +734,21 @@ describe('Collapse', () => { } function firstTest() { - expect(collapseOneOne.classList.contains('show')).toEqual(true) - expect(collapseOneTwo.classList.contains('show')).toEqual(true) + expect(collapseOneOne).toHaveClass('show') + expect(collapseOneTwo).toHaveClass('show') - expect(collapseTwoOne.classList.contains('show')).toEqual(false) - expect(collapseTwoTwo.classList.contains('show')).toEqual(false) + expect(collapseTwoOne).not.toHaveClass('show') + expect(collapseTwoTwo).not.toHaveClass('show') triggerTwo.click() } function secondTest() { - expect(collapseOneOne.classList.contains('show')).toEqual(false) - expect(collapseOneTwo.classList.contains('show')).toEqual(false) + expect(collapseOneOne).not.toHaveClass('show') + expect(collapseOneTwo).not.toHaveClass('show') - expect(collapseTwoOne.classList.contains('show')).toEqual(true) - expect(collapseTwoTwo.classList.contains('show')).toEqual(true) + expect(collapseTwoOne).toHaveClass('show') + expect(collapseTwoTwo).toHaveClass('show') done() } @@ -815,9 +816,9 @@ describe('Collapse', () => { const nestedCollapseOne = fixtureEl.querySelector('#nestedCollapseOne') function handlerCollapseOne() { - expect(collapseOne.classList.contains('show')).toEqual(true) - expect(collapseTwo.classList.contains('show')).toEqual(false) - expect(nestedCollapseOne.classList.contains('show')).toEqual(false) + expect(collapseOne).toHaveClass('show') + expect(collapseTwo).not.toHaveClass('show') + expect(nestedCollapseOne).not.toHaveClass('show') nestedCollapseOne.addEventListener('shown.bs.collapse', handlerNestedCollapseOne) nestedTrigger.click() @@ -825,14 +826,14 @@ describe('Collapse', () => { } function handlerNestedCollapseOne() { - expect(collapseOne.classList.contains('show')).toEqual(true) - expect(collapseTwo.classList.contains('show')).toEqual(false) - expect(nestedCollapseOne.classList.contains('show')).toEqual(true) + expect(collapseOne).toHaveClass('show') + expect(collapseTwo).not.toHaveClass('show') + expect(nestedCollapseOne).toHaveClass('show') collapseTwo.addEventListener('shown.bs.collapse', () => { - expect(collapseOne.classList.contains('show')).toEqual(false) - expect(collapseTwo.classList.contains('show')).toEqual(true) - expect(nestedCollapseOne.classList.contains('show')).toEqual(true) + expect(collapseOne).not.toHaveClass('show') + expect(collapseTwo).toHaveClass('show') + expect(nestedCollapseOne).toHaveClass('show') done() }) @@ -860,33 +861,33 @@ describe('Collapse', () => { const target2 = fixtureEl.querySelector('#test2') const target2Shown = () => { - expect(trigger1.classList.contains('collapsed')).toEqual(false) + expect(trigger1).not.toHaveClass('collapsed') expect(trigger1.getAttribute('aria-expanded')).toEqual('true') - expect(trigger2.classList.contains('collapsed')).toEqual(false) + expect(trigger2).not.toHaveClass('collapsed') expect(trigger2.getAttribute('aria-expanded')).toEqual('true') - expect(trigger3.classList.contains('collapsed')).toEqual(false) + expect(trigger3).not.toHaveClass('collapsed') expect(trigger3.getAttribute('aria-expanded')).toEqual('true') target2.addEventListener('hidden.bs.collapse', () => { - expect(trigger1.classList.contains('collapsed')).toEqual(false) + expect(trigger1).not.toHaveClass('collapsed') expect(trigger1.getAttribute('aria-expanded')).toEqual('true') - expect(trigger2.classList.contains('collapsed')).toEqual(true) + expect(trigger2).toHaveClass('collapsed') expect(trigger2.getAttribute('aria-expanded')).toEqual('false') - expect(trigger3.classList.contains('collapsed')).toEqual(false) + expect(trigger3).not.toHaveClass('collapsed') expect(trigger3.getAttribute('aria-expanded')).toEqual('true') target1.addEventListener('hidden.bs.collapse', () => { - expect(trigger1.classList.contains('collapsed')).toEqual(true) + expect(trigger1).toHaveClass('collapsed') expect(trigger1.getAttribute('aria-expanded')).toEqual('false') - expect(trigger2.classList.contains('collapsed')).toEqual(true) + expect(trigger2).toHaveClass('collapsed') expect(trigger2.getAttribute('aria-expanded')).toEqual('false') - expect(trigger3.classList.contains('collapsed')).toEqual(true) + expect(trigger3).toHaveClass('collapsed') expect(trigger3.getAttribute('aria-expanded')).toEqual('false') done() }) @@ -961,7 +962,7 @@ describe('Collapse', () => { const div = fixtureEl.querySelector('div') - expect(Collapse.getInstance(div)).toEqual(null) + expect(Collapse.getInstance(div)).toBeNull() }) }) @@ -982,7 +983,7 @@ describe('Collapse', () => { const div = fixtureEl.querySelector('div') - expect(Collapse.getInstance(div)).toEqual(null) + expect(Collapse.getInstance(div)).toBeNull() expect(Collapse.getOrCreateInstance(div)).toBeInstanceOf(Collapse) }) @@ -991,13 +992,13 @@ describe('Collapse', () => { const div = fixtureEl.querySelector('div') - expect(Collapse.getInstance(div)).toEqual(null) + expect(Collapse.getInstance(div)).toBeNull() const collapse = Collapse.getOrCreateInstance(div, { toggle: false }) expect(collapse).toBeInstanceOf(Collapse) - expect(collapse._config.toggle).toEqual(false) + expect(collapse._config.toggle).toBeFalse() }) it('should return the instance when exists without given configuration', () => { @@ -1015,7 +1016,7 @@ describe('Collapse', () => { expect(collapse).toBeInstanceOf(Collapse) expect(collapse2).toEqual(collapse) - expect(collapse2._config.toggle).toEqual(false) + expect(collapse2._config.toggle).toBeFalse() }) }) }) diff --git a/js/tests/unit/dom/data.spec.js b/js/tests/unit/dom/data.spec.js index 2560caff75..e898cbba21 100644 --- a/js/tests/unit/dom/data.spec.js +++ b/js/tests/unit/dom/data.spec.js @@ -50,7 +50,7 @@ describe('Data', () => { Data.set(div, TEST_KEY, data) - expect(Data.get(div, TEST_KEY)).toBe(data) + expect(Data.get(div, TEST_KEY)).toEqual(data) }) it('should overwrite data if something is already stored', () => { @@ -60,11 +60,12 @@ describe('Data', () => { Data.set(div, TEST_KEY, data) Data.set(div, TEST_KEY, copy) + // Using `toBe` since spread creates a shallow copy expect(Data.get(div, TEST_KEY)).not.toBe(data) expect(Data.get(div, TEST_KEY)).toBe(copy) }) - it('should do nothing when an element have nothing stored', () => { + it('should do nothing when an element has nothing stored', () => { Data.remove(div, TEST_KEY) expect().nothing() @@ -76,7 +77,7 @@ describe('Data', () => { Data.set(div, TEST_KEY, data) Data.remove(div, UNKNOWN_KEY) - expect(Data.get(div, TEST_KEY)).toBe(data) + expect(Data.get(div, TEST_KEY)).toEqual(data) }) it('should remove data for a given key', () => { @@ -99,7 +100,7 @@ describe('Data', () => { Data.set(div, UNKNOWN_KEY, copy) expect(console.error).toHaveBeenCalled() - expect(Data.get(div, UNKNOWN_KEY)).toBe(null) + expect(Data.get(div, UNKNOWN_KEY)).toBeNull() }) /* eslint-enable no-console */ }) diff --git a/js/tests/unit/dom/event-handler.spec.js b/js/tests/unit/dom/event-handler.spec.js index 19d63492b5..4772d892e8 100644 --- a/js/tests/unit/dom/event-handler.spec.js +++ b/js/tests/unit/dom/event-handler.spec.js @@ -105,10 +105,10 @@ describe('EventHandler', () => { EventHandler.on(outer, 'mouseleave', '.inner', delegateLeaveSpy) EventHandler.on(sibling, 'mouseenter', () => { - expect(enterSpy.calls.count()).toBe(2) - expect(leaveSpy.calls.count()).toBe(2) - expect(delegateEnterSpy.calls.count()).toBe(2) - expect(delegateLeaveSpy.calls.count()).toBe(2) + expect(enterSpy.calls.count()).toEqual(2) + expect(leaveSpy.calls.count()).toEqual(2) + expect(delegateEnterSpy.calls.count()).toEqual(2) + expect(delegateLeaveSpy.calls.count()).toEqual(2) done() }) @@ -133,10 +133,10 @@ describe('EventHandler', () => { moveMouse(inner, outer) setTimeout(() => { - expect(enterSpy.calls.count()).toBe(1) - expect(leaveSpy.calls.count()).toBe(1) - expect(delegateEnterSpy.calls.count()).toBe(1) - expect(delegateLeaveSpy.calls.count()).toBe(1) + expect(enterSpy.calls.count()).toEqual(1) + expect(leaveSpy.calls.count()).toEqual(1) + expect(delegateEnterSpy.calls.count()).toEqual(1) + expect(delegateLeaveSpy.calls.count()).toEqual(1) // from outer to inner to sibling (adjacent) moveMouse(outer, inner) diff --git a/js/tests/unit/dom/manipulator.spec.js b/js/tests/unit/dom/manipulator.spec.js index 61ffe74553..963ee5989f 100644 --- a/js/tests/unit/dom/manipulator.spec.js +++ b/js/tests/unit/dom/manipulator.spec.js @@ -96,10 +96,10 @@ describe('Manipulator', () => { const div = fixtureEl.querySelector('div') - expect(Manipulator.getDataAttribute(div, 'test')).toEqual(false) + expect(Manipulator.getDataAttribute(div, 'test')).toBeFalse() div.setAttribute('data-bs-test', 'true') - expect(Manipulator.getDataAttribute(div, 'test')).toEqual(true) + expect(Manipulator.getDataAttribute(div, 'test')).toBeTrue() div.setAttribute('data-bs-test', '1') expect(Manipulator.getDataAttribute(div, 'test')).toEqual(1) @@ -152,8 +152,8 @@ describe('Manipulator', () => { body.append(forceScrollBars) const scrollHandler = () => { - expect(window.pageYOffset).toBe(scrollY) - expect(window.pageXOffset).toBe(scrollX) + expect(window.pageYOffset).toEqual(scrollY) + expect(window.pageXOffset).toEqual(scrollX) const newOffset = Manipulator.offset(div) diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index 09c85a88ad..005e92704c 100644 --- a/js/tests/unit/dom/selector-engine.spec.js +++ b/js/tests/unit/dom/selector-engine.spec.js @@ -73,7 +73,7 @@ describe('SelectorEngine', () => { describe('parents', () => { it('should return parents', () => { - expect(SelectorEngine.parents(fixtureEl, 'body').length).toEqual(1) + expect(SelectorEngine.parents(fixtureEl, 'body')).toHaveSize(1) }) }) @@ -197,9 +197,7 @@ describe('SelectorEngine', () => { }) it('should return not return elements with negative tab index', () => { - fixtureEl.innerHTML = [ - '<button tabindex="-1">lorem</button>' - ].join('') + fixtureEl.innerHTML = '<button tabindex="-1">lorem</button>' const expectedElements = [] @@ -207,9 +205,7 @@ describe('SelectorEngine', () => { }) it('should return contenteditable elements', () => { - fixtureEl.innerHTML = [ - '<div contenteditable="true">lorem</div>' - ].join('') + fixtureEl.innerHTML = '<div contenteditable="true">lorem</div>' const expectedElements = [fixtureEl.querySelector('[contenteditable="true"]')] @@ -217,9 +213,7 @@ describe('SelectorEngine', () => { }) it('should not return disabled elements', () => { - fixtureEl.innerHTML = [ - '<button disabled="true">lorem</button>' - ].join('') + fixtureEl.innerHTML = '<button disabled="true">lorem</button>' const expectedElements = [] @@ -227,9 +221,7 @@ describe('SelectorEngine', () => { }) it('should not return invisible elements', () => { - fixtureEl.innerHTML = [ - '<button style="display:none;">lorem</button>' - ].join('') + fixtureEl.innerHTML = '<button style="display:none;">lorem</button>' const expectedElements = [] diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index f099e99908..037a6a5a93 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -130,7 +130,7 @@ describe('Dropdown', () => { it('should allow to pass config to Popper with `popperConfig` as a function', () => { fixtureEl.innerHTML = [ '<div class="dropdown">', - ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-placement="right" >Dropdown</button>', + ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-placement="right">Dropdown</button>', ' <div class="dropdown-menu">', ' <a class="dropdown-item" href="#">Secondary link</a>', ' </div>', @@ -165,7 +165,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -196,7 +196,7 @@ describe('Dropdown', () => { const dropdown1 = new Dropdown(btnDropdown1) firstDropdownEl.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown1.classList.contains('show')).toEqual(true) + expect(btnDropdown1).toHaveClass('show') spyOn(dropdown1._popper, 'destroy') btnDropdown2.click() }) @@ -228,7 +228,7 @@ describe('Dropdown', () => { spyOn(EventHandler, 'off') btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') expect(EventHandler.on).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) @@ -236,7 +236,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('hidden.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(false) + expect(btnDropdown).not.toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false') expect(EventHandler.off).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) @@ -261,7 +261,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -284,7 +284,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) dropupEl.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -307,7 +307,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) dropupEl.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -330,7 +330,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) dropendEl.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -353,7 +353,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) dropstartEl.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -377,7 +377,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -401,7 +401,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -425,7 +425,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() }) @@ -474,7 +474,7 @@ describe('Dropdown', () => { popperConfig: { onFirstUpdate() { expect(virtualElement.getBoundingClientRect).toHaveBeenCalled() - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() } @@ -606,7 +606,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') done() }) @@ -734,7 +734,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('hidden.bs.dropdown', () => { - expect(dropdownMenu.classList.contains('show')).toEqual(false) + expect(dropdownMenu).not.toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false') done() }) @@ -789,7 +789,7 @@ describe('Dropdown', () => { dropdown.hide() setTimeout(() => { - expect(dropdownMenu.classList.contains('show')).toEqual(true) + expect(dropdownMenu).toHaveClass('show') done() }, 10) }) @@ -815,7 +815,7 @@ describe('Dropdown', () => { dropdown.hide() setTimeout(() => { - expect(dropdownMenu.classList.contains('show')).toEqual(true) + expect(dropdownMenu).toHaveClass('show') done() }, 10) }) @@ -870,7 +870,7 @@ describe('Dropdown', () => { dropdown.hide() setTimeout(() => { - expect(dropdownMenu.classList.contains('show')).toEqual(true) + expect(dropdownMenu).toHaveClass('show') done() }) }) @@ -897,7 +897,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('hidden.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(false) + expect(btnDropdown).not.toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false') expect(EventHandler.off).toHaveBeenCalled() @@ -1032,9 +1032,9 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('shown.bs.dropdown', event => setTimeout(() => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') - expect(showEventTriggered).toEqual(true) + expect(showEventTriggered).toBeTrue() expect(event.relatedTarget).toEqual(btnDropdown) document.body.click() })) @@ -1044,9 +1044,9 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('hidden.bs.dropdown', event => { - expect(btnDropdown.classList.contains('show')).toEqual(false) + expect(btnDropdown).not.toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false') - expect(hideEventTriggered).toEqual(true) + expect(hideEventTriggered).toBeTrue() expect(event.relatedTarget).toEqual(btnDropdown) done() }) @@ -1054,7 +1054,7 @@ describe('Dropdown', () => { btnDropdown.click() }) - it('should not use Popper in navbar', done => { + it('should not use "static" Popper in navbar', done => { fixtureEl.innerHTML = [ '<nav class="navbar navbar-expand-md navbar-light bg-light">', ' <div class="dropdown">', @@ -1071,8 +1071,8 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(dropdown._popper).toBeNull() - expect(dropdownMenu.getAttribute('style')).toEqual(null, 'no inline style applied by Popper') + expect(dropdown._popper).not.toBeNull() + expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static') done() }) @@ -1120,7 +1120,7 @@ describe('Dropdown', () => { dropdown.show() }) - it('should manage bs attribute `data-bs-popper`="none" when dropdown is in navbar', done => { + it('should manage bs attribute `data-bs-popper`="static" when dropdown is in navbar', done => { fixtureEl.innerHTML = [ '<nav class="navbar navbar-expand-md navbar-light bg-light">', ' <div class="dropdown">', @@ -1137,7 +1137,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(btnDropdown) btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('none') + expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static') dropdown.hide() }) @@ -1164,7 +1164,7 @@ describe('Dropdown', () => { btnDropdown.addEventListener('shown.bs.dropdown', () => { // Popper adds this attribute when we use it - expect(dropdownMenu.getAttribute('data-popper-placement')).toEqual(null) + expect(dropdownMenu.getAttribute('data-popper-placement')).toBeNull() done() }) @@ -1211,7 +1211,7 @@ describe('Dropdown', () => { const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') btnDropdown.addEventListener('shown.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') const keyup = createEvent('keyup') @@ -1220,7 +1220,7 @@ describe('Dropdown', () => { }) btnDropdown.addEventListener('hidden.bs.dropdown', () => { - expect(btnDropdown.classList.contains('show')).toEqual(false) + expect(btnDropdown).not.toHaveClass('show') done() }) @@ -1248,29 +1248,29 @@ describe('Dropdown', () => { const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]') - expect(triggerDropdownList.length).toEqual(2) + expect(triggerDropdownList).toHaveSize(2) const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdownFirst.classList.contains('show')).toEqual(true) - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1) + expect(triggerDropdownFirst).toHaveClass('show') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1) document.body.click() }) triggerDropdownFirst.addEventListener('hidden.bs.dropdown', () => { - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0) + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0) triggerDropdownLast.click() }) triggerDropdownLast.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdownLast.classList.contains('show')).toEqual(true) - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1) + expect(triggerDropdownLast).toHaveClass('show') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1) document.body.click() }) triggerDropdownLast.addEventListener('hidden.bs.dropdown', () => { - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0) + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0) done() }) @@ -1296,13 +1296,13 @@ describe('Dropdown', () => { const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]') - expect(triggerDropdownList.length).toEqual(2) + expect(triggerDropdownList).toHaveSize(2) const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdownFirst.classList.contains('show')).toEqual(true, '"show" class added on click') - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1, 'only one dropdown is shown') + expect(triggerDropdownFirst).toHaveClass('show') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1) const keyup = createEvent('keyup') keyup.key = 'Tab' @@ -1311,13 +1311,13 @@ describe('Dropdown', () => { }) triggerDropdownFirst.addEventListener('hidden.bs.dropdown', () => { - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0, '"show" class removed') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0) triggerDropdownLast.click() }) triggerDropdownLast.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdownLast.classList.contains('show')).toEqual(true, '"show" class added on click') - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1, 'only one dropdown is shown') + expect(triggerDropdownLast).toHaveClass('show') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1) const keyup = createEvent('keyup') keyup.key = 'Tab' @@ -1326,7 +1326,7 @@ describe('Dropdown', () => { }) triggerDropdownLast.addEventListener('hidden.bs.dropdown', () => { - expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0, '"show" class removed') + expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0) done() }) @@ -1456,8 +1456,8 @@ describe('Dropdown', () => { triggerDropdown.dispatchEvent(keydown) triggerDropdown.dispatchEvent(keydown) - expect(document.activeElement.classList.contains('disabled')).toEqual(false, '.disabled not focused') - expect(document.activeElement.hasAttribute('disabled')).toEqual(false, ':disabled not focused') + expect(document.activeElement).not.toHaveClass('disabled') + expect(document.activeElement.hasAttribute('disabled')).toBeFalse() done() }) @@ -1490,9 +1490,9 @@ describe('Dropdown', () => { triggerDropdown.dispatchEvent(keydown) - expect(document.activeElement.classList.contains('d-none')).toEqual(false, '.d-none not focused') - expect(document.activeElement.style.display).not.toBe('none', '"display: none" not focused') - expect(document.activeElement.style.visibility).not.toBe('hidden', '"visibility: hidden" not focused') + expect(document.activeElement).not.toHaveClass('d-none') + expect(document.activeElement.style.display).not.toEqual('none') + expect(document.activeElement.style.visibility).not.toEqual('hidden') done() }) @@ -1603,12 +1603,12 @@ describe('Dropdown', () => { const input = fixtureEl.querySelector('input') input.addEventListener('click', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') + expect(triggerDropdown).toHaveClass('show') done() }) triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') + expect(triggerDropdown).toHaveClass('show') input.dispatchEvent(createEvent('click')) }) @@ -1629,12 +1629,12 @@ describe('Dropdown', () => { const textarea = fixtureEl.querySelector('textarea') textarea.addEventListener('click', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') + expect(triggerDropdown).toHaveClass('show') done() }) triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') + expect(triggerDropdown).toHaveClass('show') textarea.dispatchEvent(createEvent('click')) }) @@ -1684,57 +1684,38 @@ describe('Dropdown', () => { const input = fixtureEl.querySelector('input') const textarea = fixtureEl.querySelector('textarea') - const keydownSpace = createEvent('keydown') - keydownSpace.key = 'Space' - - const keydownArrowUp = createEvent('keydown') - keydownArrowUp.key = 'ArrowUp' - - const keydownArrowDown = createEvent('keydown') - keydownArrowDown.key = 'ArrowDown' + const test = (eventKey, elementToDispatch) => { + const event = createEvent('keydown') + event.key = eventKey + elementToDispatch.focus() + elementToDispatch.dispatchEvent(event) + expect(document.activeElement).toEqual(elementToDispatch, `${elementToDispatch.tagName} still focused`) + } const keydownEscape = createEvent('keydown') keydownEscape.key = 'Escape' triggerDropdown.addEventListener('shown.bs.dropdown', () => { // Key Space - input.focus() - input.dispatchEvent(keydownSpace) + test('Space', input) - expect(document.activeElement).toEqual(input, 'input still focused') - - textarea.focus() - textarea.dispatchEvent(keydownSpace) - - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + test('Space', textarea) // Key ArrowUp - input.focus() - input.dispatchEvent(keydownArrowUp) + test('ArrowUp', input) - expect(document.activeElement).toEqual(input, 'input still focused') - - textarea.focus() - textarea.dispatchEvent(keydownArrowUp) - - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + test('ArrowUp', textarea) // Key ArrowDown - input.focus() - input.dispatchEvent(keydownArrowDown) - - expect(document.activeElement).toEqual(input, 'input still focused') - - textarea.focus() - textarea.dispatchEvent(keydownArrowDown) + test('ArrowDown', input) - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + test('ArrowDown', textarea) // Key Escape input.focus() input.dispatchEvent(keydownEscape) - expect(triggerDropdown.classList.contains('show')).toEqual(false, 'dropdown menu is not shown') + expect(triggerDropdown).not.toHaveClass('show') done() }) @@ -1750,8 +1731,8 @@ describe('Dropdown', () => { ' <a class="dropdown-item" href="#">Secondary link</a>', ' <a class="dropdown-item" href="#">Something else here</a>', ' <div class="divider"></div>', - ' <a class="dropdown-item" href="#">Another link</a>', - ' </div>', + ' <a class="dropdown-item" href="#">Another link</a>', + ' </div>', ' </div>', '</div>' ] @@ -1771,7 +1752,7 @@ describe('Dropdown', () => { setTimeout(() => { expect(dropdown.toggle).not.toHaveBeenCalled() - expect(triggerDropdown.classList.contains('show')).toEqual(false) + expect(triggerDropdown).not.toHaveClass('show') done() }, 20) }) @@ -1783,7 +1764,7 @@ describe('Dropdown', () => { ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>', ' <div class="dropdown-menu">', ' <a class="dropdown-item" href="#">Some Item</a>', - ' </div>', + ' </div>', ' </div>', '</div>' ] @@ -1823,7 +1804,7 @@ describe('Dropdown', () => { const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) + expect(dropdownToggle).toHaveClass('show') dropdownMenu.click() }, 150) @@ -1833,7 +1814,7 @@ describe('Dropdown', () => { }) dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) + expect(dropdownToggle).not.toHaveClass('show') done() })) @@ -1854,7 +1835,7 @@ describe('Dropdown', () => { const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) + expect(dropdownToggle).toHaveClass('show') document.documentElement.click() }, 150) @@ -1864,7 +1845,7 @@ describe('Dropdown', () => { }) dropdownToggle.addEventListener('hidden.bs.dropdown', () => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) + expect(dropdownToggle).not.toHaveClass('show') done() }) @@ -1885,7 +1866,7 @@ describe('Dropdown', () => { const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') const expectDropdownToBeOpened = (shouldTriggerClick = true) => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) + expect(dropdownToggle).toHaveClass('show') if (shouldTriggerClick) { document.documentElement.click() } else { @@ -1963,7 +1944,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() }) }) @@ -1984,7 +1965,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() expect(Dropdown.getOrCreateInstance(div)).toBeInstanceOf(Dropdown) }) @@ -1993,7 +1974,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() const dropdown = Dropdown.getOrCreateInstance(div, { display: 'dynamic' }) @@ -2043,7 +2024,7 @@ describe('Dropdown', () => { keyup.key = 'ArrowUp' const handleArrowDown = () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true) + expect(triggerDropdown).toHaveClass('show') expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') setTimeout(() => { dropdown.hide() @@ -2053,7 +2034,7 @@ describe('Dropdown', () => { } const handleArrowUp = () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true) + expect(triggerDropdown).toHaveClass('show') expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') done() } @@ -2108,7 +2089,7 @@ describe('Dropdown', () => { const childElement = fixtureEl.querySelector('#childElement') btnDropdown.addEventListener('shown.bs.dropdown', () => setTimeout(() => { - expect(btnDropdown.classList.contains('show')).toEqual(true) + expect(btnDropdown).toHaveClass('show') expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() })) diff --git a/js/tests/unit/jquery.spec.js b/js/tests/unit/jquery.spec.js index 1c9258bd11..16781a3518 100644 --- a/js/tests/unit/jquery.spec.js +++ b/js/tests/unit/jquery.spec.js @@ -49,7 +49,7 @@ describe('jQuery', () => { $(fixtureEl).find('.alert') .one('closed.bs.alert', () => { - expect($(fixtureEl).find('.alert').length).toEqual(0) + expect($(fixtureEl).find('.alert')).toHaveSize(0) done() }) diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index 6e7b8fc88f..84a95c86ad 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -57,9 +57,7 @@ describe('Modal', () => { describe('toggle', () => { it('should call ScrollBarHelper to handle scrollBar on body', done => { - fixtureEl.innerHTML = [ - '<div class="modal"><div class="modal-dialog"></div></div>' - ].join('') + fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>' spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() @@ -234,12 +232,12 @@ describe('Modal', () => { modalEl.addEventListener('show.bs.modal', () => { setTimeout(() => { - expect(modal._isTransitioning).toEqual(true) + expect(modal._isTransitioning).toBeTrue() }) }) modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._isTransitioning).toEqual(false) + expect(modal._isTransitioning).toBeFalse() done() }) @@ -279,8 +277,7 @@ describe('Modal', () => { fixtureEl.innerHTML = [ '<button type="button" data-bs-dismiss="modal" data-bs-target="#modal1"></button>', '<div id="modal1" class="modal fade">', - ' <div class="modal-dialog">', - ' </div>', + ' <div class="modal-dialog"></div>', '</div>' ].join('') @@ -305,8 +302,7 @@ describe('Modal', () => { it('should set .modal\'s scroll top to 0', done => { fixtureEl.innerHTML = [ '<div class="modal fade">', - ' <div class="modal-dialog">', - ' </div>', + ' <div class="modal-dialog"></div>', '</div>' ].join('') @@ -432,6 +428,38 @@ describe('Modal', () => { modal.show() }) + it('should not close modal when clicking on modal-content', done => { + fixtureEl.innerHTML = [ + '<div class="modal">', + ' <div class="modal-dialog">', + ' <div class="modal-content"></div>', + ' </div>', + '</div>' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toEqual(true) + done() + }, 10) + } + + modalEl.addEventListener('shown.bs.modal', () => { + fixtureEl.querySelector('.modal-dialog').click() + fixtureEl.querySelector('.modal-content').click() + shownCallback() + }) + + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('Should not hide a modal') + }) + + modal.show() + }) + it('should not close modal when clicking outside of modal-content if backdrop = false', done => { fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>' @@ -442,7 +470,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -469,7 +497,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -497,7 +525,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(false) + expect(modal._isShown).toBeFalse() done() }, 10) } @@ -523,7 +551,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -687,7 +715,7 @@ describe('Modal', () => { const hideCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -994,7 +1022,7 @@ describe('Modal', () => { }) modalEl1.addEventListener('hidden.bs.modal', () => { expect(Modal.getInstance(modalEl2)).not.toBeNull() - expect(modalEl2.classList.contains('show')).toBeTrue() + expect(modalEl2).toHaveClass('show') done() }) modal1.show() @@ -1029,7 +1057,7 @@ describe('Modal', () => { const modal = Modal.getInstance(div) expect(modal).not.toBeNull() - expect(modal._config.keyboard).toBe(false) + expect(modal._config.keyboard).toBeFalse() }) it('should not re create a modal', () => { @@ -1129,7 +1157,7 @@ describe('Modal', () => { const div = fixtureEl.querySelector('div') - expect(Modal.getInstance(div)).toEqual(null) + expect(Modal.getInstance(div)).toBeNull() expect(Modal.getOrCreateInstance(div)).toBeInstanceOf(Modal) }) @@ -1138,13 +1166,13 @@ describe('Modal', () => { const div = fixtureEl.querySelector('div') - expect(Modal.getInstance(div)).toEqual(null) + expect(Modal.getInstance(div)).toBeNull() const modal = Modal.getOrCreateInstance(div, { backdrop: true }) expect(modal).toBeInstanceOf(Modal) - expect(modal._config.backdrop).toEqual(true) + expect(modal._config.backdrop).toBeTrue() }) it('should return the instance when exists without given configuration', () => { @@ -1162,7 +1190,7 @@ describe('Modal', () => { expect(modal).toBeInstanceOf(Modal) expect(modal2).toEqual(modal) - expect(modal2._config.backdrop).toEqual(true) + expect(modal2._config.backdrop).toBeTrue() }) }) }) diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index 3eda505202..f4b0b64828 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -55,7 +55,7 @@ describe('Offcanvas', () => { closeEl.click() - expect(offCanvas._config.keyboard).toBe(true) + expect(offCanvas._config.keyboard).toBeTrue() expect(offCanvas.hide).toHaveBeenCalled() }) @@ -101,47 +101,38 @@ describe('Offcanvas', () => { document.dispatchEvent(keyDownEsc) - expect(offCanvas._config.keyboard).toBe(false) + expect(offCanvas._config.keyboard).toBeFalse() expect(offCanvas.hide).not.toHaveBeenCalled() }) }) describe('config', () => { it('should have default values', () => { - fixtureEl.innerHTML = [ - '<div class="offcanvas">', - '</div>' - ].join('') + fixtureEl.innerHTML = '<div class="offcanvas"></div>' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - expect(offCanvas._config.backdrop).toEqual(true) - expect(offCanvas._backdrop._config.isVisible).toEqual(true) - expect(offCanvas._config.keyboard).toEqual(true) - expect(offCanvas._config.scroll).toEqual(false) + expect(offCanvas._config.backdrop).toBeTrue() + expect(offCanvas._backdrop._config.isVisible).toBeTrue() + expect(offCanvas._config.keyboard).toBeTrue() + expect(offCanvas._config.scroll).toBeFalse() }) it('should read data attributes and override default config', () => { - fixtureEl.innerHTML = [ - '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false">', - '</div>' - ].join('') + fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false"></div>' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - expect(offCanvas._config.backdrop).toEqual(false) - expect(offCanvas._backdrop._config.isVisible).toEqual(false) - expect(offCanvas._config.keyboard).toEqual(false) - expect(offCanvas._config.scroll).toEqual(true) + expect(offCanvas._config.backdrop).toBeFalse() + expect(offCanvas._backdrop._config.isVisible).toBeFalse() + expect(offCanvas._config.keyboard).toBeFalse() + expect(offCanvas._config.scroll).toBeTrue() }) it('given a config object must override data attributes', () => { - fixtureEl.innerHTML = [ - '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false">', - '</div>' - ].join('') + fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false"></div>' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl, { @@ -149,11 +140,12 @@ describe('Offcanvas', () => { keyboard: true, scroll: false }) - expect(offCanvas._config.backdrop).toEqual(true) - expect(offCanvas._config.keyboard).toEqual(true) - expect(offCanvas._config.scroll).toEqual(false) + expect(offCanvas._config.backdrop).toBeTrue() + expect(offCanvas._config.keyboard).toBeTrue() + expect(offCanvas._config.scroll).toBeFalse() }) }) + describe('options', () => { it('if scroll is enabled, should allow body to scroll while offcanvas is open', done => { fixtureEl.innerHTML = '<div class="offcanvas"></div>' @@ -204,7 +196,7 @@ describe('Offcanvas', () => { spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(typeof offCanvas._backdrop._config.clickCallback).toBe('function') + expect(offCanvas._backdrop._config.clickCallback).toEqual(jasmine.any(Function)) offCanvas._backdrop._getElement().dispatchEvent(clickEvent) }) @@ -256,7 +248,7 @@ describe('Offcanvas', () => { const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) offCanvas.show() - expect(offCanvasEl.classList.contains('show')).toBe(true) + expect(offCanvasEl).toHaveClass('show') spyOn(offCanvas, 'hide') @@ -274,7 +266,7 @@ describe('Offcanvas', () => { const offCanvas = new Offcanvas(offCanvasEl) offCanvas.show() - expect(offCanvasEl.classList.contains('show')).toBe(true) + expect(offCanvasEl).toHaveClass('show') spyOn(offCanvas._backdrop, 'show').and.callThrough() spyOn(EventHandler, 'trigger').and.callThrough() @@ -292,7 +284,7 @@ describe('Offcanvas', () => { spyOn(offCanvas._backdrop, 'show').and.callThrough() offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(true) + expect(offCanvasEl).toHaveClass('show') expect(offCanvas._backdrop.show).toHaveBeenCalled() done() }) @@ -384,7 +376,7 @@ describe('Offcanvas', () => { offCanvas.show() offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(false) + expect(offCanvasEl).not.toHaveClass('show') expect(offCanvas._backdrop.hide).toHaveBeenCalled() done() }) @@ -458,7 +450,7 @@ describe('Offcanvas', () => { expect(offCanvas._backdrop).toBeNull() expect(focustrap.deactivate).toHaveBeenCalled() expect(offCanvas._focustrap).toBeNull() - expect(Offcanvas.getInstance(offCanvasEl)).toEqual(null) + expect(Offcanvas.getInstance(offCanvasEl)).toBeNull() }) }) @@ -473,8 +465,8 @@ describe('Offcanvas', () => { const offCanvasEl = fixtureEl.querySelector('#offcanvasdiv1') offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(true) - expect(target.checked).toEqual(true) + expect(offCanvasEl).toHaveClass('show') + expect(target.checked).toBeTrue() done() }) @@ -498,7 +490,7 @@ describe('Offcanvas', () => { it('should call hide first, if another offcanvas is open', done => { fixtureEl.innerHTML = [ - '<button id="btn2" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2" ></button>', + '<button id="btn2" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2"></button>', '<div id="offcanvas1" class="offcanvas"></div>', '<div id="offcanvas2" class="offcanvas"></div>' ].join('') @@ -520,7 +512,7 @@ describe('Offcanvas', () => { it('should focus on trigger element after closing offcanvas', done => { fixtureEl.innerHTML = [ - '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas" ></button>', + '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>', '<div id="offcanvas" class="offcanvas"></div>' ].join('') @@ -544,7 +536,7 @@ describe('Offcanvas', () => { it('should not focus on trigger element after closing offcanvas, if it is not visible', done => { fixtureEl.innerHTML = [ - '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas" ></button>', + '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>', '<div id="offcanvas" class="offcanvas"></div>' ].join('') @@ -559,7 +551,7 @@ describe('Offcanvas', () => { }) offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { setTimeout(() => { - expect(isVisible(trigger)).toBe(false) + expect(isVisible(trigger)).toBeFalse() expect(trigger.focus).not.toHaveBeenCalled() done() }, 5) @@ -665,7 +657,7 @@ describe('Offcanvas', () => { const offcanvas = Offcanvas.getInstance(div) expect(offcanvas).not.toBeNull() - expect(offcanvas._config.scroll).toBe(true) + expect(offcanvas._config.scroll).toBeTrue() }) }) @@ -706,7 +698,7 @@ describe('Offcanvas', () => { const div = fixtureEl.querySelector('div') - expect(Offcanvas.getInstance(div)).toEqual(null) + expect(Offcanvas.getInstance(div)).toBeNull() expect(Offcanvas.getOrCreateInstance(div)).toBeInstanceOf(Offcanvas) }) @@ -715,13 +707,13 @@ describe('Offcanvas', () => { const div = fixtureEl.querySelector('div') - expect(Offcanvas.getInstance(div)).toEqual(null) + expect(Offcanvas.getInstance(div)).toBeNull() const offcanvas = Offcanvas.getOrCreateInstance(div, { scroll: true }) expect(offcanvas).toBeInstanceOf(Offcanvas) - expect(offcanvas._config.scroll).toEqual(true) + expect(offcanvas._config.scroll).toBeTrue() }) it('should return the instance when exists without given configuration', () => { @@ -739,7 +731,7 @@ describe('Offcanvas', () => { expect(offcanvas).toBeInstanceOf(Offcanvas) expect(offcanvas2).toEqual(offcanvas) - expect(offcanvas2._config.scroll).toEqual(true) + expect(offcanvas2._config.scroll).toBeTrue() }) }) }) diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index 4452a132d4..a2906ade71 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -155,6 +155,22 @@ describe('Popover', () => { popover.show() }) + it('"setContent" should keep the initial template', () => { + fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap" data-bs-custom-class="custom-class">BS twitter</a>' + + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) + + popover.setContent({ '.tooltip-inner': 'foo' }) + const tip = popover._getTipElement() + + expect(tip).toHaveClass('popover') + expect(tip).toHaveClass('bs-popover-auto') + expect(tip.querySelector('.popover-arrow')).not.toBeNull() + expect(tip.querySelector('.popover-header')).not.toBeNull() + expect(tip.querySelector('.popover-body')).not.toBeNull() + }) + it('should call setContent once', done => { fixtureEl.innerHTML = '<a href="#">BS twitter</a>' @@ -162,8 +178,8 @@ describe('Popover', () => { const popover = new Popover(popoverEl, { content: 'Popover content' }) - - const spy = spyOn(popover, 'setContent').and.callThrough() + expect(popover._templateFactory).toBeNull() + let spy = null let times = 1 popoverEl.addEventListener('hidden.bs.popover', () => { @@ -171,11 +187,12 @@ describe('Popover', () => { }) popoverEl.addEventListener('shown.bs.popover', () => { + spy = spy || spyOn(popover._templateFactory, 'constructor').and.callThrough() const popoverDisplayed = document.querySelector('.popover') expect(popoverDisplayed).not.toBeNull() expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content') - expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledTimes(0) if (times > 1) { done() } @@ -195,7 +212,7 @@ describe('Popover', () => { popoverEl.addEventListener('shown.bs.popover', () => { const tip = document.querySelector('.popover') expect(tip).not.toBeNull() - expect(tip.classList.contains('custom-class')).toBeTrue() + expect(tip).toHaveClass('custom-class') done() }) @@ -313,7 +330,7 @@ describe('Popover', () => { const popoverEl = fixtureEl.querySelector('a') - expect(Popover.getInstance(popoverEl)).toEqual(null) + expect(Popover.getInstance(popoverEl)).toBeNull() }) }) @@ -334,7 +351,7 @@ describe('Popover', () => { const div = fixtureEl.querySelector('div') - expect(Popover.getInstance(div)).toEqual(null) + expect(Popover.getInstance(div)).toBeNull() expect(Popover.getOrCreateInstance(div)).toBeInstanceOf(Popover) }) @@ -343,7 +360,7 @@ describe('Popover', () => { const div = fixtureEl.querySelector('div') - expect(Popover.getInstance(div)).toEqual(null) + expect(Popover.getInstance(div)).toBeNull() const popover = Popover.getOrCreateInstance(div, { placement: 'top' }) diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index f64b8f1dc9..5c044e697a 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -14,7 +14,7 @@ describe('ScrollSpy', () => { const scrollHeight = Math.ceil(contentEl.scrollTop + Manipulator.position(target).top) + paddingTop function listener() { - expect(element.classList.contains('active')).toEqual(true) + expect(element).toHaveClass('active') contentEl.removeEventListener('scroll', listener) expect(scrollSpy._process).toHaveBeenCalled() spy.calls.reset() @@ -73,8 +73,8 @@ describe('ScrollSpy', () => { ' </ul>', '</nav>', '<div id="content" style="height: 200px; overflow-y: auto;">', - ' <div id="two" style="height: 300px;"></div>', - ' <div id="three" style="height: 10px;"></div>', + ' <div id="two" style="height: 300px;"></div>', + ' <div id="three" style="height: 10px;"></div>', '</div>' ].join('') @@ -82,7 +82,7 @@ describe('ScrollSpy', () => { target: '#navigation' }) - expect(scrollSpy._targets.length).toEqual(2) + expect(scrollSpy._targets).toHaveSize(2) }) it('should only switch "active" class on current target', done => { @@ -120,7 +120,7 @@ describe('ScrollSpy', () => { spyOn(scrollSpy, '_process').and.callThrough() scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl.classList.contains('active')).toEqual(true) + expect(rootEl).toHaveClass('active') expect(scrollSpy._process).toHaveBeenCalled() done() }) @@ -163,7 +163,7 @@ describe('ScrollSpy', () => { spyOn(scrollSpy, '_process').and.callThrough() scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl.classList.contains('active')).toEqual(true) + expect(rootEl).toHaveClass('active') expect(scrollSpy._process).toHaveBeenCalled() done() }) @@ -175,16 +175,16 @@ describe('ScrollSpy', () => { fixtureEl.innerHTML = [ '<div id="header" style="height: 500px;"></div>', '<nav id="navigation" class="navbar">', - ' <ul class="navbar-nav">', - ' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>', - ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>', - ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>', - ' </ul>', + ' <ul class="navbar-nav">', + ' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>', + ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>', + ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>', + ' </ul>', '</nav>', '<div id="content" style="height: 200px; overflow-y: auto;">', - ' <div id="one" style="height: 500px;"></div>', - ' <div id="two" style="height: 300px;"></div>', - ' <div id="three" style="height: 10px;"></div>', + ' <div id="one" style="height: 500px;"></div>', + ' <div id="two" style="height: 300px;"></div>', + ' <div id="three" style="height: 10px;"></div>', '</div>' ].join('') @@ -197,9 +197,9 @@ describe('ScrollSpy', () => { spyOn(scrollSpy, '_process').and.callThrough() contentEl.addEventListener('scroll', () => { - expect(fixtureEl.querySelector('#one-link').classList.contains('active')).toEqual(false) - expect(fixtureEl.querySelector('#two-link').classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('#three-link').classList.contains('active')).toEqual(false) + expect(fixtureEl.querySelector('#one-link')).not.toHaveClass('active') + expect(fixtureEl.querySelector('#two-link')).toHaveClass('active') + expect(fixtureEl.querySelector('#three-link')).not.toHaveClass('active') expect(scrollSpy._process).toHaveBeenCalled() done() }) @@ -361,7 +361,7 @@ describe('ScrollSpy', () => { expect(spy).toHaveBeenCalled() spy.calls.reset() if (firstTime) { - expect(fixtureEl.querySelectorAll('.active').length).toEqual(1) + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) expect(active.getAttribute('id')).toEqual('two-link') firstTime = false contentEl.scrollTop = 0 @@ -409,12 +409,12 @@ describe('ScrollSpy', () => { expect(spy).toHaveBeenCalled() spy.calls.reset() if (firstTime) { - expect(fixtureEl.querySelectorAll('.active').length).toEqual(1) + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) expect(active.getAttribute('id')).toEqual('two-link') firstTime = false contentEl.scrollTop = negativeHeight } else { - expect(fixtureEl.querySelectorAll('.active').length).toEqual(1) + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) expect(active.getAttribute('id')).toEqual('one-link') done() } @@ -602,7 +602,7 @@ describe('ScrollSpy', () => { const scrollspy = ScrollSpy.getInstance(div) expect(scrollspy).not.toBeNull() - expect(scrollspy._config.offset).toBe(15) + expect(scrollspy._config.offset).toEqual(15) }) it('should not re create a scrollspy', () => { @@ -663,7 +663,7 @@ describe('ScrollSpy', () => { }) it('should return null if there is no instance', () => { - expect(ScrollSpy.getInstance(fixtureEl)).toEqual(null) + expect(ScrollSpy.getInstance(fixtureEl)).toBeNull() }) }) @@ -684,7 +684,7 @@ describe('ScrollSpy', () => { const div = fixtureEl.querySelector('div') - expect(ScrollSpy.getInstance(div)).toEqual(null) + expect(ScrollSpy.getInstance(div)).toBeNull() expect(ScrollSpy.getOrCreateInstance(div)).toBeInstanceOf(ScrollSpy) }) @@ -693,7 +693,7 @@ describe('ScrollSpy', () => { const div = fixtureEl.querySelector('div') - expect(ScrollSpy.getInstance(div)).toEqual(null) + expect(ScrollSpy.getInstance(div)).toBeNull() const scrollspy = ScrollSpy.getOrCreateInstance(div, { offset: 1 }) diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index 05f9db2ec1..bafa085526 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -21,8 +21,12 @@ describe('Tab', () => { describe('constructor', () => { it('should take care of element either passed as a CSS selector or DOM element', () => { fixtureEl.innerHTML = [ - '<ul class="nav"><li><a href="#home" role="tab">Home</a></li></ul>', - '<ul><li id="home"></li></ul>' + '<ul class="nav">', + ' <li><a href="#home" role="tab">Home</a></li>', + '</ul>', + '<ul>', + ' <li id="home"></li>', + '</ul>' ].join('') const tabEl = fixtureEl.querySelector('[href="#home"]') @@ -51,7 +55,7 @@ describe('Tab', () => { const tab = new Tab(profileTriggerEl) profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') done() }) @@ -75,7 +79,7 @@ describe('Tab', () => { const tab = new Tab(profileTriggerEl) profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') done() }) @@ -99,7 +103,7 @@ describe('Tab', () => { const tab = new Tab(profileTriggerEl) profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') done() }) @@ -110,16 +114,19 @@ describe('Tab', () => { fixtureEl.innerHTML = [ '<nav class="nav">', ' <button type="button" data-bs-target="#home" role="tab">Home</button>', - ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</a>', + ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>', '</nav>', - '<div><div id="home" role="tabpanel"></div><div id="profile" role="tabpanel"></div></div>' + '<div>', + ' <div id="home" role="tabpanel"></div>', + ' <div id="profile" role="tabpanel"></div>', + '</div>' ].join('') const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') const tab = new Tab(profileTriggerEl) profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') done() }) @@ -132,14 +139,17 @@ describe('Tab', () => { ' <button type="button" data-bs-target="#home" role="tab">Home</button>', ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>', '</div>', - '<div><div id="home" role="tabpanel"></div><div id="profile" role="tabpanel"></div></div>' + '<div>', + ' <div id="home" role="tabpanel"></div>', + ' <div id="profile" role="tabpanel"></div>', + '</div>' ].join('') const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') const tab = new Tab(profileTriggerEl) profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') done() }) @@ -248,7 +258,7 @@ describe('Tab', () => { }) triggerList[0].addEventListener('hidden.bs.tab', ev => { - expect(hideCalled).toEqual(true) + expect(hideCalled).toBeTrue() expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') done() }) @@ -321,7 +331,7 @@ describe('Tab', () => { const secondNavTab = new Tab(secondNavEl) secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.nav-tab').length).toEqual(2) + expect(fixtureEl.querySelectorAll('.nav-tab')).toHaveSize(2) done() }) @@ -417,7 +427,7 @@ describe('Tab', () => { describe('getInstance', () => { it('should return null if there is no instance', () => { - expect(Tab.getInstance(fixtureEl)).toEqual(null) + expect(Tab.getInstance(fixtureEl)).toBeNull() }) it('should return this instance', () => { @@ -448,7 +458,7 @@ describe('Tab', () => { const div = fixtureEl.querySelector('div') - expect(Tab.getInstance(div)).toEqual(null) + expect(Tab.getInstance(div)).toBeNull() expect(Tab.getOrCreateInstance(div)).toBeInstanceOf(Tab) }) }) @@ -469,8 +479,8 @@ describe('Tab', () => { const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') secondTabTrigger.addEventListener('shown.bs.tab', () => { - expect(secondTabTrigger.classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true) + expect(secondTabTrigger).toHaveClass('active') + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') done() }) @@ -495,9 +505,9 @@ describe('Tab', () => { const firstLiLinkEl = fixtureEl.querySelector('li:first-child a') firstLiLinkEl.click() - expect(firstLiLinkEl.classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('li:last-child a').classList.contains('active')).toEqual(false) - expect(fixtureEl.querySelector('li:last-child .dropdown-menu a:first-child').classList.contains('active')).toEqual(false) + 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', () => { @@ -529,10 +539,10 @@ describe('Tab', () => { const firstDropItem = fixtureEl.querySelector('#nav1 .dropdown-item') firstDropItem.click() - expect(firstDropItem.classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('#nav1 .dropdown-toggle').classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('#nav2 .dropdown-toggle').classList.contains('active')).toEqual(false) - expect(fixtureEl.querySelector('#nav2 .dropdown-item').classList.contains('active')).toEqual(false) + 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', () => { @@ -553,8 +563,8 @@ describe('Tab', () => { const firstDropItem = fixtureEl.querySelector('.dropdown-item') firstDropItem.click() - expect(firstDropItem.classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('.nav-link').classList.contains('active')).toEqual(false) + expect(firstDropItem).toHaveClass('active') + expect(fixtureEl.querySelector('.nav-link')).not.toHaveClass('active') }) it('should handle nested tabs', done => { @@ -585,12 +595,12 @@ describe('Tab', () => { const xTab1El = fixtureEl.querySelector('#x-tab1') tabNested2El.addEventListener('shown.bs.tab', () => { - expect(xTab1El.classList.contains('active')).toEqual(true) + expect(xTab1El).toHaveClass('active') done() }) tab1El.addEventListener('shown.bs.tab', () => { - expect(xTab1El.classList.contains('active')).toEqual(true) + expect(xTab1El).toHaveClass('active') tabNested2El.click() }) @@ -615,15 +625,15 @@ describe('Tab', () => { const tabHomeEl = fixtureEl.querySelector('#home') triggerTabProfileEl.addEventListener('shown.bs.tab', () => { - expect(tabProfileEl.classList.contains('fade')).toEqual(true) - expect(tabProfileEl.classList.contains('show')).toEqual(true) + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).toHaveClass('show') triggerTabHomeEl.addEventListener('shown.bs.tab', () => { - expect(tabProfileEl.classList.contains('fade')).toEqual(true) - expect(tabProfileEl.classList.contains('show')).toEqual(false) + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).not.toHaveClass('show') - expect(tabHomeEl.classList.contains('fade')).toEqual(true) - expect(tabHomeEl.classList.contains('show')).toEqual(true) + expect(tabHomeEl).toHaveClass('fade') + expect(tabHomeEl).toHaveClass('show') done() }) @@ -653,7 +663,7 @@ describe('Tab', () => { const secondNavEl = fixtureEl.querySelector('#secondNav') secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.show').length).toEqual(0) + expect(fixtureEl.querySelectorAll('.show')).toHaveSize(0) done() }) @@ -679,7 +689,7 @@ describe('Tab', () => { const secondNavEl = fixtureEl.querySelector('#secondNav') secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.show').length).toEqual(1) + expect(fixtureEl.querySelectorAll('.show')).toHaveSize(1) done() }) @@ -698,7 +708,7 @@ describe('Tab', () => { spyOn(Event.prototype, 'preventDefault').and.callThrough() tabEl.addEventListener('shown.bs.tab', () => { - expect(tabEl.classList.contains('active')).toEqual(true) + expect(tabEl).toHaveClass('active') expect(Event.prototype.preventDefault).toHaveBeenCalled() done() }) diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index 4b84bf2c5c..c4ea43808c 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -51,7 +51,7 @@ describe('Toast', () => { }) toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl.classList.contains('show')).toEqual(true) + expect(toastEl).toHaveClass('show') done() }) @@ -69,7 +69,7 @@ describe('Toast', () => { const toast = new Toast(toastEl) toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl.classList.contains('show')).toEqual(true) + expect(toastEl).toHaveClass('show') const button = toastEl.querySelector('.btn-close') @@ -77,7 +77,7 @@ describe('Toast', () => { }) toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl.classList.contains('show')).toEqual(false) + expect(toastEl).not.toHaveClass('show') done() }) @@ -124,7 +124,7 @@ describe('Toast', () => { const toast = new Toast(toastEl) toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl.classList.contains('show')).toEqual(false) + expect(toastEl).not.toHaveClass('show') done() }) @@ -144,7 +144,7 @@ describe('Toast', () => { const toast = new Toast(toastEl) toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl.classList.contains('fade')).toEqual(false) + expect(toastEl).not.toHaveClass('fade') done() }) @@ -165,7 +165,7 @@ describe('Toast', () => { const assertDone = () => { setTimeout(() => { - expect(toastEl.classList.contains('show')).toEqual(false) + expect(toastEl).not.toHaveClass('show') done() }, 20) } @@ -393,7 +393,7 @@ describe('Toast', () => { ' <div class="toast-body">', ' a simple toast', ' </div>', - ' </div>' + '</div>' ].join('') const toastEl = fixtureEl.querySelector('.toast') @@ -404,7 +404,7 @@ describe('Toast', () => { }) toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl.classList.contains('show')).toEqual(false) + expect(toastEl).not.toHaveClass('show') done() }) @@ -438,7 +438,7 @@ describe('Toast', () => { const assertDone = () => { setTimeout(() => { - expect(toastEl.classList.contains('show')).toEqual(true) + expect(toastEl).toHaveClass('show') done() }, 20) } @@ -487,13 +487,13 @@ describe('Toast', () => { const toastEl = fixtureEl.querySelector('div') const toast = new Toast(toastEl) const expected = () => { - expect(toastEl.classList.contains('show')).toEqual(true) + expect(toastEl).toHaveClass('show') expect(Toast.getInstance(toastEl)).not.toBeNull() toast.dispose() expect(Toast.getInstance(toastEl)).toBeNull() - expect(toastEl.classList.contains('show')).toEqual(false) + expect(toastEl).not.toHaveClass('show') done() } @@ -582,7 +582,7 @@ describe('Toast', () => { const div = fixtureEl.querySelector('div') - expect(Toast.getInstance(div)).toEqual(null) + expect(Toast.getInstance(div)).toBeNull() }) }) @@ -603,7 +603,7 @@ describe('Toast', () => { const div = fixtureEl.querySelector('div') - expect(Toast.getInstance(div)).toEqual(null) + expect(Toast.getInstance(div)).toBeNull() expect(Toast.getOrCreateInstance(div)).toBeInstanceOf(Toast) }) @@ -612,7 +612,7 @@ describe('Toast', () => { const div = fixtureEl.querySelector('div') - expect(Toast.getInstance(div)).toEqual(null) + expect(Toast.getInstance(div)).toBeNull() const toast = Toast.getOrCreateInstance(div, { delay: 1 }) diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 0cca4acff8..9054c0f642 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -78,7 +78,7 @@ describe('Tooltip', () => { const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip._config.sanitize).toEqual(true) + expect(tooltip._config.sanitize).toBeTrue() }) it('should convert title and content to string if numbers', () => { @@ -137,7 +137,7 @@ describe('Tooltip', () => { const offset = tooltip._getOffset() - expect(typeof offset).toEqual('function') + expect(offset).toEqual(jasmine.any(Function)) tooltip.show() }) @@ -180,6 +180,15 @@ describe('Tooltip', () => { expect(getPopperConfig).toHaveBeenCalled() expect(popperConfig.placement).toEqual('left') }) + + it('should use original title, if not "data-bs-title" is given', () => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + expect(tooltip._config.title).toEqual('Another tooltip') + }) }) describe('enable', () => { @@ -229,11 +238,11 @@ describe('Tooltip', () => { const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip._isEnabled).toEqual(true) + expect(tooltip._isEnabled).toBeTrue() tooltip.toggleEnabled() - expect(tooltip._isEnabled).toEqual(false) + expect(tooltip._isEnabled).toBeFalse() }) }) @@ -354,7 +363,7 @@ describe('Tooltip', () => { tooltip.dispose() - expect(Tooltip.getInstance(tooltipEl)).toEqual(null) + expect(Tooltip.getInstance(tooltipEl)).toBeNull() expect(removeEventSpy.calls.allArgs()).toEqual(expectedArgs) }) @@ -369,8 +378,8 @@ describe('Tooltip', () => { }) tooltipEl.addEventListener('hidden.bs.tooltip', () => { tooltip.dispose() - expect(tooltip.tip).toEqual(null) - expect(Tooltip.getInstance(tooltipEl)).toEqual(null) + expect(tooltip.tip).toBeNull() + expect(Tooltip.getInstance(tooltipEl)).toBeNull() done() }) @@ -415,14 +424,15 @@ describe('Tooltip', () => { tooltip.show() }) - it('should show a tooltip when hovering a children element', done => { - fixtureEl.innerHTML = - '<a href="#" rel="tooltip" title="Another tooltip">' + - '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100">' + - '<rect width="100%" fill="#563d7c"/>' + - '<circle cx="50" cy="50" r="30" fill="#fff"/>' + - '</svg>' + + it('should show a tooltip when hovering a child element', done => { + fixtureEl.innerHTML = [ + '<a href="#" rel="tooltip" title="Another tooltip">', + ' <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100">', + ' <rect width="100%" fill="#563d7c"/>', + ' <circle cx="50" cy="50" r="30" fill="#fff"/>', + ' </svg>', '</a>' + ].join('') const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -465,13 +475,12 @@ describe('Tooltip', () => { }) tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-bottom')).toEqual(true) + expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') }) tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tooltipShown = document.querySelector('.tooltip') - - expect(tooltipShown.classList.contains('bs-tooltip-bottom')).toEqual(true) + expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') + expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('bottom') done() }) @@ -586,7 +595,7 @@ describe('Tooltip', () => { const tip = document.querySelector('.tooltip') expect(tip).not.toBeNull() - expect(tip.classList.contains('fade')).toEqual(false) + expect(tip).not.toHaveClass('fade') done() }) @@ -670,7 +679,7 @@ describe('Tooltip', () => { setTimeout(() => { expect(tooltip.show).toHaveBeenCalled() - expect(document.querySelectorAll('.tooltip').length).toEqual(0) + expect(document.querySelectorAll('.tooltip')).toHaveSize(0) done() }, 200) @@ -689,19 +698,20 @@ describe('Tooltip', () => { }) setTimeout(() => { - expect(tooltip.getTipElement().classList.contains('show')).toEqual(true) + expect(tooltip._getTipElement()).toHaveClass('show') tooltipEl.dispatchEvent(createEvent('mouseout')) setTimeout(() => { - expect(tooltip.getTipElement().classList.contains('show')).toEqual(true) + expect(tooltip._getTipElement()).toHaveClass('show') tooltipEl.dispatchEvent(createEvent('mouseover')) }, 100) setTimeout(() => { - expect(tooltip.getTipElement().classList.contains('show')).toEqual(true) + expect(tooltip._getTipElement()).toHaveClass('show') + expect(document.querySelectorAll('.tooltip')).toHaveSize(1) done() }, 200) - }, 0) + }, 10) tooltipEl.dispatchEvent(createEvent('mouseover')) }) @@ -751,20 +761,20 @@ describe('Tooltip', () => { setTimeout(() => { expect(tooltip._popper).not.toBeNull() - expect(tooltip.getTipElement().getAttribute('data-popper-placement')).toBe('top') + expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('top') tooltipEl.dispatchEvent(createEvent('mouseout')) setTimeout(() => { - expect(tooltip.getTipElement().classList.contains('show')).toEqual(false) + expect(tooltip._getTipElement()).not.toHaveClass('show') tooltipEl.dispatchEvent(createEvent('mouseover')) }, 100) setTimeout(() => { expect(tooltip._popper).not.toBeNull() - expect(tooltip.getTipElement().getAttribute('data-popper-placement')).toBe('top') + expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('top') done() }, 200) - }, 0) + }, 10) tooltipEl.dispatchEvent(createEvent('mouseover')) }) @@ -809,7 +819,7 @@ describe('Tooltip', () => { tooltipEl.addEventListener('shown.bs.tooltip', () => { const tip = document.querySelector('.tooltip') expect(tip).not.toBeNull() - expect(tip.classList.contains('custom-class')).toBeTrue() + expect(tip).toHaveClass('custom-class') done() }) @@ -827,8 +837,8 @@ describe('Tooltip', () => { tooltipEl.addEventListener('shown.bs.tooltip', () => { const tip = document.querySelector('.tooltip') expect(tip).not.toBeNull() - expect(tip.classList.contains('custom-class')).toBeTrue() - expect(tip.classList.contains('custom-class-2')).toBeTrue() + expect(tip).toHaveClass('custom-class') + expect(tip).toHaveClass('custom-class-2') done() }) @@ -848,12 +858,25 @@ describe('Tooltip', () => { const tip = document.querySelector('.tooltip') expect(tip).not.toBeNull() expect(spy).toHaveBeenCalled() - expect(tip.classList.contains('custom-class')).toBeTrue() + expect(tip).toHaveClass('custom-class') done() }) tooltip.show() }) + + it('should remove `title` attribute if exists', done => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(tooltipEl.getAttribute('title')).toBeNull() + done() + }) + tooltip.show() + }) }) describe('hide', () => { @@ -985,14 +1008,14 @@ describe('Tooltip', () => { }) }) - describe('isWithContent', () => { + describe('_isWithContent', () => { it('should return true if there is content', () => { fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip.isWithContent()).toEqual(true) + expect(tooltip._isWithContent()).toBeTrue() }) it('should return false if there is no content', () => { @@ -1001,11 +1024,11 @@ describe('Tooltip', () => { const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip.isWithContent()).toEqual(false) + expect(tooltip._isWithContent()).toBeFalse() }) }) - describe('getTipElement', () => { + describe('_getTipElement', () => { it('should create the tip element and return it', () => { fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' @@ -1014,7 +1037,7 @@ describe('Tooltip', () => { spyOn(document, 'createElement').and.callThrough() - expect(tooltip.getTipElement()).toBeDefined() + expect(tooltip._getTipElement()).toBeDefined() expect(document.createElement).toHaveBeenCalled() }) @@ -1026,12 +1049,12 @@ describe('Tooltip', () => { const spy = spyOn(document, 'createElement').and.callThrough() - expect(tooltip.getTipElement()).toBeDefined() + expect(tooltip._getTipElement()).toBeDefined() expect(spy).toHaveBeenCalled() spy.calls.reset() - expect(tooltip.getTipElement()).toBeDefined() + expect(tooltip._getTipElement()).toBeDefined() expect(spy).not.toHaveBeenCalled() }) }) @@ -1041,84 +1064,78 @@ describe('Tooltip', () => { fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltip = new Tooltip(tooltipEl, { animation: false }) - const tip = tooltip.getTipElement() + const tip = tooltip._getTipElement() tooltip.setContent(tip) - expect(tip.classList.contains('show')).toEqual(false) - expect(tip.classList.contains('fade')).toEqual(false) + expect(tip).not.toHaveClass('show') + expect(tip).not.toHaveClass('fade') expect(tip.querySelector('.tooltip-inner').textContent).toEqual('Another tooltip') }) - }) - describe('updateAttachment', () => { - it('should use end class name when right placement specified', done => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + it('should re-show tip if it was already shown', () => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: 'right' - }) + const tooltip = new Tooltip(tooltipEl) + tooltip.show() + const tip = () => tooltip._getTipElement() - tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-end')).toEqual(true) - done() - }) + expect(tip()).toHaveClass('show') + tooltip.setContent({ '.tooltip-inner': 'foo' }) - tooltip.show() + expect(tip()).toHaveClass('show') + expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo') }) - it('should use start class name when left placement specified', done => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + it('should keep tip hidden, if it was already hidden before', () => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: 'left' - }) + const tooltip = new Tooltip(tooltipEl) + const tip = () => tooltip._getTipElement() - tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-start')).toEqual(true) - done() - }) + expect(tip()).not.toHaveClass('show') + tooltip.setContent({ '.tooltip-inner': 'foo' }) - tooltip.show() + expect(tip()).not.toHaveClass('show') + expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo') }) - }) - describe('setElementContent', () => { - it('should do nothing if the element is null', () => { + it('"setContent" should keep the initial template', () => { fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - tooltip.setElementContent(null, null) - expect().nothing() + tooltip.setContent({ '.tooltip-inner': 'foo' }) + const tip = tooltip._getTipElement() + + expect(tip).toHaveClass('tooltip') + expect(tip).toHaveClass('bs-tooltip-auto') + expect(tip.querySelector('.tooltip-arrow')).not.toBeNull() + expect(tip.querySelector('.tooltip-inner')).not.toBeNull() }) + }) - it('should add the content as a child of the element', () => { - fixtureEl.innerHTML = [ - '<a href="#" rel="tooltip" title="Another tooltip">', - '<div id="childContent"></div>' - ].join('') + describe('setContent', () => { + it('should do nothing if the element is null', () => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' const tooltipEl = fixtureEl.querySelector('a') - const childContent = fixtureEl.querySelector('div') - const tooltip = new Tooltip(tooltipEl, { - html: true - }) - - tooltip.setElementContent(tooltip.getTipElement(), childContent) + const tooltip = new Tooltip(tooltipEl) - expect(childContent.parentNode).toEqual(tooltip.getTipElement()) + tooltip.setContent({ '.tooltip': null }) + expect().nothing() }) it('should do nothing if the content is a child of the element', () => { fixtureEl.innerHTML = [ '<a href="#" rel="tooltip" title="Another tooltip">', - '<div id="childContent"></div>' + ' <div id="childContent"></div>', + '</a>' ].join('') const tooltipEl = fixtureEl.querySelector('a') @@ -1127,8 +1144,8 @@ describe('Tooltip', () => { html: true }) - tooltip.getTipElement().append(childContent) - tooltip.setElementContent(tooltip.getTipElement(), childContent) + tooltip._getTipElement().append(childContent) + tooltip.setContent({ '.tooltip': childContent }) expect().nothing() }) @@ -1136,7 +1153,8 @@ describe('Tooltip', () => { it('should add the content as a child of the element for jQuery elements', () => { fixtureEl.innerHTML = [ '<a href="#" rel="tooltip" title="Another tooltip">', - '<div id="childContent"></div>' + ' <div id="childContent"></div>', + '</a>' ].join('') const tooltipEl = fixtureEl.querySelector('a') @@ -1145,28 +1163,29 @@ describe('Tooltip', () => { html: true }) - tooltip.setElementContent(tooltip.getTipElement(), { 0: childContent, jquery: 'jQuery' }) + tooltip.setContent({ '.tooltip': { 0: childContent, jquery: 'jQuery' } }) - expect(childContent.parentNode).toEqual(tooltip.getTipElement()) + expect(childContent.parentNode).toEqual(tooltip._getTipElement()) }) it('should add the child text content in the element', () => { fixtureEl.innerHTML = [ '<a href="#" rel="tooltip" title="Another tooltip">', - '<div id="childContent">Tooltip</div>' + ' <div id="childContent">Tooltip</div>', + '</a>' ].join('') const tooltipEl = fixtureEl.querySelector('a') const childContent = fixtureEl.querySelector('div') const tooltip = new Tooltip(tooltipEl) - tooltip.setElementContent(tooltip.getTipElement(), childContent) + tooltip.setContent({ '.tooltip': childContent }) - expect(childContent.textContent).toEqual(tooltip.getTipElement().textContent) + expect(childContent.textContent).toEqual(tooltip._getTipElement().textContent) }) it('should add html without sanitize it', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -1174,49 +1193,50 @@ describe('Tooltip', () => { html: true }) - tooltip.setElementContent(tooltip.getTipElement(), '<div id="childContent">Tooltip</div>') + tooltip.setContent({ '.tooltip': '<div id="childContent">Tooltip</div>' }) - expect(tooltip.getTipElement().querySelector('div').id).toEqual('childContent') + expect(tooltip._getTipElement().querySelector('div').id).toEqual('childContent') }) it('should add html sanitized', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { html: true }) - tooltip.setElementContent(tooltip.getTipElement(), [ + const content = [ '<div id="childContent">', - ' <button type="button">test btn</button>', + ' <button type="button">test btn</button>', '</div>' - ].join('')) + ].join('') - expect(tooltip.getTipElement().querySelector('div').id).toEqual('childContent') - expect(tooltip.getTipElement().querySelector('button')).toEqual(null) + tooltip.setContent({ '.tooltip': content }) + expect(tooltip._getTipElement().querySelector('div').id).toEqual('childContent') + expect(tooltip._getTipElement().querySelector('button')).toBeNull() }) it('should add text content', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - tooltip.setElementContent(tooltip.getTipElement(), 'test') + tooltip.setContent({ '.tooltip': 'test' }) - expect(tooltip.getTipElement().textContent).toEqual('test') + expect(tooltip._getTipElement().textContent).toEqual('test') }) }) - describe('getTitle', () => { + describe('_getTitle', () => { it('should return the title', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip.getTitle()).toEqual('Another tooltip') + expect(tooltip._getTitle()).toEqual('Another tooltip') }) it('should call title function', () => { @@ -1227,7 +1247,7 @@ describe('Tooltip', () => { title: () => 'test' }) - expect(tooltip.getTitle()).toEqual('test') + expect(tooltip._getTitle()).toEqual('test') }) }) @@ -1247,7 +1267,7 @@ describe('Tooltip', () => { const div = fixtureEl.querySelector('div') - expect(Tooltip.getInstance(div)).toEqual(null) + expect(Tooltip.getInstance(div)).toBeNull() }) }) @@ -1321,7 +1341,7 @@ describe('Tooltip', () => { const div = fixtureEl.querySelector('div') - expect(Tooltip.getInstance(div)).toEqual(null) + expect(Tooltip.getInstance(div)).toBeNull() expect(Tooltip.getOrCreateInstance(div)).toBeInstanceOf(Tooltip) }) @@ -1330,13 +1350,13 @@ describe('Tooltip', () => { const div = fixtureEl.querySelector('div') - expect(Tooltip.getInstance(div)).toEqual(null) + expect(Tooltip.getInstance(div)).toBeNull() const tooltip = Tooltip.getOrCreateInstance(div, { title: () => 'test' }) expect(tooltip).toBeInstanceOf(Tooltip) - expect(tooltip.getTitle()).toEqual('test') + expect(tooltip._getTitle()).toEqual('test') }) it('should return the instance when exists without given configuration', () => { @@ -1354,7 +1374,7 @@ describe('Tooltip', () => { expect(tooltip).toBeInstanceOf(Tooltip) expect(tooltip2).toEqual(tooltip) - expect(tooltip2.getTitle()).toEqual('nothing') + expect(tooltip2._getTitle()).toEqual('nothing') }) }) diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 818ddf2219..4303693805 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -23,53 +23,53 @@ describe('Backdrop', () => { }) describe('show', () => { - it('if it is "shown", should append the backdrop html once, on show, and contain "show" class', done => { + it('should append the backdrop html once on show and include the "show" class if it is "shown"', done => { const instance = new Backdrop({ isVisible: true, isAnimated: false }) const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) instance.show() instance.show(() => { - expect(getElements().length).toEqual(1) + expect(getElements()).toHaveSize(1) for (const el of getElements()) { - expect(el.classList.contains(CLASS_NAME_SHOW)).toEqual(true) + expect(el).toHaveClass(CLASS_NAME_SHOW) } done() }) }) - it('if it is not "shown", should not append the backdrop html', done => { + it('should not append the backdrop html if it is not "shown"', done => { const instance = new Backdrop({ isVisible: false, isAnimated: true }) const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) instance.show(() => { - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) done() }) }) - it('if it is "shown" and "animated", should append the backdrop html once, and contain "fade" class', done => { + it('should append the backdrop html once and include the "fade" class if it is "shown" and "animated"', done => { const instance = new Backdrop({ isVisible: true, isAnimated: true }) const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) instance.show(() => { - expect(getElements().length).toEqual(1) + expect(getElements()).toHaveSize(1) for (const el of getElements()) { - expect(el.classList.contains(CLASS_NAME_FADE)).toEqual(true) + expect(el).toHaveClass(CLASS_NAME_FADE) } done() @@ -86,17 +86,17 @@ describe('Backdrop', () => { const getElements = () => document.body.querySelectorAll(CLASS_BACKDROP) - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) instance.show(() => { - expect(getElements().length).toEqual(1) + expect(getElements()).toHaveSize(1) instance.hide(() => { - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) done() }) }) }) - it('should remove "show" class', done => { + it('should remove the "show" class', done => { const instance = new Backdrop({ isVisible: true, isAnimated: true @@ -105,12 +105,12 @@ describe('Backdrop', () => { instance.show() instance.hide(() => { - expect(elem.classList.contains(CLASS_NAME_SHOW)).toEqual(false) + expect(elem).not.toHaveClass(CLASS_NAME_SHOW) done() }) }) - it('if it is not "shown", should not try to remove Node on remove method', done => { + it('should not try to remove Node on remove method if it is not "shown"', done => { const instance = new Backdrop({ isVisible: false, isAnimated: true @@ -118,13 +118,13 @@ describe('Backdrop', () => { const getElements = () => document.querySelectorAll(CLASS_BACKDROP) const spy = spyOn(instance, 'dispose').and.callThrough() - expect(getElements().length).toEqual(0) - expect(instance._isAppended).toEqual(false) + expect(getElements()).toHaveSize(0) + expect(instance._isAppended).toBeFalse() instance.show(() => { instance.hide(() => { - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) expect(spy).not.toHaveBeenCalled() - expect(instance._isAppended).toEqual(false) + expect(instance._isAppended).toBeFalse() done() }) }) @@ -145,7 +145,7 @@ describe('Backdrop', () => { instance.show(() => { wrapper.remove() instance.hide(() => { - expect(getElements().length).toEqual(0) + expect(getElements()).toHaveSize(0) done() }) }) @@ -153,7 +153,7 @@ describe('Backdrop', () => { }) describe('click callback', () => { - it('it should execute callback on click', done => { + it('should execute callback on click', done => { const spy = jasmine.createSpy('spy') const instance = new Backdrop({ @@ -178,7 +178,7 @@ describe('Backdrop', () => { }) describe('animation callbacks', () => { - it('if it is animated, should show and hide backdrop after counting transition duration', done => { + it('should show and hide backdrop after counting transition duration if it is animated', done => { const instance = new Backdrop({ isVisible: true, isAnimated: true @@ -200,7 +200,7 @@ describe('Backdrop', () => { expect(spy2).not.toHaveBeenCalled() }) - it('if it is not animated, should show and hide backdrop without delay', done => { + it('should show and hide backdrop without a delay if it is not animated', done => { const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) const instance = new Backdrop({ isVisible: true, @@ -218,7 +218,7 @@ describe('Backdrop', () => { }, 10) }) - it('if it is not "shown", should not call delay callbacks', done => { + it('should not call delay callbacks if it is not "shown"', done => { const instance = new Backdrop({ isVisible: false, isAnimated: true @@ -232,9 +232,10 @@ describe('Backdrop', () => { }) }) }) + describe('Config', () => { describe('rootElement initialization', () => { - it('Should be appended on "document.body" by default', done => { + it('should be appended on "document.body" by default', done => { const instance = new Backdrop({ isVisible: true }) @@ -245,7 +246,7 @@ describe('Backdrop', () => { }) }) - it('Should find the rootElement if passed as a string', done => { + it('should find the rootElement if passed as a string', done => { const instance = new Backdrop({ isVisible: true, rootElement: 'body' @@ -257,11 +258,8 @@ describe('Backdrop', () => { }) }) - it('Should appended on any element given by the proper config', done => { - fixtureEl.innerHTML = [ - '<div id="wrapper">', - '</div>' - ].join('') + it('should be appended on any element given by the proper config', done => { + fixtureEl.innerHTML = '<div id="wrapper"></div>' const wrapper = fixtureEl.querySelector('#wrapper') const instance = new Backdrop({ @@ -277,7 +275,7 @@ describe('Backdrop', () => { }) describe('ClassName', () => { - it('Should be able to have different classNames than default', done => { + it('should allow configuring className', done => { const instance = new Backdrop({ isVisible: true, className: 'foo' diff --git a/js/tests/unit/util/component-functions.spec.js b/js/tests/unit/util/component-functions.spec.js index edaedd32ee..16f910a633 100644 --- a/js/tests/unit/util/component-functions.spec.js +++ b/js/tests/unit/util/component-functions.spec.js @@ -33,7 +33,7 @@ describe('Plugin functions', () => { it('should get Plugin and execute the given method, when a click occurred on data-bs-dismiss="PluginName"', () => { fixtureEl.innerHTML = [ '<div id="foo" class="test">', - ' <button type="button" data-bs-dismiss="test" data-bs-target="#foo"></button>', + ' <button type="button" data-bs-dismiss="test" data-bs-target="#foo"></button>', '</div>' ].join('') @@ -53,7 +53,7 @@ describe('Plugin functions', () => { it('if data-bs-dismiss="PluginName" hasn\'t got "data-bs-target", "getOrCreateInstance" has to be initialized by closest "plugin.Name" class', () => { fixtureEl.innerHTML = [ '<div id="foo" class="test">', - ' <button type="button" data-bs-dismiss="test"></button>', + ' <button type="button" data-bs-dismiss="test"></button>', '</div>' ].join('') @@ -73,7 +73,7 @@ describe('Plugin functions', () => { it('if data-bs-dismiss="PluginName" is disabled, must not trigger function', () => { fixtureEl.innerHTML = [ '<div id="foo" class="test">', - ' <button type="button" disabled data-bs-dismiss="test"></button>', + ' <button type="button" disabled data-bs-dismiss="test"></button>', '</div>' ].join('') @@ -90,7 +90,7 @@ describe('Plugin functions', () => { it('should prevent default when the trigger is <a> or <area>', () => { fixtureEl.innerHTML = [ '<div id="foo" class="test">', - ' <a type="button" data-bs-dismiss="test"></a>', + ' <a type="button" data-bs-dismiss="test"></a>', '</div>' ].join('') diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index 99bc95fca4..52a7573971 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -45,7 +45,7 @@ describe('FocusTrap', () => { fixtureEl.innerHTML = [ '<a href="#" id="outside">outside</a>', '<div id="focustrap" tabindex="-1">', - ' <a href="#" id="inside">inside</a>', + ' <a href="#" id="inside">inside</a>', '</div>' ].join('') @@ -78,9 +78,9 @@ describe('FocusTrap', () => { fixtureEl.innerHTML = [ '<a href="#" id="outside">outside</a>', '<div id="focustrap" tabindex="-1">', - ' <a href="#" id="first">first</a>', - ' <a href="#" id="inside">inside</a>', - ' <a href="#" id="last">last</a>', + ' <a href="#" id="first">first</a>', + ' <a href="#" id="inside">inside</a>', + ' <a href="#" id="last">last</a>', '</div>' ].join('') @@ -115,9 +115,9 @@ describe('FocusTrap', () => { fixtureEl.innerHTML = [ '<a href="#" id="outside">outside</a>', '<div id="focustrap" tabindex="-1">', - ' <a href="#" id="first">first</a>', - ' <a href="#" id="inside">inside</a>', - ' <a href="#" id="last">last</a>', + ' <a href="#" id="first">first</a>', + ' <a href="#" id="inside">inside</a>', + ' <a href="#" id="last">last</a>', '</div>' ].join('') @@ -182,10 +182,10 @@ describe('FocusTrap', () => { it('should flag itself as no longer active', () => { const focustrap = new FocusTrap({ trapElement: fixtureEl }) focustrap.activate() - expect(focustrap._isActive).toBe(true) + expect(focustrap._isActive).toBeTrue() focustrap.deactivate() - expect(focustrap._isActive).toBe(false) + expect(focustrap._isActive).toBeFalse() }) it('should remove all event listeners', () => { diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index ccfe5e2c29..a9e446c9df 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -179,9 +179,9 @@ describe('Util', () => { const el = fixtureEl.querySelector('#foo') - expect(Util.isElement(el)).toEqual(true) - expect(Util.isElement({})).toEqual(false) - expect(Util.isElement(fixtureEl.querySelectorAll('.test'))).toEqual(false) + expect(Util.isElement(el)).toBeTrue() + expect(Util.isElement({})).toBeFalse() + expect(Util.isElement(fixtureEl.querySelectorAll('.test'))).toBeFalse() }) it('should detect jQuery element', () => { @@ -193,7 +193,7 @@ describe('Util', () => { jquery: 'foo' } - expect(Util.isElement(fakejQuery)).toEqual(true) + expect(Util.isElement(fakejQuery)).toBeTrue() }) }) @@ -274,12 +274,12 @@ describe('Util', () => { describe('isVisible', () => { it('should return false if the element is not defined', () => { - expect(Util.isVisible(null)).toEqual(false) - expect(Util.isVisible(undefined)).toEqual(false) + expect(Util.isVisible(null)).toBeFalse() + expect(Util.isVisible(undefined)).toBeFalse() }) it('should return false if the element provided is not a dom element', () => { - expect(Util.isVisible({})).toEqual(false) + expect(Util.isVisible({})).toBeFalse() }) it('should return false if the element is not visible with display none', () => { @@ -287,7 +287,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('div') - expect(Util.isVisible(div)).toEqual(false) + expect(Util.isVisible(div)).toBeFalse() }) it('should return false if the element is not visible with visibility hidden', () => { @@ -295,7 +295,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('div') - expect(Util.isVisible(div)).toEqual(false) + expect(Util.isVisible(div)).toBeFalse() }) it('should return false if an ancestor element is display none', () => { @@ -311,7 +311,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('.content') - expect(Util.isVisible(div)).toEqual(false) + expect(Util.isVisible(div)).toBeFalse() }) it('should return false if an ancestor element is visibility hidden', () => { @@ -327,7 +327,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('.content') - expect(Util.isVisible(div)).toEqual(false) + expect(Util.isVisible(div)).toBeFalse() }) it('should return true if an ancestor element is visibility hidden, but reverted', () => { @@ -343,7 +343,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('.content') - expect(Util.isVisible(div)).toEqual(true) + expect(Util.isVisible(div)).toBeTrue() }) it('should return true if the element is visible', () => { @@ -355,7 +355,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('#element') - expect(Util.isVisible(div)).toEqual(true) + expect(Util.isVisible(div)).toBeTrue() }) it('should return false if the element is hidden, but not via display or visibility', () => { @@ -367,20 +367,20 @@ describe('Util', () => { const div = fixtureEl.querySelector('#element') - expect(Util.isVisible(div)).toEqual(false) + expect(Util.isVisible(div)).toBeFalse() }) }) describe('isDisabled', () => { it('should return true if the element is not defined', () => { - expect(Util.isDisabled(null)).toEqual(true) - expect(Util.isDisabled(undefined)).toEqual(true) - expect(Util.isDisabled()).toEqual(true) + expect(Util.isDisabled(null)).toBeTrue() + expect(Util.isDisabled(undefined)).toBeTrue() + expect(Util.isDisabled()).toBeTrue() }) it('should return true if the element provided is not a dom element', () => { - expect(Util.isDisabled({})).toEqual(true) - expect(Util.isDisabled('test')).toEqual(true) + expect(Util.isDisabled({})).toBeTrue() + expect(Util.isDisabled('test')).toBeTrue() }) it('should return true if the element has disabled attribute', () => { @@ -396,9 +396,9 @@ describe('Util', () => { const div1 = fixtureEl.querySelector('#element1') const div2 = fixtureEl.querySelector('#element2') - expect(Util.isDisabled(div)).toEqual(true) - expect(Util.isDisabled(div1)).toEqual(true) - expect(Util.isDisabled(div2)).toEqual(true) + expect(Util.isDisabled(div)).toBeTrue() + expect(Util.isDisabled(div1)).toBeTrue() + expect(Util.isDisabled(div2)).toBeTrue() }) it('should return false if the element has disabled attribute with "false" value, or doesn\'t have attribute', () => { @@ -412,8 +412,8 @@ describe('Util', () => { const div = fixtureEl.querySelector('#element') const div1 = fixtureEl.querySelector('#element1') - expect(Util.isDisabled(div)).toEqual(false) - expect(Util.isDisabled(div1)).toEqual(false) + expect(Util.isDisabled(div)).toBeFalse() + expect(Util.isDisabled(div1)).toBeFalse() }) it('should return false if the element is not disabled ', () => { @@ -427,10 +427,11 @@ describe('Util', () => { const el = selector => fixtureEl.querySelector(selector) - expect(Util.isDisabled(el('#button'))).toEqual(false) - expect(Util.isDisabled(el('#select'))).toEqual(false) - expect(Util.isDisabled(el('#input'))).toEqual(false) + expect(Util.isDisabled(el('#button'))).toBeFalse() + expect(Util.isDisabled(el('#select'))).toBeFalse() + expect(Util.isDisabled(el('#input'))).toBeFalse() }) + it('should return true if the element has disabled attribute', () => { fixtureEl.innerHTML = [ '<div>', @@ -446,12 +447,12 @@ describe('Util', () => { const el = selector => fixtureEl.querySelector(selector) - expect(Util.isDisabled(el('#input'))).toEqual(true) - expect(Util.isDisabled(el('#input1'))).toEqual(true) - expect(Util.isDisabled(el('#button'))).toEqual(true) - expect(Util.isDisabled(el('#button1'))).toEqual(true) - expect(Util.isDisabled(el('#button2'))).toEqual(true) - expect(Util.isDisabled(el('#input'))).toEqual(true) + expect(Util.isDisabled(el('#input'))).toBeTrue() + expect(Util.isDisabled(el('#input1'))).toBeTrue() + expect(Util.isDisabled(el('#button'))).toBeTrue() + expect(Util.isDisabled(el('#button1'))).toBeTrue() + expect(Util.isDisabled(el('#button2'))).toBeTrue() + expect(Util.isDisabled(el('#input'))).toBeTrue() }) it('should return true if the element has class "disabled"', () => { @@ -463,7 +464,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('#element') - expect(Util.isDisabled(div)).toEqual(true) + expect(Util.isDisabled(div)).toBeTrue() }) it('should return true if the element has class "disabled" but disabled attribute is false', () => { @@ -475,7 +476,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('#input') - expect(Util.isDisabled(div)).toEqual(true) + expect(Util.isDisabled(div)).toBeTrue() }) }) @@ -493,7 +494,7 @@ describe('Util', () => { spyOn(document.documentElement, 'attachShadow').and.returnValue(null) - expect(Util.findShadowRoot(div)).toEqual(null) + expect(Util.findShadowRoot(div)).toBeNull() }) it('should return null when we do not find a shadow root', () => { @@ -505,7 +506,7 @@ describe('Util', () => { spyOn(document, 'getRootNode').and.returnValue(undefined) - expect(Util.findShadowRoot(document)).toEqual(null) + expect(Util.findShadowRoot(document)).toBeNull() }) it('should return the shadow root when found', () => { @@ -532,7 +533,7 @@ describe('Util', () => { describe('noop', () => { it('should be a function', () => { - expect(typeof Util.noop).toEqual('function') + expect(Util.noop).toEqual(jasmine.any(Function)) }) }) @@ -569,14 +570,14 @@ describe('Util', () => { document.body.setAttribute('data-bs-no-jquery', '') expect(window.jQuery).toEqual(fakejQuery) - expect(Util.getjQuery()).toEqual(null) + expect(Util.getjQuery()).toBeNull() document.body.removeAttribute('data-bs-no-jquery') }) it('should not return jQuery if not present', () => { window.jQuery = undefined - expect(Util.getjQuery()).toEqual(null) + expect(Util.getjQuery()).toBeNull() }) }) @@ -628,9 +629,9 @@ describe('Util', () => { pluginMock.jQueryInterface = function () {} Util.defineJQueryPlugin(pluginMock) - expect(fakejQuery.fn.test).toBe(pluginMock.jQueryInterface) - expect(fakejQuery.fn.test.Constructor).toBe(pluginMock) - expect(typeof fakejQuery.fn.test.noConflict).toEqual('function') + expect(fakejQuery.fn.test).toEqual(pluginMock.jQueryInterface) + expect(fakejQuery.fn.test.Constructor).toEqual(pluginMock) + expect(fakejQuery.fn.test.noConflict).toEqual(jasmine.any(Function)) }) }) diff --git a/js/tests/unit/util/scrollbar.spec.js b/js/tests/unit/util/scrollbar.spec.js index 280adb8e5a..15f09c0b22 100644 --- a/js/tests/unit/util/scrollbar.spec.js +++ b/js/tests/unit/util/scrollbar.spec.js @@ -5,9 +5,9 @@ import ScrollBarHelper from '../../../src/util/scrollbar' describe('ScrollBar', () => { let fixtureEl const doc = document.documentElement - const parseInt = arg => Number.parseInt(arg, 10) - const getPaddingX = el => parseInt(window.getComputedStyle(el).paddingRight) - const getMarginX = el => parseInt(window.getComputedStyle(el).marginRight) + const parseIntDecimal = arg => Number.parseInt(arg, 10) + const getPaddingX = el => parseIntDecimal(window.getComputedStyle(el).paddingRight) + const getMarginX = el => parseIntDecimal(window.getComputedStyle(el).marginRight) const getOverFlow = el => el.style.overflow const getPaddingAttr = el => Manipulator.getDataAttribute(el, 'padding-right') const getMarginAttr = el => Manipulator.getDataAttribute(el, 'margin-right') @@ -24,7 +24,9 @@ describe('ScrollBar', () => { } } - const isScrollBarHidden = () => { // IOS devices, Android devices and Browsers on Mac, hide scrollbar by default and appear it, only while scrolling. So the tests for scrollbar would fail + // iOS, Android devices and macOS browsers hide scrollbar by default and show it only while scrolling. + // So the tests for scrollbar would fail + const isScrollBarHidden = () => { const calc = windowCalculations() return calc.htmlClient === calc.htmlOffset && calc.htmlClient === calc.window } @@ -52,28 +54,24 @@ describe('ScrollBar', () => { it('should return true if body is overflowing', () => { document.documentElement.style.overflowY = 'scroll' document.body.style.overflowY = 'scroll' - fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%"></div>' - ].join('') + fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>' const result = new ScrollBarHelper().isOverflowing() if (isScrollBarHidden()) { - expect(result).toEqual(false) + expect(result).toBeFalse() } else { - expect(result).toEqual(true) + expect(result).toBeTrue() } }) it('should return false if body is not overflowing', () => { doc.style.overflowY = 'hidden' document.body.style.overflowY = 'hidden' - fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%"></div>' - ].join('') + fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>' const scrollBar = new ScrollBarHelper() const result = scrollBar.isOverflowing() - expect(result).toEqual(false) + expect(result).toBeFalse() }) }) @@ -81,13 +79,11 @@ describe('ScrollBar', () => { it('should return an integer greater than zero, if body is overflowing', () => { doc.style.overflowY = 'scroll' document.body.style.overflowY = 'scroll' - fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%"></div>' - ].join('') + fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>' const result = new ScrollBarHelper().getWidth() if (isScrollBarHidden()) { - expect(result).toBe(0) + expect(result).toEqual(0) } else { expect(result).toBeGreaterThan(1) } @@ -96,9 +92,7 @@ describe('ScrollBar', () => { it('should return 0 if body is not overflowing', () => { document.documentElement.style.overflowY = 'hidden' document.body.style.overflowY = 'hidden' - fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%"></div>' - ].join('') + fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>' const result = new ScrollBarHelper().getWidth() @@ -109,9 +103,9 @@ describe('ScrollBar', () => { describe('hide - reset', () => { it('should adjust the inline padding of fixed elements which are full-width', done => { fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%">' + - '<div class="fixed-top" id="fixed1" style="padding-right: 0px; width: 100vw"></div>', - '<div class="fixed-top" id="fixed2" style="padding-right: 5px; width: 100vw"></div>', + '<div style="height: 110vh; width: 100%">', + ' <div class="fixed-top" id="fixed1" style="padding-right: 0px; width: 100vw"></div>', + ' <div class="fixed-top" id="fixed2" style="padding-right: 5px; width: 100vw"></div>', '</div>' ].join('') doc.style.overflowY = 'scroll' @@ -128,25 +122,25 @@ describe('ScrollBar', () => { let currentPadding = getPaddingX(fixedEl) let currentPadding2 = getPaddingX(fixedEl2) - expect(getPaddingAttr(fixedEl)).toEqual(`${originalPadding}px`, 'original fixed element padding should be stored in data-bs-padding-right') - expect(getPaddingAttr(fixedEl2)).toEqual(`${originalPadding2}px`, 'original fixed element padding should be stored in data-bs-padding-right') - expect(currentPadding).toEqual(expectedPadding, 'fixed element padding should be adjusted while opening') - expect(currentPadding2).toEqual(expectedPadding2, 'fixed element padding should be adjusted while opening') + expect(getPaddingAttr(fixedEl)).toEqual(`${originalPadding}px`) + expect(getPaddingAttr(fixedEl2)).toEqual(`${originalPadding2}px`) + expect(currentPadding).toEqual(expectedPadding) + expect(currentPadding2).toEqual(expectedPadding2) scrollBar.reset() currentPadding = getPaddingX(fixedEl) currentPadding2 = getPaddingX(fixedEl2) - expect(getPaddingAttr(fixedEl)).toEqual(null, 'data-bs-padding-right should be cleared after closing') - expect(getPaddingAttr(fixedEl2)).toEqual(null, 'data-bs-padding-right should be cleared after closing') - expect(currentPadding).toEqual(originalPadding, 'fixed element padding should be reset after closing') - expect(currentPadding2).toEqual(originalPadding2, 'fixed element padding should be reset after closing') + expect(getPaddingAttr(fixedEl)).toBeNull() + expect(getPaddingAttr(fixedEl2)).toBeNull() + expect(currentPadding).toEqual(originalPadding) + expect(currentPadding2).toEqual(originalPadding2) done() }) it('should adjust the inline margin and padding of sticky elements', done => { fixtureEl.innerHTML = [ - '<div style="height: 110vh">' + - '<div class="sticky-top" style="margin-right: 10px; padding-right: 20px; width: 100vw; height: 10px"></div>', + '<div style="height: 110vh">', + ' <div class="sticky-top" style="margin-right: 10px; padding-right: 20px; width: 100vw; height: 10px"></div>', '</div>' ].join('') doc.style.overflowY = 'scroll' @@ -159,23 +153,21 @@ describe('ScrollBar', () => { const expectedPadding = originalPadding + scrollBar.getWidth() scrollBar.hide() - expect(getMarginAttr(stickyTopEl)).toEqual(`${originalMargin}px`, 'original sticky element margin should be stored in data-bs-margin-right') - expect(getMarginX(stickyTopEl)).toEqual(expectedMargin, 'sticky element margin should be adjusted while opening') - expect(getPaddingAttr(stickyTopEl)).toEqual(`${originalPadding}px`, 'original sticky element margin should be stored in data-bs-margin-right') - expect(getPaddingX(stickyTopEl)).toEqual(expectedPadding, 'sticky element margin should be adjusted while opening') + expect(getMarginAttr(stickyTopEl)).toEqual(`${originalMargin}px`) + expect(getMarginX(stickyTopEl)).toEqual(expectedMargin) + expect(getPaddingAttr(stickyTopEl)).toEqual(`${originalPadding}px`) + expect(getPaddingX(stickyTopEl)).toEqual(expectedPadding) scrollBar.reset() - expect(getMarginAttr(stickyTopEl)).toEqual(null, 'data-bs-margin-right should be cleared after closing') - expect(getMarginX(stickyTopEl)).toEqual(originalMargin, 'sticky element margin should be reset after closing') - expect(getPaddingAttr(stickyTopEl)).toEqual(null, 'data-bs-margin-right should be cleared after closing') - expect(getPaddingX(stickyTopEl)).toEqual(originalPadding, 'sticky element margin should be reset after closing') + expect(getMarginAttr(stickyTopEl)).toBeNull() + expect(getMarginX(stickyTopEl)).toEqual(originalMargin) + expect(getPaddingAttr(stickyTopEl)).toBeNull() + expect(getPaddingX(stickyTopEl)).toEqual(originalPadding) done() }) it('should not adjust the inline margin and padding of sticky and fixed elements when element do not have full width', () => { - fixtureEl.innerHTML = [ - '<div class="sticky-top" style="margin-right: 0px; padding-right: 0px; width: 50vw"></div>' - ].join('') + fixtureEl.innerHTML = '<div class="sticky-top" style="margin-right: 0px; padding-right: 0px; width: 50vw"></div>' const stickyTopEl = fixtureEl.querySelector('.sticky-top') const originalMargin = getMarginX(stickyTopEl) @@ -187,16 +179,16 @@ describe('ScrollBar', () => { const currentMargin = getMarginX(stickyTopEl) const currentPadding = getPaddingX(stickyTopEl) - expect(currentMargin).toEqual(originalMargin, 'sticky element\'s margin should not be adjusted while opening') - expect(currentPadding).toEqual(originalPadding, 'sticky element\'s padding should not be adjusted while opening') + expect(currentMargin).toEqual(originalMargin) + expect(currentPadding).toEqual(originalPadding) scrollBar.reset() }) it('should not put data-attribute if element doesn\'t have the proper style property, should just remove style property if element didn\'t had one', () => { fixtureEl.innerHTML = [ - '<div style="height: 110vh; width: 100%">' + - '<div class="sticky-top" id="sticky" style="width: 100vw"></div>', + '<div style="height: 110vh; width: 100%">', + ' <div class="sticky-top" id="sticky" style="width: 100vw"></div>', '</div>' ].join('') @@ -232,8 +224,8 @@ describe('ScrollBar', () => { const scrollBarWidth = scrollBar.getWidth() scrollBar.hide() - expect(getPaddingX(document.body)).toEqual(scrollBarWidth, 'body does not have inline padding set') - expect(document.body.style.color).toEqual('red', 'body still has other inline styles set') + expect(getPaddingX(document.body)).toEqual(scrollBarWidth) + expect(document.body.style.color).toEqual('red') scrollBar.reset() }) @@ -243,7 +235,7 @@ describe('ScrollBar', () => { fixtureEl.innerHTML = [ '<style>', ' body {', - ` padding-right: ${styleSheetPadding} }`, + ` padding-right: ${styleSheetPadding}`, ' }', '</style>' ].join('') @@ -253,7 +245,7 @@ describe('ScrollBar', () => { el.style.paddingRight = inlineStylePadding const originalPadding = getPaddingX(el) - expect(originalPadding).toEqual(parseInt(inlineStylePadding)) // Respect only the inline style as it has prevails this of css + expect(originalPadding).toEqual(parseIntDecimal(inlineStylePadding)) // Respect only the inline style as it has prevails this of css const originalOverFlow = 'auto' el.style.overflow = originalOverFlow const scrollBar = new ScrollBarHelper() @@ -264,7 +256,7 @@ describe('ScrollBar', () => { const currentPadding = getPaddingX(el) expect(currentPadding).toEqual(scrollBarWidth + originalPadding) - expect(currentPadding).toEqual(scrollBarWidth + parseInt(inlineStylePadding)) + expect(currentPadding).toEqual(scrollBarWidth + parseIntDecimal(inlineStylePadding)) expect(getPaddingAttr(el)).toEqual(inlineStylePadding) expect(getOverFlow(el)).toEqual('hidden') expect(getOverFlowAttr(el)).toEqual(originalOverFlow) @@ -273,9 +265,9 @@ describe('ScrollBar', () => { const currentPadding1 = getPaddingX(el) expect(currentPadding1).toEqual(originalPadding) - expect(getPaddingAttr(el)).toEqual(null) + expect(getPaddingAttr(el)).toBeNull() expect(getOverFlow(el)).toEqual(originalOverFlow) - expect(getOverFlowAttr(el)).toEqual(null) + expect(getOverFlowAttr(el)).toBeNull() }) it('should hide scrollbar and reset it to its initial value - respecting css rules', () => { @@ -283,7 +275,7 @@ describe('ScrollBar', () => { fixtureEl.innerHTML = [ '<style>', ' body {', - ` padding-right: ${styleSheetPadding} }`, + ` padding-right: ${styleSheetPadding}`, ' }', '</style>' ].join('') @@ -299,7 +291,7 @@ describe('ScrollBar', () => { const currentPadding = getPaddingX(el) expect(currentPadding).toEqual(scrollBarWidth + originalPadding) - expect(currentPadding).toEqual(scrollBarWidth + parseInt(styleSheetPadding)) + expect(currentPadding).toEqual(scrollBarWidth + parseIntDecimal(styleSheetPadding)) expect(getPaddingAttr(el)).toBeNull() // We do not have to keep css padding expect(getOverFlow(el)).toEqual('hidden') expect(getOverFlowAttr(el)).toEqual(originalOverFlow) @@ -308,9 +300,9 @@ describe('ScrollBar', () => { const currentPadding1 = getPaddingX(el) expect(currentPadding1).toEqual(originalPadding) - expect(getPaddingAttr(el)).toEqual(null) + expect(getPaddingAttr(el)).toBeNull() expect(getOverFlow(el)).toEqual(originalOverFlow) - expect(getOverFlowAttr(el)).toEqual(null) + expect(getOverFlowAttr(el)).toBeNull() }) it('should not adjust the inline body padding when it does not overflow', () => { @@ -324,7 +316,7 @@ describe('ScrollBar', () => { scrollBar.hide() const currentPadding = getPaddingX(document.body) - expect(currentPadding).toEqual(originalPadding, 'body padding should not be adjusted') + expect(currentPadding).toEqual(originalPadding) scrollBar.reset() }) @@ -344,7 +336,7 @@ describe('ScrollBar', () => { const currentPadding = getPaddingX(document.body) - expect(currentPadding).toEqual(originalPadding, 'body padding should not be adjusted') + expect(currentPadding).toEqual(originalPadding) scrollBar.reset() }) diff --git a/js/tests/unit/util/swipe.spec.js b/js/tests/unit/util/swipe.spec.js index 474e34f653..93131b8fdd 100644 --- a/js/tests/unit/util/swipe.spec.js +++ b/js/tests/unit/util/swipe.spec.js @@ -39,17 +39,17 @@ describe('Swipe', () => { fixtureEl = getFixture() const cssStyle = [ '<style>', - ' #fixture .pointer-event {', - ' touch-action: pan-y;', + ' #fixture .pointer-event {', + ' touch-action: pan-y;', ' }', - ' #fixture div {', - ' width: 300px;', - ' height: 300px;', + ' #fixture div {', + ' width: 300px;', + ' height: 300px;', ' }', '</style>' ].join('') - fixtureEl.innerHTML = '<div id="swipeEl"></div>' + cssStyle + fixtureEl.innerHTML = `<div id="swipeEl"></div>${cssStyle}` swipeEl = fixtureEl.querySelector('div') }) @@ -266,7 +266,7 @@ describe('Swipe', () => { expect(Swipe.isSupported()).toBeTrue() }) - it('should return "false" if "touchstart" not exists in document element and "navigator.maxTouchPoints" are zero (0)', () => { + it('should return "false" if "touchstart" not exists in document element and "navigator.maxTouchPoints" are zero (0)', () => { Object.defineProperty(window.navigator, 'maxTouchPoints', () => 0) deleteDocumentElementOntouchstart() diff --git a/js/tests/unit/util/template-factory.spec.js b/js/tests/unit/util/template-factory.spec.js new file mode 100644 index 0000000000..0fdf871466 --- /dev/null +++ b/js/tests/unit/util/template-factory.spec.js @@ -0,0 +1,306 @@ +import { clearFixture, getFixture } from '../../helpers/fixture' +import TemplateFactory from '../../../src/util/template-factory' + +describe('TemplateFactory', () => { + let fixtureEl + + beforeAll(() => { + fixtureEl = getFixture() + }) + + afterEach(() => { + clearFixture() + }) + + describe('NAME', () => { + it('should return plugin NAME', () => { + expect(TemplateFactory.NAME).toEqual('TemplateFactory') + }) + }) + + describe('Default', () => { + it('should return plugin default config', () => { + expect(TemplateFactory.Default).toEqual(jasmine.any(Object)) + }) + }) + + describe('toHtml', () => { + describe('Sanitization', () => { + it('should use "sanitizeHtml" to sanitize template', () => { + const factory = new TemplateFactory({ + sanitize: true, + template: '<div><a href="javascript:alert(7)">Click me</a></div>' + }) + const spy = spyOn(factory, '_maybeSanitize').and.callThrough() + + expect(factory.toHtml().innerHTML).not.toContain('href="javascript:alert(7)') + expect(spy).toHaveBeenCalled() + }) + + it('should not sanitize template', () => { + const factory = new TemplateFactory({ + sanitize: false, + template: '<div><a href="javascript:alert(7)">Click me</a></div>' + }) + const spy = spyOn(factory, '_maybeSanitize').and.callThrough() + + expect(factory.toHtml().innerHTML).toContain('href="javascript:alert(7)') + expect(spy).toHaveBeenCalled() + }) + + it('should use "sanitizeHtml" to sanitize content', () => { + const factory = new TemplateFactory({ + sanitize: true, + html: true, + template: '<div id="foo"></div>', + content: { '#foo': '<a href="javascript:alert(7)">Click me</a>' } + }) + expect(factory.toHtml().innerHTML).not.toContain('href="javascript:alert(7)') + }) + + it('should not sanitize content', () => { + const factory = new TemplateFactory({ + sanitize: false, + html: true, + template: '<div id="foo"></div>', + content: { '#foo': '<a href="javascript:alert(7)">Click me</a>' } + }) + expect(factory.toHtml().innerHTML).toContain('href="javascript:alert(7)') + }) + + it('should sanitize content only if "config.html" is enabled', () => { + const factory = new TemplateFactory({ + sanitize: true, + html: false, + template: '<div id="foo"></div>', + content: { '#foo': '<a href="javascript:alert(7)">Click me</a>' } + }) + const spy = spyOn(factory, '_maybeSanitize').and.callThrough() + + expect(spy).not.toHaveBeenCalled() + }) + }) + + describe('Extra Class', () => { + it('should add extra class', () => { + const factory = new TemplateFactory({ + extraClass: 'testClass' + }) + expect(factory.toHtml()).toHaveClass('testClass') + }) + + it('should add extra classes', () => { + const factory = new TemplateFactory({ + extraClass: 'testClass testClass2' + }) + expect(factory.toHtml()).toHaveClass('testClass') + expect(factory.toHtml()).toHaveClass('testClass2') + }) + + it('should resolve class if function is given', () => { + const factory = new TemplateFactory({ + extraClass: arg => { + expect(arg).toEqual(factory) + return 'testClass' + } + }) + + expect(factory.toHtml()).toHaveClass('testClass') + }) + }) + }) + + describe('Content', () => { + it('add simple text content', () => { + const template = [ + '<div>', + ' <div class="foo"></div>', + ' <div class="foo2"></div>', + '</div>' + ].join('') + + const factory = new TemplateFactory({ + template, + content: { + '.foo': 'bar', + '.foo2': 'bar2' + } + }) + + const html = factory.toHtml() + expect(html.querySelector('.foo').textContent).toEqual('bar') + expect(html.querySelector('.foo2').textContent).toEqual('bar2') + }) + + it('should not fill template if selector not exists', () => { + const factory = new TemplateFactory({ + sanitize: true, + html: true, + template: '<div id="foo"></div>', + content: { '#bar': 'test' } + }) + + expect(factory.toHtml().outerHTML).toEqual('<div id="foo"></div>') + }) + + it('should remove template selector, if content is null', () => { + const factory = new TemplateFactory({ + sanitize: true, + html: true, + template: '<div><div id="foo"></div></div>', + content: { '#foo': null } + }) + + expect(factory.toHtml().outerHTML).toEqual('<div></div>') + }) + + it('should resolve content if is function', () => { + const factory = new TemplateFactory({ + sanitize: true, + html: true, + template: '<div><div id="foo"></div></div>', + content: { '#foo': () => null } + }) + + expect(factory.toHtml().outerHTML).toEqual('<div></div>') + }) + + it('if content is element and "config.html=false", should put content\'s textContent', () => { + fixtureEl.innerHTML = '<div>foo<span>bar</span></div>' + const contentElement = fixtureEl.querySelector('div') + + const factory = new TemplateFactory({ + html: false, + template: '<div><div id="foo"></div></div>', + content: { '#foo': contentElement } + }) + + const fooEl = factory.toHtml().querySelector('#foo') + expect(fooEl.innerHTML).not.toEqual(contentElement.innerHTML) + expect(fooEl.textContent).toEqual(contentElement.textContent) + expect(fooEl.textContent).toEqual('foobar') + }) + + it('if content is element and "config.html=true", should put content\'s outerHtml as child', () => { + fixtureEl.innerHTML = '<div>foo<span>bar</span></div>' + const contentElement = fixtureEl.querySelector('div') + + const factory = new TemplateFactory({ + html: true, + template: '<div><div id="foo"></div></div>', + content: { '#foo': contentElement } + }) + + const fooEl = factory.toHtml().querySelector('#foo') + expect(fooEl.innerHTML).toEqual(contentElement.outerHTML) + expect(fooEl.textContent).toEqual(contentElement.textContent) + }) + }) + + describe('getContent', () => { + it('should get content as array', () => { + const factory = new TemplateFactory({ + content: { + '.foo': 'bar', + '.foo2': 'bar2' + } + }) + expect(factory.getContent()).toEqual(['bar', 'bar2']) + }) + + it('should filter empties', () => { + const factory = new TemplateFactory({ + content: { + '.foo': 'bar', + '.foo2': '', + '.foo3': null, + '.foo4': () => 2, + '.foo5': () => null + } + }) + expect(factory.getContent()).toEqual(['bar', 2]) + }) + }) + + describe('hasContent', () => { + it('should return true, if it has', () => { + const factory = new TemplateFactory({ + content: { + '.foo': 'bar', + '.foo2': 'bar2', + '.foo3': '' + } + }) + expect(factory.hasContent()).toBeTrue() + }) + + it('should return false, if filtered content is empty', () => { + const factory = new TemplateFactory({ + content: { + '.foo2': '', + '.foo3': null, + '.foo4': () => null + } + }) + expect(factory.hasContent()).toBeFalse() + }) + }) + + describe('changeContent', () => { + it('should change Content', () => { + const template = [ + '<div>', + ' <div class="foo"></div>', + ' <div class="foo2"></div>', + '</div>' + ].join('') + + const factory = new TemplateFactory({ + template, + content: { + '.foo': 'bar', + '.foo2': 'bar2' + } + }) + + const html = selector => factory.toHtml().querySelector(selector).textContent + expect(html('.foo')).toEqual('bar') + expect(html('.foo2')).toEqual('bar2') + factory.changeContent({ + '.foo': 'test', + '.foo2': 'test2' + }) + + expect(html('.foo')).toEqual('test') + expect(html('.foo2')).toEqual('test2') + }) + + it('should change only the given, content', () => { + const template = [ + '<div>', + ' <div class="foo"></div>', + ' <div class="foo2"></div>', + '</div>' + ].join('') + + const factory = new TemplateFactory({ + template, + content: { + '.foo': 'bar', + '.foo2': 'bar2' + } + }) + + const html = selector => factory.toHtml().querySelector(selector).textContent + expect(html('.foo')).toEqual('bar') + expect(html('.foo2')).toEqual('bar2') + factory.changeContent({ + '.foo': 'test', + '.wrong': 'wrong' + }) + + expect(html('.foo')).toEqual('test') + expect(html('.foo2')).toEqual('bar2') + }) + }) +}) |