From 3129ff075b36e3eb59205ee2c51682fa6a29bda4 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Mon, 29 Nov 2021 14:27:03 +0200 Subject: BaseComponent: add a couple more tests (#35410) Co-authored-by: XhmikosR --- js/tests/unit/base-component.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/base-component.spec.js b/js/tests/unit/base-component.spec.js index b8ec83f12..460a1b9a0 100644 --- a/js/tests/unit/base-component.spec.js +++ b/js/tests/unit/base-component.spec.js @@ -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) }) @@ -74,6 +81,17 @@ 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', () => { -- cgit v1.2.3 From 1692fc6b4b3ac25261fcd1353670bb58b8bc8049 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Mon, 29 Nov 2021 14:32:11 +0200 Subject: Alert: add a couple more tests (#35419) Co-authored-by: XhmikosR --- js/tests/unit/alert.spec.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index cdda997c9..eb3d3e5fa 100644 --- a/js/tests/unit/alert.spec.js +++ b/js/tests/unit/alert.spec.js @@ -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 = '
' + + 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 = '
' + + 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', () => { -- cgit v1.2.3 From 5739bf76371cb7be36598ad201b587167349681b Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Wed, 13 Oct 2021 08:42:21 +0300 Subject: tests/browsers.js: remove unneeded export --- js/tests/browsers.js | 5 +---- js/tests/karma.conf.js | 8 ++------ 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'js/tests') diff --git a/js/tests/browsers.js b/js/tests/browsers.js index 665b26a2e..8adedc68b 100644 --- a/js/tests/browsers.js +++ b/js/tests/browsers.js @@ -74,9 +74,6 @@ const browsers = { } } -const browsersKeys = Object.keys(browsers) - module.exports = { - browsers, - browsersKeys + browsers } diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index d85f2441c..8d29dad63 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -8,11 +8,7 @@ const { babel } = require('@rollup/plugin-babel') const istanbul = require('rollup-plugin-istanbul') const { nodeResolve } = require('@rollup/plugin-node-resolve') const replace = require('@rollup/plugin-replace') - -const { - browsers, - browsersKeys -} = require('./browsers') +const { browsers } = require('./browsers') const ENV = process.env const BROWSERSTACK = Boolean(ENV.BROWSERSTACK) @@ -115,7 +111,7 @@ if (BROWSERSTACK) { } plugins.push('karma-browserstack-launcher', 'karma-jasmine-html-reporter') conf.customLaunchers = browsers - conf.browsers = browsersKeys + conf.browsers = Object.keys(browsers) reporters.push('BrowserStack', 'kjhtml') } else if (JQUERY_TEST) { frameworks.push('detectBrowsers') -- cgit v1.2.3 From eb54e1a1ce9d0080a65eb7a8532503a399e506ee Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Thu, 14 Oct 2021 18:16:54 +0300 Subject: tests: tweak Jasmine's matchers usage Use: * toBeNull * toEqual * toBeTrue * toBeFalse * toHaveSize * toHaveClass --- js/tests/README.md | 2 +- js/tests/unit/alert.spec.js | 14 +-- js/tests/unit/base-component.spec.js | 6 +- js/tests/unit/button.spec.js | 20 ++-- js/tests/unit/carousel.spec.js | 44 ++++----- js/tests/unit/collapse.spec.js | 140 ++++++++++++++-------------- js/tests/unit/dom/data.spec.js | 7 +- js/tests/unit/dom/event-handler.spec.js | 16 ++-- js/tests/unit/dom/manipulator.spec.js | 8 +- js/tests/unit/dom/selector-engine.spec.js | 2 +- js/tests/unit/dropdown.spec.js | 126 ++++++++++++------------- js/tests/unit/jquery.spec.js | 2 +- js/tests/unit/modal.spec.js | 26 +++--- js/tests/unit/offcanvas.spec.js | 54 +++++------ js/tests/unit/popover.spec.js | 8 +- js/tests/unit/scrollspy.spec.js | 28 +++--- js/tests/unit/tab.spec.js | 62 ++++++------ js/tests/unit/toast.spec.js | 26 +++--- js/tests/unit/tooltip.spec.js | 72 +++++++------- js/tests/unit/util/backdrop.spec.js | 34 +++---- js/tests/unit/util/focustrap.spec.js | 4 +- js/tests/unit/util/index.spec.js | 86 ++++++++--------- js/tests/unit/util/scrollbar.spec.js | 60 ++++++------ js/tests/unit/util/template-factory.spec.js | 28 +++--- 24 files changed, 438 insertions(+), 437 deletions(-) (limited to 'js/tests') diff --git a/js/tests/README.md b/js/tests/README.md index 1e96a6b5d..ca99c0ede 100644 --- a/js/tests/README.md +++ b/js/tests/README.md @@ -35,7 +35,7 @@ Currently we're aiming for at least 90% test coverage for our code. To ensure yo describe('getInstance', () => { it('should return null if there is no instance', () => { // Make assertion - expect(Tab.getInstance(fixtureEl)).toEqual(null) + expect(Tab.getInstance(fixtureEl)).toBeNull() }) it('should return this instance', () => { diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index eb3d3e5fa..210ae9a25 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() }) @@ -225,7 +225,7 @@ describe('Alert', () => { const div = fixtureEl.querySelector('div') - expect(Alert.getInstance(div)).toEqual(null) + expect(Alert.getInstance(div)).toBeNull() }) }) @@ -246,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 460a1b9a0..9fe4e72d7 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)) }) }) @@ -141,7 +141,7 @@ describe('Base Component', () => { const div = fixtureEl.querySelector('div') - expect(DummyClass.getInstance(div)).toEqual(null) + expect(DummyClass.getInstance(div)).toBeNull() }) }) describe('getOrCreateInstance', () => { @@ -157,7 +157,7 @@ describe('Base Component', () => { fixtureEl.innerHTML = '
' 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 e24ff5cb0..30e62f0b3 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 a138f3ad5..a4b440c89 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() }) @@ -285,7 +285,7 @@ describe('Carousel', () => { carousel.prev() setTimeout(() => { - expect(firstElement.classList.contains('active')).toEqual(true) + expect(firstElement).toHaveClass('active') done() }, 10) }) @@ -368,7 +368,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 +413,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 +453,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 +492,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 +632,7 @@ describe('Carousel', () => { const doneTest = () => { setTimeout(() => { - expect(slidEvent).toEqual(false) + expect(slidEvent).toBeFalse() done() }, 20) } @@ -665,7 +665,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 +700,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 +761,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 +859,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 +885,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 +910,7 @@ describe('Carousel', () => { carousel.pause(event) expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(false) + expect(carousel._isPaused).toBeFalse() }) }) @@ -1175,7 +1175,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 +1292,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() }) }) @@ -1313,7 +1313,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 +1322,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 }) @@ -1441,7 +1441,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) @@ -1465,7 +1465,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) @@ -1488,7 +1488,7 @@ describe('Carousel', () => { next.click() setTimeout(() => { - expect(item2.classList.contains('active')).toEqual(true) + expect(item2).toHaveClass('active') done() }, 10) }) diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index 89d20a6d8..fa8024f6e 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() }) @@ -307,16 +307,16 @@ 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() }) @@ -359,7 +359,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 +440,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 +489,7 @@ describe('Collapse', () => { collapse.dispose() - expect(Collapse.getInstance(collapseEl)).toEqual(null) + expect(Collapse.getInstance(collapseEl)).toBeNull() }) }) @@ -508,8 +508,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 +530,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 +552,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 +575,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 +597,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 +625,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 +650,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 +684,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 +733,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 +815,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 +825,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 +860,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 +961,7 @@ describe('Collapse', () => { const div = fixtureEl.querySelector('div') - expect(Collapse.getInstance(div)).toEqual(null) + expect(Collapse.getInstance(div)).toBeNull() }) }) @@ -982,7 +982,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 +991,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 +1015,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 2560caff7..bf389cded 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,6 +60,7 @@ 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) }) @@ -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 19d63492b..4772d892e 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 61ffe7455..963ee5989 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 09c85a88a..3df753b72 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) }) }) diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index f099e9990..0765768d4 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -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() }) @@ -1072,7 +1072,7 @@ describe('Dropdown', () => { btnDropdown.addEventListener('shown.bs.dropdown', () => { expect(dropdown._popper).toBeNull() - expect(dropdownMenu.getAttribute('style')).toEqual(null, 'no inline style applied by Popper') + expect(dropdownMenu.getAttribute('style')).toBeNull() done() }) @@ -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')) }) @@ -1734,7 +1734,7 @@ describe('Dropdown', () => { input.focus() input.dispatchEvent(keydownEscape) - expect(triggerDropdown.classList.contains('show')).toEqual(false, 'dropdown menu is not shown') + expect(triggerDropdown).not.toHaveClass('show') done() }) @@ -1771,7 +1771,7 @@ describe('Dropdown', () => { setTimeout(() => { expect(dropdown.toggle).not.toHaveBeenCalled() - expect(triggerDropdown.classList.contains('show')).toEqual(false) + expect(triggerDropdown).not.toHaveClass('show') done() }, 20) }) @@ -1823,7 +1823,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 +1833,7 @@ describe('Dropdown', () => { }) dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) + expect(dropdownToggle).not.toHaveClass('show') done() })) @@ -1854,7 +1854,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 +1864,7 @@ describe('Dropdown', () => { }) dropdownToggle.addEventListener('hidden.bs.dropdown', () => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) + expect(dropdownToggle).not.toHaveClass('show') done() }) @@ -1885,7 +1885,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 +1963,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() }) }) @@ -1984,7 +1984,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 +1993,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 +2043,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 +2053,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 +2108,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 1c9258bd1..16781a351 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 613b0a0a1..dd501aa7b 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -234,12 +234,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() }) @@ -474,7 +474,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -501,7 +501,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -529,7 +529,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(false) + expect(modal._isShown).toBeFalse() done() }, 10) } @@ -555,7 +555,7 @@ describe('Modal', () => { const shownCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -719,7 +719,7 @@ describe('Modal', () => { const hideCallback = () => { setTimeout(() => { - expect(modal._isShown).toEqual(true) + expect(modal._isShown).toBeTrue() done() }, 10) } @@ -1026,7 +1026,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() @@ -1061,7 +1061,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', () => { @@ -1161,7 +1161,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) }) @@ -1170,13 +1170,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', () => { @@ -1194,7 +1194,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 3eda50520..e262a9a3a 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,7 +101,7 @@ describe('Offcanvas', () => { document.dispatchEvent(keyDownEsc) - expect(offCanvas._config.keyboard).toBe(false) + expect(offCanvas._config.keyboard).toBeFalse() expect(offCanvas.hide).not.toHaveBeenCalled() }) }) @@ -116,10 +116,10 @@ describe('Offcanvas', () => { 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', () => { @@ -131,10 +131,10 @@ describe('Offcanvas', () => { 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', () => { @@ -149,9 +149,9 @@ 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', () => { @@ -204,7 +204,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 +256,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 +274,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 +292,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 +384,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 +458,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 +473,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() }) @@ -559,7 +559,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 +665,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 +706,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 +715,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 +739,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 b3bba3180..ba23ec024 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -196,7 +196,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() }) @@ -314,7 +314,7 @@ describe('Popover', () => { const popoverEl = fixtureEl.querySelector('a') - expect(Popover.getInstance(popoverEl)).toEqual(null) + expect(Popover.getInstance(popoverEl)).toBeNull() }) }) @@ -335,7 +335,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) }) @@ -344,7 +344,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 f64b8f1dc..1b713757e 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() @@ -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() }) @@ -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 05f9db2ec..ade0f3570 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -51,7 +51,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 +75,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 +99,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() }) @@ -119,7 +119,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() }) @@ -139,7 +139,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() }) @@ -248,7 +248,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 +321,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 +417,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 +448,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 +469,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 +495,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 +529,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 +553,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 +585,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 +615,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 +653,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 +679,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 +698,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 4b84bf2c5..9541bcdee 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) } @@ -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 4a7022234..9b87f75b2 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() }) @@ -229,11 +229,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 +354,7 @@ describe('Tooltip', () => { tooltip.dispose() - expect(Tooltip.getInstance(tooltipEl)).toEqual(null) + expect(Tooltip.getInstance(tooltipEl)).toBeNull() expect(removeEventSpy.calls.allArgs()).toEqual(expectedArgs) }) @@ -369,8 +369,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() }) @@ -465,11 +465,11 @@ describe('Tooltip', () => { }) tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-auto')).toEqual(true) + expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') }) tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-auto')).toEqual(true) + expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') expect(tooltip.getTipElement().getAttribute('data-popper-placement')).toEqual('bottom') done() }) @@ -585,7 +585,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() }) @@ -669,7 +669,7 @@ describe('Tooltip', () => { setTimeout(() => { expect(tooltip.show).toHaveBeenCalled() - expect(document.querySelectorAll('.tooltip').length).toEqual(0) + expect(document.querySelectorAll('.tooltip')).toHaveSize(0) done() }, 200) @@ -688,17 +688,17 @@ 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(document.querySelectorAll('.tooltip').length).toEqual(1) + expect(tooltip.getTipElement()).toHaveClass('show') + expect(document.querySelectorAll('.tooltip')).toHaveSize(1) done() }, 200) }, 0) @@ -751,17 +751,17 @@ 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) @@ -809,7 +809,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 +827,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,7 +848,7 @@ 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() }) @@ -992,7 +992,7 @@ describe('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,7 +1001,7 @@ describe('Tooltip', () => { const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) - expect(tooltip.isWithContent()).toEqual(false) + expect(tooltip.isWithContent()).toBeFalse() }) }) @@ -1047,8 +1047,8 @@ describe('Tooltip', () => { 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') }) @@ -1060,10 +1060,10 @@ describe('Tooltip', () => { tooltip.show() const tip = () => tooltip.getTipElement() - expect(tip().classList.contains('show')).toEqual(true) + expect(tip()).toHaveClass('show') tooltip.setContent({ '.tooltip-inner': 'foo' }) - expect(tip().classList.contains('show')).toEqual(true) + expect(tip()).toHaveClass('show') expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo') }) @@ -1074,10 +1074,10 @@ describe('Tooltip', () => { const tooltip = new Tooltip(tooltipEl) const tip = () => tooltip.getTipElement() - expect(tip().classList.contains('show')).toEqual(false) + expect(tip()).not.toHaveClass('show') tooltip.setContent({ '.tooltip-inner': 'foo' }) - expect(tip().classList.contains('show')).toEqual(false) + expect(tip()).not.toHaveClass('show') expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo') }) }) @@ -1092,7 +1092,7 @@ describe('Tooltip', () => { }) tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-auto')).toEqual(true) + expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') done() }) @@ -1108,7 +1108,7 @@ describe('Tooltip', () => { }) tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement().classList.contains('bs-tooltip-auto')).toEqual(true) + expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') done() }) @@ -1207,7 +1207,7 @@ describe('Tooltip', () => { tooltip.setContent({ '.tooltip': content }) expect(tooltip.getTipElement().querySelector('div').id).toEqual('childContent') - expect(tooltip.getTipElement().querySelector('button')).toEqual(null) + expect(tooltip.getTipElement().querySelector('button')).toBeNull() }) it('should add text content', () => { @@ -1260,7 +1260,7 @@ describe('Tooltip', () => { const div = fixtureEl.querySelector('div') - expect(Tooltip.getInstance(div)).toEqual(null) + expect(Tooltip.getInstance(div)).toBeNull() }) }) @@ -1334,7 +1334,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) }) @@ -1343,7 +1343,7 @@ 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' }) diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 818ddf221..5a62ab8b1 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -30,13 +30,13 @@ describe('Backdrop', () => { }) 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() @@ -50,9 +50,9 @@ describe('Backdrop', () => { }) 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() }) }) @@ -64,12 +64,12 @@ describe('Backdrop', () => { }) 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,11 +86,11 @@ 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() }) }) @@ -105,7 +105,7 @@ describe('Backdrop', () => { instance.show() instance.hide(() => { - expect(elem.classList.contains(CLASS_NAME_SHOW)).toEqual(false) + expect(elem).not.toHaveClass(CLASS_NAME_SHOW) done() }) }) @@ -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() }) }) diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index 99bc95fca..12fd46ecf 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -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 ccfe5e2c2..e0220091e 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,9 +427,9 @@ 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 = [ @@ -446,12 +446,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 +463,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 +475,7 @@ describe('Util', () => { const div = fixtureEl.querySelector('#input') - expect(Util.isDisabled(div)).toEqual(true) + expect(Util.isDisabled(div)).toBeTrue() }) }) @@ -493,7 +493,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 +505,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 +532,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 +569,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 +628,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 280adb8e5..ee17d3c7b 100644 --- a/js/tests/unit/util/scrollbar.spec.js +++ b/js/tests/unit/util/scrollbar.spec.js @@ -58,9 +58,9 @@ describe('ScrollBar', () => { const result = new ScrollBarHelper().isOverflowing() if (isScrollBarHidden()) { - expect(result).toEqual(false) + expect(result).toBeFalse() } else { - expect(result).toEqual(true) + expect(result).toBeTrue() } }) @@ -73,7 +73,7 @@ describe('ScrollBar', () => { const scrollBar = new ScrollBarHelper() const result = scrollBar.isOverflowing() - expect(result).toEqual(false) + expect(result).toBeFalse() }) }) @@ -87,7 +87,7 @@ describe('ScrollBar', () => { const result = new ScrollBarHelper().getWidth() if (isScrollBarHidden()) { - expect(result).toBe(0) + expect(result).toEqual(0) } else { expect(result).toBeGreaterThan(1) } @@ -128,18 +128,18 @@ 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() }) @@ -159,16 +159,16 @@ 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() }) @@ -187,8 +187,8 @@ 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() }) @@ -232,8 +232,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() }) @@ -273,9 +273,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', () => { @@ -308,9 +308,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 +324,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 +344,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/template-factory.spec.js b/js/tests/unit/util/template-factory.spec.js index 842c480c2..dccf2a585 100644 --- a/js/tests/unit/util/template-factory.spec.js +++ b/js/tests/unit/util/template-factory.spec.js @@ -86,15 +86,15 @@ describe('TemplateFactory', () => { const factory = new TemplateFactory({ extraClass: 'testClass' }) - expect(factory.toHtml().classList.contains('testClass')).toBeTrue() + expect(factory.toHtml()).toHaveClass('testClass') }) it('should add extra classes', () => { const factory = new TemplateFactory({ extraClass: 'testClass testClass2' }) - expect(factory.toHtml().classList.contains('testClass')).toBeTrue() - expect(factory.toHtml().classList.contains('testClass2')).toBeTrue() + expect(factory.toHtml()).toHaveClass('testClass') + expect(factory.toHtml()).toHaveClass('testClass2') }) it('should resolve class if function is given', () => { @@ -105,7 +105,7 @@ describe('TemplateFactory', () => { } }) - expect(factory.toHtml().classList.contains('testClass')).toBeTrue() + expect(factory.toHtml()).toHaveClass('testClass') }) }) }) @@ -128,8 +128,8 @@ describe('TemplateFactory', () => { }) const html = factory.toHtml() - expect(html.querySelector('.foo').textContent).toBe('bar') - expect(html.querySelector('.foo2').textContent).toBe('bar2') + expect(html.querySelector('.foo').textContent).toEqual('bar') + expect(html.querySelector('.foo2').textContent).toEqual('bar2') }) it('should not fill template if selector not exists', () => { @@ -140,7 +140,7 @@ describe('TemplateFactory', () => { content: { '#bar': 'test' } }) - expect(factory.toHtml().outerHTML).toBe('
') + expect(factory.toHtml().outerHTML).toEqual('
') }) it('should remove template selector, if content is null', () => { @@ -151,7 +151,7 @@ describe('TemplateFactory', () => { content: { '#foo': null } }) - expect(factory.toHtml().outerHTML).toBe('
') + expect(factory.toHtml().outerHTML).toEqual('
') }) it('should resolve content if is function', () => { @@ -162,7 +162,7 @@ describe('TemplateFactory', () => { content: { '#foo': () => null } }) - expect(factory.toHtml().outerHTML).toBe('
') + expect(factory.toHtml().outerHTML).toEqual('
') }) it('if content is element and "config.html=false", should put content\'s textContent', () => { @@ -176,9 +176,9 @@ describe('TemplateFactory', () => { }) const fooEl = factory.toHtml().querySelector('#foo') - expect(fooEl.innerHTML).not.toBe(contentElement.innerHTML) - expect(fooEl.textContent).toBe(contentElement.textContent) - expect(fooEl.textContent).toBe('foobar') + 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', () => { @@ -192,8 +192,8 @@ describe('TemplateFactory', () => { }) const fooEl = factory.toHtml().querySelector('#foo') - expect(fooEl.innerHTML).toBe(contentElement.outerHTML) - expect(fooEl.textContent).toBe(contentElement.textContent) + expect(fooEl.innerHTML).toEqual(contentElement.outerHTML) + expect(fooEl.textContent).toEqual(contentElement.textContent) }) }) -- cgit v1.2.3 From f8f9dc3b5cfda049f38eb069b1ee008a3a6dd704 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 26 Nov 2021 09:16:59 +0200 Subject: tests: remove extra spaces, unneeded arrays and add missing newlines --- js/tests/unit/base-component.spec.js | 3 + js/tests/unit/carousel.spec.js | 5 +- js/tests/unit/collapse.spec.js | 87 +++++++++++++------------- js/tests/unit/dom/selector-engine.spec.js | 16 ++--- js/tests/unit/dropdown.spec.js | 6 +- js/tests/unit/modal.spec.js | 4 +- js/tests/unit/offcanvas.spec.js | 16 ++--- js/tests/unit/scrollspy.spec.js | 20 +++--- js/tests/unit/tab.spec.js | 18 ++++-- js/tests/unit/toast.spec.js | 2 +- js/tests/unit/tooltip.spec.js | 15 ++--- js/tests/unit/util/backdrop.spec.js | 6 +- js/tests/unit/util/component-functions.spec.js | 8 +-- js/tests/unit/util/focustrap.spec.js | 14 ++--- js/tests/unit/util/index.spec.js | 1 + js/tests/unit/util/scrollbar.spec.js | 42 +++++-------- js/tests/unit/util/swipe.spec.js | 14 ++--- js/tests/unit/util/template-factory.spec.js | 25 ++++---- 18 files changed, 145 insertions(+), 157 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/base-component.spec.js b/js/tests/unit/base-component.spec.js index 9fe4e72d7..9e0b872d4 100644 --- a/js/tests/unit/base-component.spec.js +++ b/js/tests/unit/base-component.spec.js @@ -66,6 +66,7 @@ describe('Base Component', () => { }) }) }) + describe('Public Methods', () => { describe('constructor', () => { it('should accept element, either passed as a CSS selector or DOM element', () => { @@ -93,6 +94,7 @@ describe('Base Component', () => { expect(selectorInstance._element).not.toBeDefined() }) }) + describe('dispose', () => { it('should dispose an component', () => { createInstance() @@ -144,6 +146,7 @@ describe('Base Component', () => { expect(DummyClass.getInstance(div)).toBeNull() }) }) + describe('getOrCreateInstance', () => { it('should return an instance', () => { createInstance() diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index a4b440c89..66f4a8367 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -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() @@ -1153,6 +1151,7 @@ describe('Carousel', () => { }) }) }) + describe('rtl function', () => { it('"_directionToOrder" and "_orderToDirection" must return the right results', () => { fixtureEl.innerHTML = '
' diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index fa8024f6e..a7635006f 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -268,31 +268,31 @@ describe('Collapse', () => { it('should be able to handle toggling of other children siblings', done => { fixtureEl.innerHTML = [ '
', - '
', - ' ', - '
', - '
', - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
content
', - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
content
', - '
', - '
', - '
', + '
', + ' ', + '
', + '
', + '
', + '
', + '
', + '
', + ' ', + '
', + '
', + '
content
', + '
', + '
', + '
', + '
', + ' ', + '
', + '
', + '
content
', + '
', + '
', '
', - '
', + '
', + '
', '
' ].join('') @@ -322,31 +322,32 @@ describe('Collapse', () => { parentBtn.click() }) + it('should not change tab tabpanels descendants on accordion', done => { fixtureEl.innerHTML = [ '
', - '
', - '

', - ' ', - '

', - '
', - '
', - ' ', - ' ', + '
', + '

', + ' ', + '

', + '
', + '
', + ' ', + ' ', '
', - '
' + '
', + '
', + '
' ].join('') const el = fixtureEl.querySelector('#collapseOne') diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index 3df753b72..005e92704 100644 --- a/js/tests/unit/dom/selector-engine.spec.js +++ b/js/tests/unit/dom/selector-engine.spec.js @@ -197,9 +197,7 @@ describe('SelectorEngine', () => { }) it('should return not return elements with negative tab index', () => { - fixtureEl.innerHTML = [ - '' - ].join('') + fixtureEl.innerHTML = '' const expectedElements = [] @@ -207,9 +205,7 @@ describe('SelectorEngine', () => { }) it('should return contenteditable elements', () => { - fixtureEl.innerHTML = [ - '
lorem
' - ].join('') + fixtureEl.innerHTML = '
lorem
' const expectedElements = [fixtureEl.querySelector('[contenteditable="true"]')] @@ -217,9 +213,7 @@ describe('SelectorEngine', () => { }) it('should not return disabled elements', () => { - fixtureEl.innerHTML = [ - '' - ].join('') + fixtureEl.innerHTML = '' const expectedElements = [] @@ -227,9 +221,7 @@ describe('SelectorEngine', () => { }) it('should not return invisible elements', () => { - fixtureEl.innerHTML = [ - '' - ].join('') + fixtureEl.innerHTML = '' const expectedElements = [] diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 0765768d4..9c0eae6d8 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1750,8 +1750,8 @@ describe('Dropdown', () => { ' Secondary link', ' Something else here', '
', - ' Another link', - '
', + ' Another link', + '
', '
', '' ] @@ -1783,7 +1783,7 @@ describe('Dropdown', () => { ' ', ' ', + ' ', ' ', '' ] diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index dd501aa7b..5729942e5 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 = [ - '' - ].join('') + fixtureEl.innerHTML = '' spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index e262a9a3a..191a9f801 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -108,10 +108,7 @@ describe('Offcanvas', () => { describe('config', () => { it('should have default values', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) @@ -123,10 +120,7 @@ describe('Offcanvas', () => { }) it('should read data attributes and override default config', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) @@ -138,10 +132,7 @@ describe('Offcanvas', () => { }) it('given a config object must override data attributes', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl, { @@ -154,6 +145,7 @@ describe('Offcanvas', () => { expect(offCanvas._config.scroll).toBeFalse() }) }) + describe('options', () => { it('if scroll is enabled, should allow body to scroll while offcanvas is open', done => { fixtureEl.innerHTML = '
' diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index 1b713757e..5c044e697 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -73,8 +73,8 @@ describe('ScrollSpy', () => { ' ', '', '
', - '
', - '
', + '
', + '
', '
' ].join('') @@ -175,16 +175,16 @@ describe('ScrollSpy', () => { fixtureEl.innerHTML = [ '', '', '
', - '
', - '
', - '
', + '
', + '
', + '
', '
' ].join('') diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index ade0f3570..43d20438e 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 = [ - '', - '
' + '', + '
    ', + '
  • ', + '
' ].join('') const tabEl = fixtureEl.querySelector('[href="#home"]') @@ -112,7 +116,10 @@ describe('Tab', () => { ' ', ' ', ' ', '', - '
' + '
', + '
', + '
', + '
' ].join('') const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index 9541bcdee..c4ea43808 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -393,7 +393,7 @@ describe('Toast', () => { '
', ' a simple toast', '
', - ' ' + '' ].join('') const toastEl = fixtureEl.querySelector('.toast') diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 9b87f75b2..d8ca21a63 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -416,13 +416,14 @@ describe('Tooltip', () => { }) it('should show a tooltip when hovering a children element', done => { - fixtureEl.innerHTML = - '' + - '' + - '' + - '' + - '' + + fixtureEl.innerHTML = [ + '', + ' ', + ' ', + ' ', + ' ', '' + ].join('') const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1201,7 +1202,7 @@ describe('Tooltip', () => { const content = [ '
', - ' ', + ' ', '
' ].join('') diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 5a62ab8b1..4fa9e5436 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -232,6 +232,7 @@ describe('Backdrop', () => { }) }) }) + describe('Config', () => { describe('rootElement initialization', () => { it('Should be appended on "document.body" by default', done => { @@ -258,10 +259,7 @@ describe('Backdrop', () => { }) it('Should appended on any element given by the proper config', done => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const wrapper = fixtureEl.querySelector('#wrapper') const instance = new Backdrop({ diff --git a/js/tests/unit/util/component-functions.spec.js b/js/tests/unit/util/component-functions.spec.js index edaedd32e..16f910a63 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 = [ '
', - ' ', + ' ', '
' ].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 = [ '
', - ' ', + ' ', '
' ].join('') @@ -73,7 +73,7 @@ describe('Plugin functions', () => { it('if data-bs-dismiss="PluginName" is disabled, must not trigger function', () => { fixtureEl.innerHTML = [ '
', - ' ', + ' ', '
' ].join('') @@ -90,7 +90,7 @@ describe('Plugin functions', () => { it('should prevent default when the trigger is or ', () => { fixtureEl.innerHTML = [ '
', - ' ', + ' ', '
' ].join('') diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index 12fd46ecf..52a757397 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 = [ 'outside', '
', - ' inside', + ' inside', '
' ].join('') @@ -78,9 +78,9 @@ describe('FocusTrap', () => { fixtureEl.innerHTML = [ 'outside', '
', - ' first', - ' inside', - ' last', + ' first', + ' inside', + ' last', '
' ].join('') @@ -115,9 +115,9 @@ describe('FocusTrap', () => { fixtureEl.innerHTML = [ 'outside', '
', - ' first', - ' inside', - ' last', + ' first', + ' inside', + ' last', '
' ].join('') diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index e0220091e..a9e446c9d 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -431,6 +431,7 @@ describe('Util', () => { expect(Util.isDisabled(el('#select'))).toBeFalse() expect(Util.isDisabled(el('#input'))).toBeFalse() }) + it('should return true if the element has disabled attribute', () => { fixtureEl.innerHTML = [ '
', diff --git a/js/tests/unit/util/scrollbar.spec.js b/js/tests/unit/util/scrollbar.spec.js index ee17d3c7b..c42234c4f 100644 --- a/js/tests/unit/util/scrollbar.spec.js +++ b/js/tests/unit/util/scrollbar.spec.js @@ -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,9 +54,7 @@ describe('ScrollBar', () => { it('should return true if body is overflowing', () => { document.documentElement.style.overflowY = 'scroll' document.body.style.overflowY = 'scroll' - fixtureEl.innerHTML = [ - '
' - ].join('') + fixtureEl.innerHTML = '
' const result = new ScrollBarHelper().isOverflowing() if (isScrollBarHidden()) { @@ -67,9 +67,7 @@ describe('ScrollBar', () => { it('should return false if body is not overflowing', () => { doc.style.overflowY = 'hidden' document.body.style.overflowY = 'hidden' - fixtureEl.innerHTML = [ - '
' - ].join('') + fixtureEl.innerHTML = '
' const scrollBar = new ScrollBarHelper() const result = scrollBar.isOverflowing() @@ -81,9 +79,7 @@ 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 = [ - '
' - ].join('') + fixtureEl.innerHTML = '
' const result = new ScrollBarHelper().getWidth() if (isScrollBarHidden()) { @@ -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 = [ - '
' - ].join('') + fixtureEl.innerHTML = '
' 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 = [ - '
' + - '
', - '
', + '
', + '
', + '
', '
' ].join('') doc.style.overflowY = 'scroll' @@ -145,8 +139,8 @@ describe('ScrollBar', () => { it('should adjust the inline margin and padding of sticky elements', done => { fixtureEl.innerHTML = [ - '
' + - '
', + '
', + '
', '
' ].join('') doc.style.overflowY = 'scroll' @@ -173,9 +167,7 @@ describe('ScrollBar', () => { }) it('should not adjust the inline margin and padding of sticky and fixed elements when element do not have full width', () => { - fixtureEl.innerHTML = [ - '
' - ].join('') + fixtureEl.innerHTML = '
' const stickyTopEl = fixtureEl.querySelector('.sticky-top') const originalMargin = getMarginX(stickyTopEl) @@ -195,8 +187,8 @@ describe('ScrollBar', () => { 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 = [ - '
' + - '
', + '
', + '
', '
' ].join('') @@ -243,7 +235,7 @@ describe('ScrollBar', () => { fixtureEl.innerHTML = [ '' ].join('') @@ -283,7 +275,7 @@ describe('ScrollBar', () => { fixtureEl.innerHTML = [ '' ].join('') diff --git a/js/tests/unit/util/swipe.spec.js b/js/tests/unit/util/swipe.spec.js index 474e34f65..93131b8fd 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 = [ '' ].join('') - fixtureEl.innerHTML = '
' + cssStyle + fixtureEl.innerHTML = `
${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 index dccf2a585..0fdf87146 100644 --- a/js/tests/unit/util/template-factory.spec.js +++ b/js/tests/unit/util/template-factory.spec.js @@ -113,11 +113,11 @@ describe('TemplateFactory', () => { describe('Content', () => { it('add simple text content', () => { const template = [ - '
' + - '
' + - '
' + + '
', + '
', + '
', '
' - ].join(' ') + ].join('') const factory = new TemplateFactory({ template, @@ -245,14 +245,15 @@ describe('TemplateFactory', () => { expect(factory.hasContent()).toBeFalse() }) }) + describe('changeContent', () => { it('should change Content', () => { const template = [ - '
' + - '
' + - '
' + + '
', + '
', + '
', '
' - ].join(' ') + ].join('') const factory = new TemplateFactory({ template, @@ -276,11 +277,11 @@ describe('TemplateFactory', () => { it('should change only the given, content', () => { const template = [ - '
' + - '
' + - '
' + + '
', + '
', + '
', '
' - ].join(' ') + ].join('') const factory = new TemplateFactory({ template, -- cgit v1.2.3 From 11ce6c2dcd8aa31030aa1569dbee34d9b0372cbd Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 26 Nov 2021 10:09:12 +0200 Subject: tests: fix a few typos --- js/tests/unit/dom/data.spec.js | 2 +- js/tests/unit/tooltip.spec.js | 2 +- js/tests/unit/util/backdrop.spec.js | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/dom/data.spec.js b/js/tests/unit/dom/data.spec.js index bf389cded..e898cbba2 100644 --- a/js/tests/unit/dom/data.spec.js +++ b/js/tests/unit/dom/data.spec.js @@ -65,7 +65,7 @@ describe('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() diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index d8ca21a63..87f6c0a10 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -415,7 +415,7 @@ describe('Tooltip', () => { tooltip.show() }) - it('should show a tooltip when hovering a children element', done => { + it('should show a tooltip when hovering a child element', done => { fixtureEl.innerHTML = [ '', ' ', diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 4fa9e5436..430369380 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -23,7 +23,7 @@ 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 @@ -43,7 +43,7 @@ describe('Backdrop', () => { }) }) - 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 @@ -57,7 +57,7 @@ describe('Backdrop', () => { }) }) - 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 @@ -96,7 +96,7 @@ describe('Backdrop', () => { }) }) - it('should remove "show" class', done => { + it('should remove the "show" class', done => { const instance = new Backdrop({ isVisible: true, isAnimated: true @@ -110,7 +110,7 @@ describe('Backdrop', () => { }) }) - 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 @@ -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 @@ -235,7 +235,7 @@ 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 }) @@ -246,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' @@ -258,7 +258,7 @@ describe('Backdrop', () => { }) }) - it('Should appended on any element given by the proper config', done => { + it('should be appended on any element given by the proper config', done => { fixtureEl.innerHTML = '
' const wrapper = fixtureEl.querySelector('#wrapper') @@ -275,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' -- cgit v1.2.3 From e5d8256e42074fdaf4e7418cf2675023dfbb8fe0 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 26 Nov 2021 10:15:58 +0200 Subject: tests/unit/util/scrollbar.spec.js: rename function `parseInt` is a global one. --- js/tests/unit/util/scrollbar.spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/util/scrollbar.spec.js b/js/tests/unit/util/scrollbar.spec.js index c42234c4f..15f09c0b2 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') @@ -245,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() @@ -256,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) @@ -291,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) -- cgit v1.2.3 From 44a6cd724c0a5c5247492fdb8db7d4df4705641e Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 1 Dec 2021 14:53:56 +0200 Subject: Tooltip: remove leftover method (#35440) Remove a leftover after #32692 Co-authored-by: XhmikosR --- js/tests/unit/tooltip.spec.js | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 87f6c0a10..19eeca2f5 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -1083,40 +1083,6 @@ describe('Tooltip', () => { }) }) - describe('updateAttachment', () => { - it('should use end class name when right placement specified', done => { - fixtureEl.innerHTML = '
' - - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: 'right' - }) - - tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') - done() - }) - - tooltip.show() - }) - - it('should use start class name when left placement specified', done => { - fixtureEl.innerHTML = '' - - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: 'left' - }) - - tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip.getTipElement()).toHaveClass('bs-tooltip-auto') - done() - }) - - tooltip.show() - }) - }) - describe('setContent', () => { it('should do nothing if the element is null', () => { fixtureEl.innerHTML = '' -- cgit v1.2.3 From cab62af2e6ecddbadbf799e00f911c2b342d93b2 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 1 Dec 2021 15:10:10 +0200 Subject: Fix popover arrow & tooltip template after the `setContent` addition (#35441) --- js/tests/unit/popover.spec.js | 16 ++++++++++++++++ js/tests/unit/tooltip.spec.js | 15 +++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index ba23ec024..606d7370c 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 = 'BS twitter' + + 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 = 'BS twitter' diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 19eeca2f5..d261986c3 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -1081,6 +1081,21 @@ describe('Tooltip', () => { expect(tip()).not.toHaveClass('show') expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo') }) + + it('"setContent" should keep the initial template', () => { + fixtureEl.innerHTML = '' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + 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() + }) }) describe('setContent', () => { -- cgit v1.2.3 From 8b308b76f0ec826908ebe8b106688378f5d616a5 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 1 Dec 2021 16:49:02 +0200 Subject: Dropdown tests: Use a function to improve readability (#35448) --- js/tests/unit/dropdown.spec.js | 45 ++++++++++++------------------------------ 1 file changed, 13 insertions(+), 32 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 9c0eae6d8..bec0aae62 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1684,51 +1684,32 @@ 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) + test('ArrowDown', input) - expect(document.activeElement).toEqual(input, 'input still focused') - - textarea.focus() - textarea.dispatchEvent(keydownArrowDown) - - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + test('ArrowDown', textarea) // Key Escape input.focus() -- cgit v1.2.3 From fb5921dec49da37e9bab745d7319037e89e2f31e Mon Sep 17 00:00:00 2001 From: GeoSot Date: Sun, 10 Oct 2021 15:09:57 +0300 Subject: Dropdown: Merge `display='static'` & `isNavbar` functionality activating static popper with no styles attached --- js/tests/unit/dropdown.spec.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index bec0aae62..aec70063e 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -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 = [ '
' ].join('') @@ -1453,8 +1453,8 @@ describe('Carousel', () => { ' ', ' ', '
', - ' ', - '
', + ' ', '
' ].join('') @@ -1520,8 +1520,8 @@ describe('Carousel', () => { ' ', ' ', '
', - '
', - '
', + ' ', + ' ', '' ].join('') diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index a7635006f..327a68449 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -276,18 +276,18 @@ describe('Collapse', () => { '
', '
', '
', - ' ', + ' ', '
', '
', - '
content
', + '
content
', '
', '
', '
', '
', - ' ', + ' ', '
', '
', - '
content
', + '
content
', '
', '
', '
', diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index aec70063e..037a6a5a9 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 = [ '', '' - ] + ].join('') const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const input = fixtureEl.querySelector('input') @@ -1735,7 +1735,7 @@ describe('Dropdown', () => { ' ', ' ', '' - ] + ].join('') const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const dropdown = new Dropdown(triggerDropdown) @@ -1767,7 +1767,7 @@ describe('Dropdown', () => { ' ', ' ', '' - ] + ].join('') const parent = fixtureEl.querySelector('.parent') const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') @@ -1826,7 +1826,7 @@ describe('Dropdown', () => { ' Dropdown item', ' ', '' - ] + ].join('') const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') @@ -1857,7 +1857,7 @@ describe('Dropdown', () => { ' Dropdown item', ' ', '' - ] + ].join('') const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') @@ -1888,7 +1888,7 @@ describe('Dropdown', () => { ' Dropdown item', ' ', '' - ] + ].join('') const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 9054c0f64..3feacf7b4 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -722,7 +722,7 @@ describe('Tooltip', () => { 'Trigger', 'the tooltip', '' - ] + ].join('') const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index a9e446c9d..ef6647e92 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -171,11 +171,10 @@ describe('Util', () => { describe('isElement', () => { it('should detect if the parameter is an element or not and return Boolean', () => { - fixtureEl.innerHTML = - [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = [ + '
', + '
' + ].join('') const el = fixtureEl.querySelector('#foo') @@ -199,11 +198,10 @@ describe('Util', () => { describe('getElement', () => { it('should try to parse element', () => { - fixtureEl.innerHTML = - [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = [ + '
', + '
' + ].join('') const el = fixtureEl.querySelector('div') -- cgit v1.2.3 From 886b940796b3595a03b44230ca8b78197c5ee1c5 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 10 Dec 2021 18:18:18 +0200 Subject: Extract Component config functionality to a separate class (#33872) Co-authored-by: XhmikosR --- js/tests/unit/util/config.spec.js | 78 +++++++++++++++++++++++++++++++++++++++ js/tests/unit/util/index.spec.js | 47 ----------------------- 2 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 js/tests/unit/util/config.spec.js (limited to 'js/tests') diff --git a/js/tests/unit/util/config.spec.js b/js/tests/unit/util/config.spec.js new file mode 100644 index 000000000..a8f8962ee --- /dev/null +++ b/js/tests/unit/util/config.spec.js @@ -0,0 +1,78 @@ +import Config from '../../../src/util/config' + +class DummyConfigClass extends Config { + static get NAME() { + return 'dummy' + } +} + +describe('Config', () => { + const name = 'dummy' + describe('NAME', () => { + it('should return plugin NAME', () => { + expect(DummyConfigClass.NAME).toEqual(name) + }) + }) + + describe('DefaultType', () => { + it('should return plugin default type', () => { + expect(DummyConfigClass.DefaultType).toEqual(jasmine.any(Object)) + }) + }) + + describe('Default', () => { + it('should return plugin defaults', () => { + expect(DummyConfigClass.Default).toEqual(jasmine.any(Object)) + }) + }) + + describe('typeCheckConfig', () => { + it('should check type of the config object', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(string|element)' + }) + const config = { + toggle: true, + parent: 777 + } + + const obj = new DummyConfigClass() + expect(() => { + obj._typeCheckConfig(config) + }).toThrowError(TypeError, obj.constructor.NAME.toUpperCase() + ': Option "parent" provided type "number" but expected type "(string|element)".') + }) + + it('should return null stringified when null is passed', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(null|element)' + }) + + const obj = new DummyConfigClass() + const config = { + toggle: true, + parent: null + } + + obj._typeCheckConfig(config) + expect().nothing() + }) + + it('should return undefined stringified when undefined is passed', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(undefined|element)' + }) + + const obj = new DummyConfigClass() + const config = { + toggle: true, + parent: undefined + } + + obj._typeCheckConfig(config) + expect().nothing() + }) + }) +}) diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index ef6647e92..52e64faa9 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -223,53 +223,6 @@ describe('Util', () => { }) }) - describe('typeCheckConfig', () => { - const namePlugin = 'collapse' - - it('should check type of the config object', () => { - const defaultType = { - toggle: 'boolean', - parent: '(string|element)' - } - const config = { - toggle: true, - parent: 777 - } - - expect(() => { - Util.typeCheckConfig(namePlugin, config, defaultType) - }).toThrowError(TypeError, 'COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".') - }) - - it('should return null stringified when null is passed', () => { - const defaultType = { - toggle: 'boolean', - parent: '(null|element)' - } - const config = { - toggle: true, - parent: null - } - - Util.typeCheckConfig(namePlugin, config, defaultType) - expect().nothing() - }) - - it('should return undefined stringified when undefined is passed', () => { - const defaultType = { - toggle: 'boolean', - parent: '(undefined|element)' - } - const config = { - toggle: true, - parent: undefined - } - - Util.typeCheckConfig(namePlugin, config, defaultType) - expect().nothing() - }) - }) - describe('isVisible', () => { it('should return false if the element is not defined', () => { expect(Util.isVisible(null)).toBeFalse() -- cgit v1.2.3 From d40fae456e0273c7e8c98cbdd17c55fd5d69ec47 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 15 Dec 2021 10:41:31 +0200 Subject: Popover.js: Accept empty content through `data-bs-content` (#35514) Co-authored-by: XhmikosR --- js/tests/unit/popover.spec.js | 44 +++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index a2906ade7..a04bd21c6 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -1,4 +1,5 @@ import Popover from '../../src/popover' +import EventHandler from '../../src/dom/event-handler' import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' describe('Popover', () => { @@ -96,59 +97,74 @@ describe('Popover', () => { popover.show() }) - it('should show a popover with just content', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should show a popover with just content without having header', done => { + fixtureEl.innerHTML = 'Nice link' const popoverEl = fixtureEl.querySelector('a') const popover = new Popover(popoverEl, { - content: 'Popover content' + content: 'Some beautiful content :)' }) popoverEl.addEventListener('shown.bs.popover', () => { const popoverDisplayed = document.querySelector('.popover') expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content') + expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') done() }) popover.show() }) - it('should show a popover with just content without having header', done => { + it('should show a popover with just title without having body', done => { fixtureEl.innerHTML = 'Nice link' const popoverEl = fixtureEl.querySelector('a') const popover = new Popover(popoverEl, { - content: 'Some beautiful content :)' + title: 'Title which does not require content' }) popoverEl.addEventListener('shown.bs.popover', () => { const popoverDisplayed = document.querySelector('.popover') expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') + expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') done() }) popover.show() }) - it('should show a popover with just title without having body', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just title without having body using data-attribute to get config', done => { + fixtureEl.innerHTML = 'Nice link' const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - title: 'Title, which does not require content' - }) + const popover = new Popover(popoverEl) popoverEl.addEventListener('shown.bs.popover', () => { const popoverDisplayed = document.querySelector('.popover') expect(popoverDisplayed).not.toBeNull() expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title, which does not require content') + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') + done() + }) + + popover.show() + }) + + it('should NOT show a popover without `title` and `content`', done => { + fixtureEl.innerHTML = 'Nice link' + + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { animation: false }) + spyOn(EventHandler, 'trigger').and.callThrough() + + setTimeout(() => { + expect(EventHandler.trigger).not.toHaveBeenCalled() + expect(document.querySelector('.popover')).toBeNull() done() }) -- cgit v1.2.3 From 0d4213bde39bb4f2e2bc5a0df699dad82780efa3 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 10 Sep 2021 02:17:28 +0300 Subject: Carousel: move repeated code to a method --- js/tests/unit/carousel.spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index ce9cd0fbc..7b58b9de9 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -851,12 +851,12 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) spyOn(carousel, 'cycle') - spyOn(window, 'clearInterval') + spyOn(carousel, '_clearInterval') carousel.pause() expect(carousel.cycle).toHaveBeenCalledWith(true) - expect(window.clearInterval).toHaveBeenCalled() + expect(carousel._clearInterval).toHaveBeenCalled() expect(carousel._isPaused).toBeTrue() }) @@ -877,12 +877,12 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) spyOn(carousel, 'cycle') - spyOn(window, 'clearInterval') + spyOn(carousel, '_clearInterval') carousel.pause() expect(carousel.cycle).not.toHaveBeenCalled() - expect(window.clearInterval).toHaveBeenCalled() + expect(carousel._clearInterval).toHaveBeenCalled() expect(carousel._isPaused).toBeTrue() }) @@ -903,11 +903,11 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) const event = createEvent('mouseenter') - spyOn(window, 'clearInterval') + spyOn(carousel, '_clearInterval') carousel.pause(event) - expect(window.clearInterval).toHaveBeenCalled() + expect(carousel._clearInterval).toHaveBeenCalled() expect(carousel._isPaused).toBeFalse() }) }) -- cgit v1.2.3 From 0d054bb0f1484dbc0c778d3643e96e37ff46d708 Mon Sep 17 00:00:00 2001 From: "Patrick H. Lauke" Date: Wed, 5 Jan 2022 17:20:15 +0000 Subject: Remove explicit use of aria-hidden for offcanvas when closed (#35589) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove explicit use of aria-hidden & visibility for offcanvas when closed, handling it with css Co-authored-by: GeoSot Co-authored-by: Gaël Poupard --- js/tests/unit/offcanvas.spec.js | 59 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index f4b0b6482..f87527fb2 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -242,23 +242,46 @@ describe('Offcanvas', () => { expect(offCanvas.show).toHaveBeenCalled() }) - it('should call hide method if show class is present', () => { + it('should call hide method if show class is present', done => { fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - offCanvas.show() - expect(offCanvasEl).toHaveClass('show') - spyOn(offCanvas, 'hide') + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + spyOn(offCanvas, 'hide') - offCanvas.toggle() + offCanvas.toggle() - expect(offCanvas.hide).toHaveBeenCalled() + expect(offCanvas.hide).toHaveBeenCalled() + done() + }) + + offCanvas.show() }) }) describe('show', () => { + it('should add `showing` class during opening and `show` class on end', done => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) + + offCanvasEl.addEventListener('show.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('show') + }) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + done() + }) + + offCanvas.show() + expect(offCanvasEl).toHaveClass('showing') + }) + it('should do nothing if already shown', () => { fixtureEl.innerHTML = '
' @@ -353,6 +376,30 @@ describe('Offcanvas', () => { }) describe('hide', () => { + it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', done => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) + + offCanvasEl.addEventListener('hide.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + }) + + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('hiding') + expect(offCanvasEl).not.toHaveClass('show') + done() + }) + + offCanvas.show() + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + offCanvas.hide() + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('hiding') + }) + }) + it('should do nothing if already shown', () => { fixtureEl.innerHTML = '
' -- cgit v1.2.3 From 14c7dc1e886015f2ed845f0f8e88d3597694250f Mon Sep 17 00:00:00 2001 From: Ryan Berliner <22206986+RyanBerliner@users.noreply.github.com> Date: Thu, 13 Jan 2022 03:55:05 -0500 Subject: Fix: `isVisible` function behavior in case of a `
` element, on chrome 97 (#35682) --- js/tests/unit/util/index.spec.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 52e64faa9..9d8c5ed98 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -320,6 +320,42 @@ describe('Util', () => { expect(Util.isVisible(div)).toBeFalse() }) + + it('should return true if its a closed details element', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('#element') + + expect(Util.isVisible(div)).toBeTrue() + }) + + it('should return true if the element is visible inside an open details element', () => { + fixtureEl.innerHTML = [ + '
', + '
', + '
' + ].join('') + + const div = fixtureEl.querySelector('#element') + + expect(Util.isVisible(div)).toBeTrue() + }) + + it('should return true if the element is a visible summary in a closed details element', () => { + fixtureEl.innerHTML = [ + '
', + ' ', + ' ', + ' ', + '
' + ].join('') + + const element1 = fixtureEl.querySelector('#element-1') + const element2 = fixtureEl.querySelector('#element-2') + + expect(Util.isVisible(element1)).toBeTrue() + expect(Util.isVisible(element2)).toBeTrue() + }) }) describe('isDisabled', () => { -- cgit v1.2.3 From 62d86c07f81dfae632742dbf62633e767bac8edd Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 29 Oct 2021 10:38:35 +0300 Subject: Rename variables --- js/tests/helpers/fixture.js | 42 +++++++++++++++++++++--------------------- js/tests/karma.conf.js | 34 +++++++++++++++++----------------- 2 files changed, 38 insertions(+), 38 deletions(-) (limited to 'js/tests') diff --git a/js/tests/helpers/fixture.js b/js/tests/helpers/fixture.js index 02915af44..ccb2bb166 100644 --- a/js/tests/helpers/fixture.js +++ b/js/tests/helpers/fixture.js @@ -1,32 +1,32 @@ const fixtureId = 'fixture' export const getFixture = () => { - let fixtureEl = document.getElementById(fixtureId) - - if (!fixtureEl) { - fixtureEl = document.createElement('div') - fixtureEl.setAttribute('id', fixtureId) - fixtureEl.style.position = 'absolute' - fixtureEl.style.top = '-10000px' - fixtureEl.style.left = '-10000px' - fixtureEl.style.width = '10000px' - fixtureEl.style.height = '10000px' - document.body.append(fixtureEl) + let fixtureElement = document.getElementById(fixtureId) + + if (!fixtureElement) { + fixtureElement = document.createElement('div') + fixtureElement.setAttribute('id', fixtureId) + fixtureElement.style.position = 'absolute' + fixtureElement.style.top = '-10000px' + fixtureElement.style.left = '-10000px' + fixtureElement.style.width = '10000px' + fixtureElement.style.height = '10000px' + document.body.append(fixtureElement) } - return fixtureEl + return fixtureElement } export const clearFixture = () => { - const fixtureEl = getFixture() + const fixtureElement = getFixture() - fixtureEl.innerHTML = '' + fixtureElement.innerHTML = '' } -export const createEvent = (eventName, params = {}) => { +export const createEvent = (eventName, parameters = {}) => { const event = document.createEvent('Event') - event.initEvent(eventName, Boolean(params.bubbles), Boolean(params.cancelable)) + event.initEvent(eventName, Boolean(parameters.bubbles), Boolean(parameters.cancelable)) return event } @@ -34,8 +34,8 @@ export const jQueryMock = { elements: undefined, fn: {}, each(fn) { - for (const el of this.elements) { - fn.call(el) + for (const element of this.elements) { + fn.call(element) } } } @@ -43,8 +43,8 @@ export const jQueryMock = { export const clearBodyAndDocument = () => { const attributes = ['data-bs-padding-right', 'style'] - for (const attr of attributes) { - document.documentElement.removeAttribute(attr) - document.body.removeAttribute(attr) + for (const attribute of attributes) { + document.documentElement.removeAttribute(attribute) + document.body.removeAttribute(attribute) } } diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index 8d29dad63..a1b96d041 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -50,7 +50,7 @@ const detectBrowsers = { } } -const conf = { +const config = { basePath: '../..', port: 9876, colors: true, @@ -101,8 +101,8 @@ const conf = { } if (BROWSERSTACK) { - conf.hostname = ip.address() - conf.browserStack = { + config.hostname = ip.address() + config.browserStack = { username: ENV.BROWSER_STACK_USERNAME, accessKey: ENV.BROWSER_STACK_ACCESS_KEY, build: `bootstrap-${ENV.GITHUB_SHA ? ENV.GITHUB_SHA.slice(0, 7) + '-' : ''}${new Date().toISOString()}`, @@ -110,8 +110,8 @@ if (BROWSERSTACK) { retryLimit: 2 } plugins.push('karma-browserstack-launcher', 'karma-jasmine-html-reporter') - conf.customLaunchers = browsers - conf.browsers = Object.keys(browsers) + config.customLaunchers = browsers + config.browsers = Object.keys(browsers) reporters.push('BrowserStack', 'kjhtml') } else if (JQUERY_TEST) { frameworks.push('detectBrowsers') @@ -120,8 +120,8 @@ if (BROWSERSTACK) { 'karma-firefox-launcher', 'karma-detect-browsers' ) - conf.detectBrowsers = detectBrowsers - conf.files = [ + config.detectBrowsers = detectBrowsers + config.files = [ 'node_modules/jquery/dist/jquery.slim.min.js', { pattern: 'js/tests/unit/jquery.spec.js', @@ -137,8 +137,8 @@ if (BROWSERSTACK) { 'karma-coverage-istanbul-reporter' ) reporters.push('coverage-istanbul') - conf.detectBrowsers = detectBrowsers - conf.coverageIstanbulReporter = { + config.detectBrowsers = detectBrowsers + config.coverageIstanbulReporter = { dir: path.resolve(__dirname, '../coverage/'), reports: ['lcov', 'text-summary'], thresholds: { @@ -153,19 +153,19 @@ if (BROWSERSTACK) { } if (DEBUG) { - conf.hostname = ip.address() + config.hostname = ip.address() plugins.push('karma-jasmine-html-reporter') reporters.push('kjhtml') - conf.singleRun = false - conf.autoWatch = true + config.singleRun = false + config.autoWatch = true } } -conf.frameworks = frameworks -conf.plugins = plugins -conf.reporters = reporters +config.frameworks = frameworks +config.plugins = plugins +config.reporters = reporters module.exports = karmaConfig => { - conf.logLevel = karmaConfig.LOG_ERROR - karmaConfig.set(conf) + config.logLevel = karmaConfig.LOG_ERROR + karmaConfig.set(config) } -- cgit v1.2.3 From fa939951232b7066722e928b370fd5e56b373fba Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 16 Dec 2021 13:23:17 +0200 Subject: Event handler: replace deprecated `initEvent` --- js/tests/helpers/fixture.js | 5 +---- js/tests/unit/offcanvas.spec.js | 3 +-- js/tests/unit/util/backdrop.spec.js | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) (limited to 'js/tests') diff --git a/js/tests/helpers/fixture.js b/js/tests/helpers/fixture.js index ccb2bb166..5ad14e1db 100644 --- a/js/tests/helpers/fixture.js +++ b/js/tests/helpers/fixture.js @@ -24,10 +24,7 @@ export const clearFixture = () => { } export const createEvent = (eventName, parameters = {}) => { - const event = document.createEvent('Event') - - event.initEvent(eventName, Boolean(parameters.bubbles), Boolean(parameters.cancelable)) - return event + return new Event(eventName, parameters) } export const jQueryMock = { diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index f87527fb2..36ef45dce 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -191,8 +191,7 @@ describe('Offcanvas', () => { const offCanvasEl = fixtureEl.querySelector('div') const offCanvas = new Offcanvas(offCanvasEl, { backdrop: true }) - const clickEvent = document.createEvent('MouseEvents') - clickEvent.initEvent('mousedown', true, true) + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() offCanvasEl.addEventListener('shown.bs.offcanvas', () => { diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 430369380..f9903c832 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -169,8 +169,7 @@ describe('Backdrop', () => { } instance.show(() => { - const clickEvent = document.createEvent('MouseEvents') - clickEvent.initEvent('mousedown', true, true) + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) document.querySelector(CLASS_BACKDROP).dispatchEvent(clickEvent) endTest() }) -- cgit v1.2.3 From aa650f0f1e30279f0868433a4afab9c3efa93b2c Mon Sep 17 00:00:00 2001 From: GeoSot Date: Sun, 30 Jan 2022 14:30:04 +0200 Subject: tests: replace 'done' callback with 'Promise' to fix deprecation errors (#35659) Reference: https://jasmine.github.io/tutorials/async 'DEPRECATION: An asynchronous function called its 'done' callback more than once. This is a bug in the spec, beforeAll, beforeEach, afterAll, or afterEach function in question. This will be treated as an error in a future version. See for more information. --- js/tests/README.md | 28 +- js/tests/unit/alert.spec.js | 84 +- js/tests/unit/carousel.spec.js | 1208 ++++++------- js/tests/unit/collapse.spec.js | 1164 +++++++------ js/tests/unit/dom/event-handler.spec.js | 541 +++--- js/tests/unit/dom/manipulator.spec.js | 60 +- js/tests/unit/dropdown.spec.js | 2856 ++++++++++++++++--------------- js/tests/unit/jquery.spec.js | 32 +- js/tests/unit/modal.spec.js | 1362 ++++++++------- js/tests/unit/offcanvas.spec.js | 586 ++++--- js/tests/unit/popover.spec.js | 270 +-- js/tests/unit/scrollspy.spec.js | 796 ++++----- js/tests/unit/tab.spec.js | 914 +++++----- js/tests/unit/toast.spec.js | 678 ++++---- js/tests/unit/tooltip.spec.js | 1222 +++++++------ js/tests/unit/util/backdrop.spec.js | 428 ++--- js/tests/unit/util/focustrap.spec.js | 240 +-- js/tests/unit/util/index.spec.js | 165 +- js/tests/unit/util/scrollbar.spec.js | 9 +- js/tests/unit/util/swipe.spec.js | 204 +-- 20 files changed, 6715 insertions(+), 6132 deletions(-) (limited to 'js/tests') diff --git a/js/tests/README.md b/js/tests/README.md index ca99c0ede..79d05d444 100644 --- a/js/tests/README.md +++ b/js/tests/README.md @@ -50,22 +50,24 @@ describe('getInstance', () => { }) // Asynchronous test -it('should show a tooltip without the animation', done => { - fixtureEl.innerHTML = '' +it('should show a tooltip without the animation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - animation: false - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + animation: false + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tip = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tip = document.querySelector('.tooltip') - expect(tip).not.toBeNull() - expect(tip.classList.contains('fade')).toEqual(false) - done() - }) + expect(tip).not.toBeNull() + expect(tip.classList.contains('fade')).toEqual(false) + resolve() + }) - tooltip.show() + tooltip.show() + }) }) ``` diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index 210ae9a25..e2fe49246 100644 --- a/js/tests/unit/alert.spec.js +++ b/js/tests/unit/alert.spec.js @@ -63,60 +63,66 @@ describe('Alert', () => { }) describe('close', () => { - it('should close an alert', done => { - const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) - fixtureEl.innerHTML = '
' + it('should close an alert', () => { + return new Promise(resolve => { + const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) + fixtureEl.innerHTML = '
' - const alertEl = document.querySelector('.alert') - const alert = new Alert(alertEl) + const alertEl = document.querySelector('.alert') + const alert = new Alert(alertEl) - alertEl.addEventListener('closed.bs.alert', () => { - expect(document.querySelectorAll('.alert')).toHaveSize(0) - expect(spy).not.toHaveBeenCalled() - done() - }) + alertEl.addEventListener('closed.bs.alert', () => { + expect(document.querySelectorAll('.alert')).toHaveSize(0) + expect(spy).not.toHaveBeenCalled() + resolve() + }) - alert.close() + alert.close() + }) }) - it('should close alert with fade class', done => { - fixtureEl.innerHTML = '
' + it('should close alert with fade class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const alertEl = document.querySelector('.alert') - const alert = new Alert(alertEl) + const alertEl = document.querySelector('.alert') + const alert = new Alert(alertEl) - alertEl.addEventListener('transitionend', () => { - expect().nothing() - }) + alertEl.addEventListener('transitionend', () => { + expect().nothing() + }) - alertEl.addEventListener('closed.bs.alert', () => { - expect(document.querySelectorAll('.alert')).toHaveSize(0) - done() - }) + alertEl.addEventListener('closed.bs.alert', () => { + expect(document.querySelectorAll('.alert')).toHaveSize(0) + resolve() + }) - alert.close() + alert.close() + }) }) - it('should not remove alert if close event is prevented', done => { - fixtureEl.innerHTML = '
' + it('should not remove alert if close event is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const getAlert = () => document.querySelector('.alert') - const alertEl = getAlert() - const alert = new Alert(alertEl) + const getAlert = () => document.querySelector('.alert') + const alertEl = getAlert() + const alert = new Alert(alertEl) - alertEl.addEventListener('close.bs.alert', event => { - event.preventDefault() - setTimeout(() => { - expect(getAlert()).not.toBeNull() - done() - }, 10) - }) + alertEl.addEventListener('close.bs.alert', event => { + event.preventDefault() + setTimeout(() => { + expect(getAlert()).not.toBeNull() + resolve() + }, 10) + }) - alertEl.addEventListener('closed.bs.alert', () => { - throw new Error('should not fire closed event') - }) + alertEl.addEventListener('closed.bs.alert', () => { + throw new Error('should not fire closed event') + }) - alert.close() + alert.close() + }) }) }) diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index 7b58b9de9..1c91cebec 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -63,94 +63,100 @@ describe('Carousel', () => { expect(carouselByElement._element).toEqual(carouselEl) }) - it('should go to next item if right arrow key is pressed', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should go to next item if right arrow key is pressed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) + + spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) + expect(carousel._keydown).toHaveBeenCalled() + resolve() + }) - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, { - keyboard: true - }) - - spyOn(carousel, '_keydown').and.callThrough() + const keydown = createEvent('keydown') + keydown.key = 'ArrowRight' - carouselEl.addEventListener('slid.bs.carousel', () => { - expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) - expect(carousel._keydown).toHaveBeenCalled() - done() + carouselEl.dispatchEvent(keydown) }) - - const keydown = createEvent('keydown') - keydown.key = 'ArrowRight' - - carouselEl.dispatchEvent(keydown) }) - it('should go to previous item if left arrow key is pressed', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should go to previous item if left arrow key is pressed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, { - keyboard: true - }) + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) - spyOn(carousel, '_keydown').and.callThrough() + spyOn(carousel, '_keydown').and.callThrough() - carouselEl.addEventListener('slid.bs.carousel', () => { - expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1')) - expect(carousel._keydown).toHaveBeenCalled() - done() - }) + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1')) + expect(carousel._keydown).toHaveBeenCalled() + resolve() + }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowLeft' + const keydown = createEvent('keydown') + keydown.key = 'ArrowLeft' - carouselEl.dispatchEvent(keydown) + carouselEl.dispatchEvent(keydown) + }) }) - it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, { - keyboard: true - }) + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) - spyOn(carousel, '_keydown').and.callThrough() + spyOn(carousel, '_keydown').and.callThrough() - carouselEl.addEventListener('keydown', event => { - expect(carousel._keydown).toHaveBeenCalled() - expect(event.defaultPrevented).toBeFalse() - done() - }) + carouselEl.addEventListener('keydown', event => { + expect(carousel._keydown).toHaveBeenCalled() + expect(event.defaultPrevented).toBeFalse() + resolve() + }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - carouselEl.dispatchEvent(keydown) + carouselEl.dispatchEvent(keydown) + }) }) it('should ignore keyboard events within s and ', - ' ', - '' - ].join('') + it('should ignore keyboard events within s and ', + ' ', + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') - const textarea = fixtureEl.querySelector('textarea') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') + const textarea = fixtureEl.querySelector('textarea') + + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + input.focus() + const keydown = createEvent('keydown') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - input.focus() - const keydown = createEvent('keydown') + keydown.key = 'ArrowUp' + input.dispatchEvent(keydown) - keydown.key = 'ArrowUp' - input.dispatchEvent(keydown) + expect(document.activeElement).toEqual(input, 'input still focused') - expect(document.activeElement).toEqual(input, 'input still focused') + textarea.focus() + textarea.dispatchEvent(keydown) - textarea.focus() - textarea.dispatchEvent(keydown) + expect(document.activeElement).toEqual(textarea, 'textarea still focused') + resolve() + }) - expect(document.activeElement).toEqual(textarea, 'textarea still focused') - done() + triggerDropdown.click() }) - - triggerDropdown.click() }) - it('should skip disabled element when using keyboard navigation', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should skip disabled element when using keyboard navigation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydown) - triggerDropdown.dispatchEvent(keydown) + triggerDropdown.dispatchEvent(keydown) + triggerDropdown.dispatchEvent(keydown) - expect(document.activeElement).not.toHaveClass('disabled') - expect(document.activeElement.hasAttribute('disabled')).toBeFalse() - done() - }) + expect(document.activeElement).not.toHaveClass('disabled') + expect(document.activeElement.hasAttribute('disabled')).toBeFalse() + resolve() + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should skip hidden element when using keyboard navigation', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should skip hidden element when using keyboard navigation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydown) + triggerDropdown.dispatchEvent(keydown) - expect(document.activeElement).not.toHaveClass('d-none') - expect(document.activeElement.style.display).not.toEqual('none') - expect(document.activeElement.style.visibility).not.toEqual('hidden') + expect(document.activeElement).not.toHaveClass('d-none') + expect(document.activeElement.style.display).not.toEqual('none') + expect(document.activeElement.style.visibility).not.toEqual('hidden') - done() - }) + resolve() + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should focus next/previous element when using keyboard navigation', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should focus next/previous element when using keyboard navigation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const item1 = fixtureEl.querySelector('#item1') - const item2 = fixtureEl.querySelector('#item2') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const item1 = fixtureEl.querySelector('#item1') + const item2 = fixtureEl.querySelector('#item2') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - const keydownArrowDown = createEvent('keydown') - keydownArrowDown.key = 'ArrowDown' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + const keydownArrowDown = createEvent('keydown') + keydownArrowDown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydownArrowDown) - expect(document.activeElement).toEqual(item1, 'item1 is focused') + triggerDropdown.dispatchEvent(keydownArrowDown) + expect(document.activeElement).toEqual(item1, 'item1 is focused') - document.activeElement.dispatchEvent(keydownArrowDown) - expect(document.activeElement).toEqual(item2, 'item2 is focused') + document.activeElement.dispatchEvent(keydownArrowDown) + expect(document.activeElement).toEqual(item2, 'item2 is focused') - const keydownArrowUp = createEvent('keydown') - keydownArrowUp.key = 'ArrowUp' + const keydownArrowUp = createEvent('keydown') + keydownArrowUp.key = 'ArrowUp' - document.activeElement.dispatchEvent(keydownArrowUp) - expect(document.activeElement).toEqual(item1, 'item1 is focused') + document.activeElement.dispatchEvent(keydownArrowUp) + expect(document.activeElement).toEqual(item1, 'item1 is focused') - done() - }) + resolve() + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should open the dropdown and focus on the last item when using ArrowUp for the first time', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open the dropdown and focus on the last item when using ArrowUp for the first time', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const lastItem = fixtureEl.querySelector('#item2') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const lastItem = fixtureEl.querySelector('#item2') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - setTimeout(() => { - expect(document.activeElement).toEqual(lastItem, 'item2 is focused') - done() + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + setTimeout(() => { + expect(document.activeElement).toEqual(lastItem, 'item2 is focused') + resolve() + }) }) - }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowUp' - triggerDropdown.dispatchEvent(keydown) + const keydown = createEvent('keydown') + keydown.key = 'ArrowUp' + triggerDropdown.dispatchEvent(keydown) + }) }) - it('should open the dropdown and focus on the first item when using ArrowDown for the first time', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open the dropdown and focus on the first item when using ArrowDown for the first time', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const firstItem = fixtureEl.querySelector('#item1') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const firstItem = fixtureEl.querySelector('#item1') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - setTimeout(() => { - expect(document.activeElement).toEqual(firstItem, 'item1 is focused') - done() + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + setTimeout(() => { + expect(document.activeElement).toEqual(firstItem, 'item1 is focused') + resolve() + }) }) - }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydown) + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' + triggerDropdown.dispatchEvent(keydown) + }) }) - it('should not close the dropdown if the user clicks on a text field within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close the dropdown if the user clicks on a text field within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') - input.addEventListener('click', () => { - expect(triggerDropdown).toHaveClass('show') - done() - }) + input.addEventListener('click', () => { + expect(triggerDropdown).toHaveClass('show') + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown).toHaveClass('show') - input.dispatchEvent(createEvent('click')) - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + expect(triggerDropdown).toHaveClass('show') + input.dispatchEvent(createEvent('click')) + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should not close the dropdown if the user clicks on a textarea within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close the dropdown if the user clicks on a textarea within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const textarea = fixtureEl.querySelector('textarea') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const textarea = fixtureEl.querySelector('textarea') - textarea.addEventListener('click', () => { - expect(triggerDropdown).toHaveClass('show') - done() - }) + textarea.addEventListener('click', () => { + expect(triggerDropdown).toHaveClass('show') + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown).toHaveClass('show') - textarea.dispatchEvent(createEvent('click')) - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + expect(triggerDropdown).toHaveClass('show') + textarea.dispatchEvent(createEvent('click')) + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should close the dropdown if the user clicks on a text field that is not contained within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') - - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') + it('should close the dropdown if the user clicks on a text field that is not contained within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - triggerDropdown.addEventListener('hidden.bs.dropdown', () => { - expect().nothing() - done() - }) + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - input.dispatchEvent(createEvent('click', { - bubbles: true - })) - }) + triggerDropdown.addEventListener('hidden.bs.dropdown', () => { + expect().nothing() + resolve() + }) - triggerDropdown.click() - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + input.dispatchEvent(createEvent('click', { + bubbles: true + })) + }) - it('should ignore keyboard events for s and ', - ' ', - '' - ].join('') + triggerDropdown.click() + }) + }) + + it('should ignore keyboard events for s and ', + ' ', + '' + ].join('') + + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') + const textarea = fixtureEl.querySelector('textarea') + + 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 triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') - const textarea = fixtureEl.querySelector('textarea') - - 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' - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + // Key Space + test('Space', input) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - // Key Space - test('Space', input) + test('Space', textarea) - test('Space', textarea) + // Key ArrowUp + test('ArrowUp', input) - // Key ArrowUp - test('ArrowUp', input) + test('ArrowUp', textarea) - test('ArrowUp', textarea) + // Key ArrowDown + test('ArrowDown', input) - // Key ArrowDown - test('ArrowDown', input) + test('ArrowDown', textarea) - test('ArrowDown', textarea) + // Key Escape + input.focus() + input.dispatchEvent(keydownEscape) - // Key Escape - input.focus() - input.dispatchEvent(keydownEscape) + expect(triggerDropdown).not.toHaveClass('show') + resolve() + }) - expect(triggerDropdown).not.toHaveClass('show') - done() + triggerDropdown.click() }) - - triggerDropdown.click() }) - it('should not open dropdown if escape key was pressed on the toggle', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') - - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdown = new Dropdown(triggerDropdown) - const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]') - - spyOn(dropdown, 'toggle') + it('should not open dropdown if escape key was pressed on the toggle', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - // Key escape - button.focus() - // Key escape - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' - button.dispatchEvent(keydownEscape) + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdown = new Dropdown(triggerDropdown) + const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]') - setTimeout(() => { - expect(dropdown.toggle).not.toHaveBeenCalled() - expect(triggerDropdown).not.toHaveClass('show') - done() - }, 20) - }) + spyOn(dropdown, 'toggle') - it('should propagate escape key events if dropdown is closed', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') + // Key escape + button.focus() + // Key escape + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' + button.dispatchEvent(keydownEscape) - const parent = fixtureEl.querySelector('.parent') - const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + setTimeout(() => { + expect(dropdown.toggle).not.toHaveBeenCalled() + expect(triggerDropdown).not.toHaveClass('show') + resolve() + }, 20) + }) + }) + + it('should propagate escape key events if dropdown is closed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') + + const parent = fixtureEl.querySelector('.parent') + const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + + const parentKeyHandler = jasmine.createSpy('parentKeyHandler') + + parent.addEventListener('keydown', parentKeyHandler) + parent.addEventListener('keyup', () => { + expect(parentKeyHandler).toHaveBeenCalled() + resolve() + }) - const parentKeyHandler = jasmine.createSpy('parentKeyHandler') + const keydownEscape = createEvent('keydown', { bubbles: true }) + keydownEscape.key = 'Escape' + const keyupEscape = createEvent('keyup', { bubbles: true }) + keyupEscape.key = 'Escape' - parent.addEventListener('keydown', parentKeyHandler) - parent.addEventListener('keyup', () => { - expect(parentKeyHandler).toHaveBeenCalled() - done() + toggle.focus() + toggle.dispatchEvent(keydownEscape) + toggle.dispatchEvent(keyupEscape) }) - - const keydownEscape = createEvent('keydown', { bubbles: true }) - keydownEscape.key = 'Escape' - const keyupEscape = createEvent('keyup', { bubbles: true }) - keyupEscape.key = 'Escape' - - toggle.focus() - toggle.dispatchEvent(keydownEscape) - toggle.dispatchEvent(keyupEscape) }) - it('should close dropdown using `escape` button, and return focus to its trigger', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should close dropdown using `escape` button, and return focus to its trigger', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - toggle.addEventListener('shown.bs.dropdown', () => { - const keydownEvent = createEvent('keydown', { bubbles: true }) - keydownEvent.key = 'ArrowDown' - toggle.dispatchEvent(keydownEvent) - keydownEvent.key = 'Escape' - toggle.dispatchEvent(keydownEvent) - }) + toggle.addEventListener('shown.bs.dropdown', () => { + const keydownEvent = createEvent('keydown', { bubbles: true }) + keydownEvent.key = 'ArrowDown' + toggle.dispatchEvent(keydownEvent) + keydownEvent.key = 'Escape' + toggle.dispatchEvent(keydownEvent) + }) - toggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { - expect(document.activeElement).toEqual(toggle) - done() - })) + toggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { + expect(document.activeElement).toEqual(toggle) + resolve() + })) - toggle.click() + toggle.click() + }) }) - it('should close dropdown (only) by clicking inside the dropdown menu when it has data-attribute `data-bs-auto-close="inside"`', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should close dropdown (only) by clicking inside the dropdown menu when it has data-attribute `data-bs-auto-close="inside"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle).toHaveClass('show') - dropdownMenu.click() - }, 150) + const expectDropdownToBeOpened = () => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + dropdownMenu.click() + }, 150) - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - document.documentElement.click() - expectDropdownToBeOpened() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + document.documentElement.click() + expectDropdownToBeOpened() + }) - dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { - expect(dropdownToggle).not.toHaveClass('show') - done() - })) + dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { + expect(dropdownToggle).not.toHaveClass('show') + resolve() + })) - dropdownToggle.click() + dropdownToggle.click() + }) }) - it('should close dropdown (only) by clicking outside the dropdown menu when it has data-attribute `data-bs-auto-close="outside"`', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should close dropdown (only) by clicking outside the dropdown menu when it has data-attribute `data-bs-auto-close="outside"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle).toHaveClass('show') - document.documentElement.click() - }, 150) + const expectDropdownToBeOpened = () => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + document.documentElement.click() + }, 150) - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - dropdownMenu.click() - expectDropdownToBeOpened() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + dropdownMenu.click() + expectDropdownToBeOpened() + }) - dropdownToggle.addEventListener('hidden.bs.dropdown', () => { - expect(dropdownToggle).not.toHaveClass('show') - done() - }) + dropdownToggle.addEventListener('hidden.bs.dropdown', () => { + expect(dropdownToggle).not.toHaveClass('show') + resolve() + }) - dropdownToggle.click() + dropdownToggle.click() + }) }) - it('should not close dropdown by clicking inside or outside the dropdown menu when it has data-attribute `data-bs-auto-close="false"`', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close dropdown by clicking inside or outside the dropdown menu when it has data-attribute `data-bs-auto-close="false"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const expectDropdownToBeOpened = (shouldTriggerClick = true) => setTimeout(() => { - expect(dropdownToggle).toHaveClass('show') - if (shouldTriggerClick) { - document.documentElement.click() - } else { - done() - } + const expectDropdownToBeOpened = (shouldTriggerClick = true) => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + if (shouldTriggerClick) { + document.documentElement.click() + } else { + resolve() + } - expectDropdownToBeOpened(false) - }, 150) + expectDropdownToBeOpened(false) + }, 150) - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - dropdownMenu.click() - expectDropdownToBeOpened() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + dropdownMenu.click() + expectDropdownToBeOpened() + }) - dropdownToggle.click() + dropdownToggle.click() + }) }) }) @@ -2030,52 +2142,54 @@ describe('Dropdown', () => { }) }) - it('should open dropdown when pressing keydown or keyup', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open dropdown when pressing keydown or keyup', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdown = fixtureEl.querySelector('.dropdown') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdown = fixtureEl.querySelector('.dropdown') + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + const keyup = createEvent('keyup') + keyup.key = 'ArrowUp' - const keyup = createEvent('keyup') - keyup.key = 'ArrowUp' + const handleArrowDown = () => { + expect(triggerDropdown).toHaveClass('show') + expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') + setTimeout(() => { + dropdown.hide() + keydown.key = 'ArrowUp' + triggerDropdown.dispatchEvent(keyup) + }, 20) + } - const handleArrowDown = () => { - expect(triggerDropdown).toHaveClass('show') - expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') - setTimeout(() => { - dropdown.hide() - keydown.key = 'ArrowUp' - triggerDropdown.dispatchEvent(keyup) - }, 20) - } - - const handleArrowUp = () => { - expect(triggerDropdown).toHaveClass('show') - expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') - done() - } - - dropdown.addEventListener('shown.bs.dropdown', event => { - if (event.target.key === 'ArrowDown') { - handleArrowDown() - } else { - handleArrowUp() + const handleArrowUp = () => { + expect(triggerDropdown).toHaveClass('show') + expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') + resolve() } - }) - triggerDropdown.dispatchEvent(keydown) + dropdown.addEventListener('shown.bs.dropdown', event => { + if (event.target.key === 'ArrowDown') { + handleArrowDown() + } else { + handleArrowUp() + } + }) + + triggerDropdown.dispatchEvent(keydown) + }) }) it('should allow `data-bs-toggle="dropdown"` click events to bubble up', () => { @@ -2101,27 +2215,29 @@ describe('Dropdown', () => { expect(delegatedClickListener).toHaveBeenCalled() }) - it('should open the dropdown when clicking the child element inside `data-bs-toggle="dropdown"`', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') + it('should open the dropdown when clicking the child element inside `data-bs-toggle="dropdown"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const childElement = fixtureEl.querySelector('#childElement') + const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const childElement = fixtureEl.querySelector('#childElement') - btnDropdown.addEventListener('shown.bs.dropdown', () => setTimeout(() => { - expect(btnDropdown).toHaveClass('show') - expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') - done() - })) + btnDropdown.addEventListener('shown.bs.dropdown', () => setTimeout(() => { + expect(btnDropdown).toHaveClass('show') + expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') + resolve() + })) - childElement.click() + childElement.click() + }) }) }) diff --git a/js/tests/unit/jquery.spec.js b/js/tests/unit/jquery.spec.js index 16781a351..7da39d630 100644 --- a/js/tests/unit/jquery.spec.js +++ b/js/tests/unit/jquery.spec.js @@ -12,7 +12,7 @@ import ScrollSpy from '../../src/scrollspy' import Tab from '../../src/tab' import Toast from '../../src/toast' import Tooltip from '../../src/tooltip' -import { getFixture, clearFixture } from '../helpers/fixture' +import { clearFixture, getFixture } from '../helpers/fixture' describe('jQuery', () => { let fixtureEl @@ -40,19 +40,21 @@ describe('jQuery', () => { expect(Tooltip.jQueryInterface).toEqual(jQuery.fn.tooltip) }) - it('should use jQuery event system', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') - - $(fixtureEl).find('.alert') - .one('closed.bs.alert', () => { - expect($(fixtureEl).find('.alert')).toHaveSize(0) - done() - }) - - $(fixtureEl).find('button').trigger('click') + it('should use jQuery event system', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') + + $(fixtureEl).find('.alert') + .one('closed.bs.alert', () => { + expect($(fixtureEl).find('.alert')).toHaveSize(0) + resolve() + }) + + $(fixtureEl).find('button').trigger('click') + }) }) }) diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index 84a95c86a..bf796411b 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -56,93 +56,101 @@ describe('Modal', () => { }) describe('toggle', () => { - it('should call ScrollBarHelper to handle scrollBar on body', done => { - fixtureEl.innerHTML = '' + it('should call ScrollBarHelper to handle scrollBar on body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' + + spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + + modalEl.addEventListener('shown.bs.modal', () => { + expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() + modal.toggle() + }) - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() modal.toggle() }) - - modalEl.addEventListener('hidden.bs.modal', () => { - expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() - done() - }) - - modal.toggle() }) }) describe('show', () => { - it('should show a modal', done => { - fixtureEl.innerHTML = '' + it('should show a modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('show.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('show.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should show a modal without backdrop', done => { - fixtureEl.innerHTML = '' + it('should show a modal without backdrop', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: false + }) - modalEl.addEventListener('show.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('show.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).toBeNull() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should show a modal and append the element', done => { - const modalEl = document.createElement('div') - const id = 'dynamicModal' + it('should show a modal and append the element', () => { + return new Promise(resolve => { + const modalEl = document.createElement('div') + const id = 'dynamicModal' - modalEl.setAttribute('id', id) - modalEl.classList.add('modal') - modalEl.innerHTML = '' + modalEl.setAttribute('id', id) + modalEl.classList.add('modal') + modalEl.innerHTML = '' - const modal = new Modal(modalEl) + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - const dynamicModal = document.getElementById(id) - expect(dynamicModal).not.toBeNull() - dynamicModal.remove() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + const dynamicModal = document.getElementById(id) + expect(dynamicModal).not.toBeNull() + dynamicModal.remove() + resolve() + }) - modal.show() + modal.show() + }) }) it('should do nothing if a modal is shown', () => { @@ -173,511 +181,551 @@ describe('Modal', () => { expect(EventHandler.trigger).not.toHaveBeenCalled() }) - it('should not fire shown event when show is prevented', done => { - fixtureEl.innerHTML = '' + it('should not fire shown event when show is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('show.bs.modal', event => { - event.preventDefault() + modalEl.addEventListener('show.bs.modal', event => { + event.preventDefault() - const expectedDone = () => { - expect().nothing() - done() - } + const expectedDone = () => { + expect().nothing() + resolve() + } - setTimeout(expectedDone, 10) - }) + setTimeout(expectedDone, 10) + }) - modalEl.addEventListener('shown.bs.modal', () => { - throw new Error('shown event triggered') - }) + modalEl.addEventListener('shown.bs.modal', () => { + throw new Error('shown event triggered') + }) - modal.show() + modal.show() + }) }) - it('should be shown after the first call to show() has been prevented while fading is enabled ', done => { - fixtureEl.innerHTML = '' + it('should be shown after the first call to show() has been prevented while fading is enabled ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - let prevented = false - modalEl.addEventListener('show.bs.modal', event => { - if (!prevented) { - event.preventDefault() - prevented = true + let prevented = false + modalEl.addEventListener('show.bs.modal', event => { + if (!prevented) { + event.preventDefault() + prevented = true - setTimeout(() => { - modal.show() - }) - } - }) + setTimeout(() => { + modal.show() + }) + } + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(prevented).toBeTrue() - expect(modal._isAnimated()).toBeTrue() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(prevented).toBeTrue() + expect(modal._isAnimated()).toBeTrue() + resolve() + }) - modal.show() + modal.show() + }) }) + it('should set is transitioning if fade class is present', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - it('should set is transitioning if fade class is present', done => { - fixtureEl.innerHTML = '' + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + modalEl.addEventListener('show.bs.modal', () => { + setTimeout(() => { + expect(modal._isTransitioning).toBeTrue() + }) + }) - modalEl.addEventListener('show.bs.modal', () => { - setTimeout(() => { - expect(modal._isTransitioning).toBeTrue() + modalEl.addEventListener('shown.bs.modal', () => { + expect(modal._isTransitioning).toBeFalse() + resolve() }) - }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._isTransitioning).toBeFalse() - done() + modal.show() }) - - modal.show() }) - it('should close modal when a click occurred on data-bs-dismiss="modal" inside modal', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) - - spyOn(modal, 'hide').and.callThrough() + it('should close modal when a click occurred on data-bs-dismiss="modal" inside modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) + + spyOn(modal, 'hide').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modal.hide).toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() + modal.show() }) - - modal.show() }) - it('should close modal when a click occurred on a data-bs-dismiss="modal" with "bs-target" outside of modal element', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should close modal when a click occurred on a data-bs-dismiss="modal" with "bs-target" outside of modal element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) - spyOn(modal, 'hide').and.callThrough() + spyOn(modal, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modal.hide).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should set .modal\'s scroll top to 0', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should set .modal\'s scroll top to 0', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.scrollTop).toEqual(0) - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.scrollTop).toEqual(0) + resolve() + }) - modal.show() + modal.show() + }) }) - it('should set modal body scroll top to 0 if modal body do not exists', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const modalBody = modalEl.querySelector('.modal-body') - const modal = new Modal(modalEl) + it('should set modal body scroll top to 0 if modal body do not exists', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const modalBody = modalEl.querySelector('.modal-body') + const modal = new Modal(modalEl) + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalBody.scrollTop).toEqual(0) + resolve() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalBody.scrollTop).toEqual(0) - done() + modal.show() }) - - modal.show() }) - it('should not trap focus if focus equal to false', done => { - fixtureEl.innerHTML = '' + it('should not trap focus if focus equal to false', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - focus: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + focus: false + }) - spyOn(modal._focustrap, 'activate').and.callThrough() + spyOn(modal._focustrap, 'activate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._focustrap.activate).not.toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modal._focustrap.activate).not.toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should add listener when escape touch is pressed', done => { - fixtureEl.innerHTML = '' + it('should add listener when escape touch is pressed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal, 'hide').and.callThrough() + spyOn(modal, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - modalEl.dispatchEvent(keydownEscape) - }) + modalEl.dispatchEvent(keydownEscape) + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modal.hide).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should do nothing when the pressed key is not escape', done => { - fixtureEl.innerHTML = '' + it('should do nothing when the pressed key is not escape', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal, 'hide') + spyOn(modal, 'hide') - const expectDone = () => { - expect(modal.hide).not.toHaveBeenCalled() + const expectDone = () => { + expect(modal.hide).not.toHaveBeenCalled() - done() - } + resolve() + } - modalEl.addEventListener('shown.bs.modal', () => { - const keydownTab = createEvent('keydown') - keydownTab.key = 'Tab' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownTab = createEvent('keydown') + keydownTab.key = 'Tab' - modalEl.dispatchEvent(keydownTab) - setTimeout(expectDone, 30) - }) + modalEl.dispatchEvent(keydownTab) + setTimeout(expectDone, 30) + }) - modal.show() + modal.show() + }) }) - it('should adjust dialog on resize', done => { - fixtureEl.innerHTML = '' + it('should adjust dialog on resize', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + + spyOn(modal, '_adjustDialog').and.callThrough() - spyOn(modal, '_adjustDialog').and.callThrough() + const expectDone = () => { + expect(modal._adjustDialog).toHaveBeenCalled() - const expectDone = () => { - expect(modal._adjustDialog).toHaveBeenCalled() + resolve() + } - done() - } + modalEl.addEventListener('shown.bs.modal', () => { + const resizeEvent = createEvent('resize') - modalEl.addEventListener('shown.bs.modal', () => { - const resizeEvent = createEvent('resize') + window.dispatchEvent(resizeEvent) + setTimeout(expectDone, 10) + }) - window.dispatchEvent(resizeEvent) - setTimeout(expectDone, 10) + modal.show() }) - - modal.show() }) - it('should not close modal when clicking on modal-content', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close modal when clicking on modal-content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].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() - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toEqual(true) + resolve() + }, 10) + } - modal.show() - }) + modalEl.addEventListener('shown.bs.modal', () => { + fixtureEl.querySelector('.modal-dialog').click() + fixtureEl.querySelector('.modal-content').click() + shownCallback() + }) - it('should not close modal when clicking outside of modal-content if backdrop = false', done => { - fixtureEl.innerHTML = '' + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('Should not hide a modal') + }) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: false + modal.show() }) + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toBeTrue() - done() - }, 10) - } + it('should not close modal when clicking outside of modal-content if backdrop = false', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - shownCallback() - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: false + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modal.show() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + shownCallback() + }) - it('should not close modal when clicking outside of modal-content if backdrop = static', done => { - fixtureEl.innerHTML = '' + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('Should not hide a modal') + }) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' + modal.show() }) + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toBeTrue() - done() - }, 10) - } + it('should not close modal when clicking outside of modal-content if backdrop = static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - shownCallback() - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modal.show() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + shownCallback() + }) - it('should close modal when escape key is pressed with keyboard = true and backdrop is static', done => { - fixtureEl.innerHTML = '' + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('Should not hide a modal') + }) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static', - keyboard: true + modal.show() }) + }) + it('should close modal when escape key is pressed with keyboard = true and backdrop is static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' + + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static', + keyboard: true + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toBeFalse() - done() - }, 10) - } + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeFalse() + resolve() + }, 10) + } - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - modalEl.dispatchEvent(keydownEscape) - shownCallback() - }) + modalEl.dispatchEvent(keydownEscape) + shownCallback() + }) - modal.show() + modal.show() + }) }) - it('should not close modal when escape key is pressed with keyboard = false', done => { - fixtureEl.innerHTML = '' + it('should not close modal when escape key is pressed with keyboard = false', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - keyboard: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + keyboard: false + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toBeTrue() - done() - }, 10) - } + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - modalEl.dispatchEvent(keydownEscape) - shownCallback() - }) + modalEl.dispatchEvent(keydownEscape) + shownCallback() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('Should not hide a modal') + }) - modal.show() + modal.show() + }) }) - it('should not overflow when clicking outside of modal-content if backdrop = static', done => { - fixtureEl.innerHTML = '' + it('should not overflow when clicking outside of modal-content if backdrop = static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - setTimeout(() => { - expect(modalEl.clientHeight).toEqual(modalEl.scrollHeight) - done() - }, 20) - }) + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + setTimeout(() => { + expect(modalEl.clientHeight).toEqual(modalEl.scrollHeight) + resolve() + }, 20) + }) - modal.show() + modal.show() + }) }) - it('should not queue multiple callbacks when clicking outside of modal-content and backdrop = static', done => { - fixtureEl.innerHTML = '' + it('should not queue multiple callbacks when clicking outside of modal-content and backdrop = static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - modalEl.addEventListener('shown.bs.modal', () => { - const spy = spyOn(modal, '_queueCallback').and.callThrough() + modalEl.addEventListener('shown.bs.modal', () => { + const spy = spyOn(modal, '_queueCallback').and.callThrough() - modalEl.click() - modalEl.click() + modalEl.click() + modalEl.click() - setTimeout(() => { - expect(spy).toHaveBeenCalledTimes(1) - done() - }, 20) - }) + setTimeout(() => { + expect(spy).toHaveBeenCalledTimes(1) + resolve() + }, 20) + }) - modal.show() + modal.show() + }) }) - it('should trap focus', done => { - fixtureEl.innerHTML = '' + it('should trap focus', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal._focustrap, 'activate').and.callThrough() + spyOn(modal._focustrap, 'activate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._focustrap.activate).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modal._focustrap.activate).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) }) describe('hide', () => { - it('should hide a modal', done => { - fixtureEl.innerHTML = '' + it('should hide a modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) - const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - modalEl.addEventListener('hide.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('hide.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(backdropSpy).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toBeNull() + expect(modalEl.getAttribute('role')).toBeNull() + expect(modalEl.getAttribute('aria-hidden')).toEqual('true') + expect(modalEl.style.display).toEqual('none') + expect(backdropSpy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should close modal when clicking outside of modal-content', done => { - fixtureEl.innerHTML = '' + it('should close modal when clicking outside of modal-content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toBeNull() + expect(modalEl.getAttribute('role')).toBeNull() + expect(modalEl.getAttribute('aria-hidden')).toEqual('true') + expect(modalEl.style.display).toEqual('none') + expect(document.querySelector('.modal-backdrop')).toBeNull() + resolve() + }) - modal.show() + modal.show() + }) }) it('should do nothing is the modal is not shown', () => { @@ -703,52 +751,56 @@ describe('Modal', () => { expect().nothing() }) - it('should not hide a modal if hide is prevented', done => { - fixtureEl.innerHTML = '' + it('should not hide a modal if hide is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - const hideCallback = () => { - setTimeout(() => { - expect(modal._isShown).toBeTrue() - done() - }, 10) - } + const hideCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('hide.bs.modal', event => { - event.preventDefault() - hideCallback() - }) + modalEl.addEventListener('hide.bs.modal', event => { + event.preventDefault() + hideCallback() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('should not trigger hidden') - }) + modalEl.addEventListener('hidden.bs.modal', () => { + throw new Error('should not trigger hidden') + }) - modal.show() + modal.show() + }) }) - it('should release focus trap', done => { - fixtureEl.innerHTML = '' + it('should release focus trap', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) - spyOn(modal._focustrap, 'deactivate').and.callThrough() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + spyOn(modal._focustrap, 'deactivate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal._focustrap.deactivate).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modal._focustrap.deactivate).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) }) @@ -789,246 +841,260 @@ describe('Modal', () => { }) describe('data-api', () => { - it('should toggle modal', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should toggle modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + setTimeout(() => trigger.click(), 10) + }) - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - setTimeout(() => trigger.click(), 10) - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toBeNull() + expect(modalEl.getAttribute('role')).toBeNull() + expect(modalEl.getAttribute('aria-hidden')).toEqual('true') + expect(modalEl.style.display).toEqual('none') + expect(document.querySelector('.modal-backdrop')).toBeNull() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() + trigger.click() }) - - trigger.click() }) - it('should not recreate a new modal', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should not recreate a new modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - spyOn(modal, 'show').and.callThrough() + spyOn(modal, 'show').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal.show).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modal.show).toHaveBeenCalled() + resolve() + }) - trigger.click() + trigger.click() + }) }) - it('should prevent default when the trigger is or ', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should prevent default when the trigger is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + + spyOn(Event.prototype, 'preventDefault').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + expect(Event.prototype.preventDefault).toHaveBeenCalled() + resolve() + }) - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - - spyOn(Event.prototype, 'preventDefault').and.callThrough() - - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() + trigger.click() }) - - trigger.click() }) - it('should focus the trigger on hide', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should focus the trigger on hide', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - spyOn(trigger, 'focus') + spyOn(trigger, 'focus') - modalEl.addEventListener('shown.bs.modal', () => { - const modal = Modal.getInstance(modalEl) + modalEl.addEventListener('shown.bs.modal', () => { + const modal = Modal.getInstance(modalEl) - modal.hide() - }) + modal.hide() + }) - const hideListener = () => { - setTimeout(() => { - expect(trigger.focus).toHaveBeenCalled() - done() - }, 20) - } + const hideListener = () => { + setTimeout(() => { + expect(trigger.focus).toHaveBeenCalled() + resolve() + }, 20) + } - modalEl.addEventListener('hidden.bs.modal', () => { - hideListener() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + hideListener() + }) - trigger.click() + trigger.click() + }) }) + it('should not prevent default when a click occurred on data-bs-dismiss="modal" where tagName is DIFFERENT than or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('button[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) + + spyOn(Event.prototype, 'preventDefault').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - it('should not prevent default when a click occurred on data-bs-dismiss="modal" where tagName is DIFFERENT than or ', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('button[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) - - spyOn(Event.prototype, 'preventDefault').and.callThrough() - - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(Event.prototype.preventDefault).not.toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(Event.prototype.preventDefault).not.toHaveBeenCalled() - done() + modal.show() }) - - modal.show() }) - it('should prevent default when a click occurred on data-bs-dismiss="modal" where tagName is or ', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should prevent default when a click occurred on data-bs-dismiss="modal" where tagName is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('a[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('a[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) - spyOn(Event.prototype, 'preventDefault').and.callThrough() + spyOn(Event.prototype, 'preventDefault').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(Event.prototype.preventDefault).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) + it('should not focus the trigger if the modal is not visible', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - it('should not focus the trigger if the modal is not visible', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + spyOn(trigger, 'focus') - spyOn(trigger, 'focus') + modalEl.addEventListener('shown.bs.modal', () => { + const modal = Modal.getInstance(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - const modal = Modal.getInstance(modalEl) + modal.hide() + }) - modal.hide() - }) + const hideListener = () => { + setTimeout(() => { + expect(trigger.focus).not.toHaveBeenCalled() + resolve() + }, 20) + } - const hideListener = () => { - setTimeout(() => { - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 20) - } + modalEl.addEventListener('hidden.bs.modal', () => { + hideListener() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - hideListener() + trigger.click() }) - - trigger.click() }) + it('should not focus the trigger if the modal is not shown', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - it('should not focus the trigger if the modal is not shown', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + spyOn(trigger, 'focus') - spyOn(trigger, 'focus') + const showListener = () => { + setTimeout(() => { + expect(trigger.focus).not.toHaveBeenCalled() + resolve() + }, 10) + } - const showListener = () => { - setTimeout(() => { - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 10) - } + modalEl.addEventListener('show.bs.modal', event => { + event.preventDefault() + showListener() + }) - modalEl.addEventListener('show.bs.modal', event => { - event.preventDefault() - showListener() + trigger.click() }) - - trigger.click() }) - it('should call hide first, if another modal is open', done => { - fixtureEl.innerHTML = [ - '', - '', - '' - ].join('') - - const trigger2 = fixtureEl.querySelector('button') - const modalEl1 = document.querySelector('#modal1') - const modalEl2 = document.querySelector('#modal2') - const modal1 = new Modal(modalEl1) - - modalEl1.addEventListener('shown.bs.modal', () => { - trigger2.click() - }) - modalEl1.addEventListener('hidden.bs.modal', () => { - expect(Modal.getInstance(modalEl2)).not.toBeNull() - expect(modalEl2).toHaveClass('show') - done() + it('should call hide first, if another modal is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '', + '' + ].join('') + + const trigger2 = fixtureEl.querySelector('button') + const modalEl1 = document.querySelector('#modal1') + const modalEl2 = document.querySelector('#modal2') + const modal1 = new Modal(modalEl1) + + modalEl1.addEventListener('shown.bs.modal', () => { + trigger2.click() + }) + modalEl1.addEventListener('hidden.bs.modal', () => { + expect(Modal.getInstance(modalEl2)).not.toBeNull() + expect(modalEl2).toHaveClass('show') + resolve() + }) + modal1.show() }) - modal1.show() }) }) - describe('jQueryInterface', () => { it('should create a modal', () => { fixtureEl.innerHTML = '' diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index 36ef45dce..852ffa556 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -147,83 +147,91 @@ describe('Offcanvas', () => { }) describe('options', () => { - it('if scroll is enabled, should allow body to scroll while offcanvas is open', done => { - fixtureEl.innerHTML = '
' + it('if scroll is enabled, should allow body to scroll while offcanvas is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { scroll: true }) + spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { scroll: true }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.hide).not.toHaveBeenCalled() - offCanvas.hide() - }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.reset).not.toHaveBeenCalled() - done() + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(ScrollBarHelper.prototype.hide).not.toHaveBeenCalled() + offCanvas.hide() + }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(ScrollBarHelper.prototype.reset).not.toHaveBeenCalled() + resolve() + }) + offCanvas.show() }) - offCanvas.show() }) - it('if scroll is disabled, should call ScrollBarHelper to handle scrollBar on body', done => { - fixtureEl.innerHTML = '
' + it('if scroll is disabled, should call ScrollBarHelper to handle scrollBar on body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { scroll: false }) + spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { scroll: false }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() - offCanvas.hide() + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() + offCanvas.hide() + }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() + resolve() + }) + offCanvas.show() }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() - done() - }) - offCanvas.show() }) - it('should hide a shown element if user click on backdrop', done => { - fixtureEl.innerHTML = '
' + it('should hide a shown element if user click on backdrop', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl, { backdrop: true }) + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl, { backdrop: true }) - const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) - spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) + spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvas._backdrop._config.clickCallback).toEqual(jasmine.any(Function)) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvas._backdrop._config.clickCallback).toEqual(jasmine.any(Function)) - offCanvas._backdrop._getElement().dispatchEvent(clickEvent) - }) + offCanvas._backdrop._getElement().dispatchEvent(clickEvent) + }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvas._backdrop._config.clickCallback).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvas._backdrop._config.clickCallback).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) - it('should not trap focus if scroll is allowed', done => { - fixtureEl.innerHTML = '
' + it('should not trap focus if scroll is allowed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { - scroll: true - }) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { + scroll: true + }) - spyOn(offCanvas._focustrap, 'activate').and.callThrough() + spyOn(offCanvas._focustrap, 'activate').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvas._focustrap.activate).not.toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvas._focustrap.activate).not.toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) }) @@ -241,44 +249,48 @@ describe('Offcanvas', () => { expect(offCanvas.show).toHaveBeenCalled() }) - it('should call hide method if show class is present', done => { - fixtureEl.innerHTML = '
' + it('should call hide method if show class is present', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl).toHaveClass('show') - spyOn(offCanvas, 'hide') + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + spyOn(offCanvas, 'hide') - offCanvas.toggle() + offCanvas.toggle() - expect(offCanvas.hide).toHaveBeenCalled() - done() - }) + expect(offCanvas.hide).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) }) describe('show', () => { - it('should add `showing` class during opening and `show` class on end', done => { - fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) + it('should add `showing` class during opening and `show` class on end', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - offCanvasEl.addEventListener('show.bs.offcanvas', () => { - expect(offCanvasEl).not.toHaveClass('show') - }) + offCanvasEl.addEventListener('show.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('show') + }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl).not.toHaveClass('showing') - expect(offCanvasEl).toHaveClass('show') - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + resolve() + }) - offCanvas.show() - expect(offCanvasEl).toHaveClass('showing') + offCanvas.show() + expect(offCanvasEl).toHaveClass('showing') + }) }) it('should do nothing if already shown', () => { @@ -298,104 +310,114 @@ describe('Offcanvas', () => { expect(offCanvas._backdrop.show).not.toHaveBeenCalled() }) - it('should show a hidden element', done => { - fixtureEl.innerHTML = '
' + it('should show a hidden element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'show').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + spyOn(offCanvas._backdrop, 'show').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl).toHaveClass('show') - expect(offCanvas._backdrop.show).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + expect(offCanvas._backdrop.show).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) - it('should not fire shown when show is prevented', done => { - fixtureEl.innerHTML = '
' + it('should not fire shown when show is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'show').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + spyOn(offCanvas._backdrop, 'show').and.callThrough() - const expectEnd = () => { - setTimeout(() => { - expect(offCanvas._backdrop.show).not.toHaveBeenCalled() - done() - }, 10) - } + const expectEnd = () => { + setTimeout(() => { + expect(offCanvas._backdrop.show).not.toHaveBeenCalled() + resolve() + }, 10) + } - offCanvasEl.addEventListener('show.bs.offcanvas', event => { - event.preventDefault() - expectEnd() - }) + offCanvasEl.addEventListener('show.bs.offcanvas', event => { + event.preventDefault() + expectEnd() + }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - throw new Error('should not fire shown event') - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + throw new Error('should not fire shown event') + }) - offCanvas.show() + offCanvas.show() + }) }) - it('on window load, should make visible an offcanvas element, if its markup contains class "show"', done => { - fixtureEl.innerHTML = '
' + it('on window load, should make visible an offcanvas element, if its markup contains class "show"', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - spyOn(Offcanvas.prototype, 'show').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + spyOn(Offcanvas.prototype, 'show').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + resolve() + }) - window.dispatchEvent(createEvent('load')) + window.dispatchEvent(createEvent('load')) - const instance = Offcanvas.getInstance(offCanvasEl) - expect(instance).not.toBeNull() - expect(Offcanvas.prototype.show).toHaveBeenCalled() + const instance = Offcanvas.getInstance(offCanvasEl) + expect(instance).not.toBeNull() + expect(Offcanvas.prototype.show).toHaveBeenCalled() + }) }) - it('should trap focus', done => { - fixtureEl.innerHTML = '
' + it('should trap focus', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._focustrap, 'activate').and.callThrough() + spyOn(offCanvas._focustrap, 'activate').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvas._focustrap.activate).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvas._focustrap.activate).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) }) describe('hide', () => { - it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', done => { - fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) + it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - offCanvasEl.addEventListener('hide.bs.offcanvas', () => { - expect(offCanvasEl).not.toHaveClass('showing') - expect(offCanvasEl).toHaveClass('show') - }) + offCanvasEl.addEventListener('hide.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvasEl).not.toHaveClass('hiding') - expect(offCanvasEl).not.toHaveClass('show') - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('hiding') + expect(offCanvasEl).not.toHaveClass('show') + resolve() + }) - offCanvas.show() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - offCanvas.hide() - expect(offCanvasEl).not.toHaveClass('showing') - expect(offCanvasEl).toHaveClass('hiding') + offCanvas.show() + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + offCanvas.hide() + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('hiding') + }) }) }) @@ -413,65 +435,71 @@ describe('Offcanvas', () => { expect(EventHandler.trigger).not.toHaveBeenCalled() }) - it('should hide a shown element', done => { - fixtureEl.innerHTML = '
' + it('should hide a shown element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'hide').and.callThrough() - offCanvas.show() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + spyOn(offCanvas._backdrop, 'hide').and.callThrough() + offCanvas.show() - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvasEl).not.toHaveClass('show') - expect(offCanvas._backdrop.hide).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('show') + expect(offCanvas._backdrop.hide).toHaveBeenCalled() + resolve() + }) - offCanvas.hide() + offCanvas.hide() + }) }) - it('should not fire hidden when hide is prevented', done => { - fixtureEl.innerHTML = '
' + it('should not fire hidden when hide is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'hide').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + spyOn(offCanvas._backdrop, 'hide').and.callThrough() - offCanvas.show() + offCanvas.show() - const expectEnd = () => { - setTimeout(() => { - expect(offCanvas._backdrop.hide).not.toHaveBeenCalled() - done() - }, 10) - } + const expectEnd = () => { + setTimeout(() => { + expect(offCanvas._backdrop.hide).not.toHaveBeenCalled() + resolve() + }, 10) + } - offCanvasEl.addEventListener('hide.bs.offcanvas', event => { - event.preventDefault() - expectEnd() - }) + offCanvasEl.addEventListener('hide.bs.offcanvas', event => { + event.preventDefault() + expectEnd() + }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - throw new Error('should not fire hidden event') - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + throw new Error('should not fire hidden event') + }) - offCanvas.hide() + offCanvas.hide() + }) }) - it('should release focus trap', done => { - fixtureEl.innerHTML = '
' + it('should release focus trap', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._focustrap, 'deactivate').and.callThrough() - offCanvas.show() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + spyOn(offCanvas._focustrap, 'deactivate').and.callThrough() + offCanvas.show() - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvas._focustrap.deactivate).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvas._focustrap.deactivate).toHaveBeenCalled() + resolve() + }) - offCanvas.hide() + offCanvas.hide() + }) }) }) @@ -501,22 +529,24 @@ describe('Offcanvas', () => { }) describe('data-api', () => { - it('should not prevent event for input', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') + it('should not prevent event for input', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') - const target = fixtureEl.querySelector('input') - const offCanvasEl = fixtureEl.querySelector('#offcanvasdiv1') + const target = fixtureEl.querySelector('input') + const offCanvasEl = fixtureEl.querySelector('#offcanvasdiv1') - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl).toHaveClass('show') - expect(target.checked).toBeTrue() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + expect(target.checked).toBeTrue() + resolve() + }) - target.click() + target.click() + }) }) it('should not call toggle on disabled elements', () => { @@ -534,76 +564,82 @@ describe('Offcanvas', () => { expect(Offcanvas.prototype.toggle).not.toHaveBeenCalled() }) - it('should call hide first, if another offcanvas is open', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
' - ].join('') - - const trigger2 = fixtureEl.querySelector('#btn2') - const offcanvasEl1 = document.querySelector('#offcanvas1') - const offcanvasEl2 = document.querySelector('#offcanvas2') - const offcanvas1 = new Offcanvas(offcanvasEl1) - - offcanvasEl1.addEventListener('shown.bs.offcanvas', () => { - trigger2.click() + it('should call hide first, if another offcanvas is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
' + ].join('') + + const trigger2 = fixtureEl.querySelector('#btn2') + const offcanvasEl1 = document.querySelector('#offcanvas1') + const offcanvasEl2 = document.querySelector('#offcanvas2') + const offcanvas1 = new Offcanvas(offcanvasEl1) + + offcanvasEl1.addEventListener('shown.bs.offcanvas', () => { + trigger2.click() + }) + offcanvasEl1.addEventListener('hidden.bs.offcanvas', () => { + expect(Offcanvas.getInstance(offcanvasEl2)).not.toBeNull() + resolve() + }) + offcanvas1.show() + }) + }) + + it('should focus on trigger element after closing offcanvas', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const trigger = fixtureEl.querySelector('#btn') + const offcanvasEl = fixtureEl.querySelector('#offcanvas') + const offcanvas = new Offcanvas(offcanvasEl) + spyOn(trigger, 'focus') + + offcanvasEl.addEventListener('shown.bs.offcanvas', () => { + offcanvas.hide() + }) + offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { + setTimeout(() => { + expect(trigger.focus).toHaveBeenCalled() + resolve() + }, 5) + }) + + trigger.click() + }) + }) + + it('should not focus on trigger element after closing offcanvas, if it is not visible', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const trigger = fixtureEl.querySelector('#btn') + const offcanvasEl = fixtureEl.querySelector('#offcanvas') + const offcanvas = new Offcanvas(offcanvasEl) + spyOn(trigger, 'focus') + + offcanvasEl.addEventListener('shown.bs.offcanvas', () => { + trigger.style.display = 'none' + offcanvas.hide() + }) + offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { + setTimeout(() => { + expect(isVisible(trigger)).toBeFalse() + expect(trigger.focus).not.toHaveBeenCalled() + resolve() + }, 5) + }) + + trigger.click() }) - offcanvasEl1.addEventListener('hidden.bs.offcanvas', () => { - expect(Offcanvas.getInstance(offcanvasEl2)).not.toBeNull() - done() - }) - offcanvas1.show() - }) - - it('should focus on trigger element after closing offcanvas', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const trigger = fixtureEl.querySelector('#btn') - const offcanvasEl = fixtureEl.querySelector('#offcanvas') - const offcanvas = new Offcanvas(offcanvasEl) - spyOn(trigger, 'focus') - - offcanvasEl.addEventListener('shown.bs.offcanvas', () => { - offcanvas.hide() - }) - offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { - setTimeout(() => { - expect(trigger.focus).toHaveBeenCalled() - done() - }, 5) - }) - - trigger.click() - }) - - it('should not focus on trigger element after closing offcanvas, if it is not visible', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const trigger = fixtureEl.querySelector('#btn') - const offcanvasEl = fixtureEl.querySelector('#offcanvas') - const offcanvas = new Offcanvas(offcanvasEl) - spyOn(trigger, 'focus') - - offcanvasEl.addEventListener('shown.bs.offcanvas', () => { - trigger.style.display = 'none' - offcanvas.hide() - }) - offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { - setTimeout(() => { - expect(isVisible(trigger)).toBeFalse() - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 5) - }) - - trigger.click() }) }) diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index a04bd21c6..7bbd52b1d 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -62,113 +62,125 @@ describe('Popover', () => { }) describe('show', () => { - it('should show a popover', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should show a popover', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - expect(document.querySelector('.popover')).not.toBeNull() - done() - }) + popoverEl.addEventListener('shown.bs.popover', () => { + expect(document.querySelector('.popover')).not.toBeNull() + resolve() + }) - popover.show() + popover.show() + }) }) - it('should set title and content from functions', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should set title and content from functions', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - title: () => 'Bootstrap', - content: () => 'loves writing tests (╯°□°)╯︵ ┻━┻' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + title: () => 'Bootstrap', + content: () => 'loves writing tests (╯°□°)╯︵ ┻━┻' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Bootstrap') - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('loves writing tests (╯°□°)╯︵ ┻━┻') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Bootstrap') + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('loves writing tests (╯°□°)╯︵ ┻━┻') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should show a popover with just content without having header', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just content without having header', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - content: 'Some beautiful content :)' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + content: 'Some beautiful content :)' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should show a popover with just title without having body', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just title without having body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - title: 'Title which does not require content' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + title: 'Title which does not require content' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should show a popover with just title without having body using data-attribute to get config', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just title without having body using data-attribute to get config', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should NOT show a popover without `title` and `content`', done => { - fixtureEl.innerHTML = 'Nice link' + it('should NOT show a popover without `title` and `content`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { animation: false }) - spyOn(EventHandler, 'trigger').and.callThrough() + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { animation: false }) + spyOn(EventHandler, 'trigger').and.callThrough() - setTimeout(() => { - expect(EventHandler.trigger).not.toHaveBeenCalled() - expect(document.querySelector('.popover')).toBeNull() - done() - }) + setTimeout(() => { + expect(EventHandler.trigger).not.toHaveBeenCalled() + expect(document.querySelector('.popover')).toBeNull() + resolve() + }) - popover.show() + popover.show() + }) }) it('"setContent" should keep the initial template', () => { @@ -187,72 +199,78 @@ describe('Popover', () => { expect(tip.querySelector('.popover-body')).not.toBeNull() }) - it('should call setContent once', done => { - fixtureEl.innerHTML = 'BS twitter' - - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - content: 'Popover content' - }) - expect(popover._templateFactory).toBeNull() - let spy = null - let times = 1 - - popoverEl.addEventListener('hidden.bs.popover', () => { + it('should call setContent once', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' + + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + content: 'Popover content' + }) + expect(popover._templateFactory).toBeNull() + let spy = null + let times = 1 + + popoverEl.addEventListener('hidden.bs.popover', () => { + popover.show() + }) + + 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(0) + if (times > 1) { + resolve() + } + + times++ + popover.hide() + }) popover.show() }) - - 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(0) - if (times > 1) { - done() - } - - times++ - popover.hide() - }) - popover.show() }) - it('should show a popover with provided custom class', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should show a popover with provided custom class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - const tip = document.querySelector('.popover') - expect(tip).not.toBeNull() - expect(tip).toHaveClass('custom-class') - done() - }) + popoverEl.addEventListener('shown.bs.popover', () => { + const tip = document.querySelector('.popover') + expect(tip).not.toBeNull() + expect(tip).toHaveClass('custom-class') + resolve() + }) - popover.show() + popover.show() + }) }) }) describe('hide', () => { - it('should hide a popover', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should hide a popover', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - popover.hide() - }) + popoverEl.addEventListener('shown.bs.popover', () => { + popover.hide() + }) - popoverEl.addEventListener('hidden.bs.popover', () => { - expect(document.querySelector('.popover')).toBeNull() - done() - }) + popoverEl.addEventListener('hidden.bs.popover', () => { + expect(document.querySelector('.popover')).toBeNull() + resolve() + }) - popover.show() + popover.show() + }) }) }) diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index 5c044e697..291654d9b 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -1,6 +1,6 @@ import ScrollSpy from '../../src/scrollspy' import Manipulator from '../../src/dom/manipulator' -import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' describe('ScrollSpy', () => { let fixtureEl @@ -85,418 +85,436 @@ describe('ScrollSpy', () => { expect(scrollSpy._targets).toHaveSize(2) }) - it('should only switch "active" class on current target', done => { - fixtureEl.innerHTML = [ - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
', - '
', - '
', - '

Overview

', - '

', - '
', - '
', - '

Detail

', - '

', - '
', - '
', - '
' - ].join('') - - const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') - const rootEl = fixtureEl.querySelector('#root') - const scrollSpy = new ScrollSpy(scrollSpyEl, { - target: 'ss-target' - }) - - spyOn(scrollSpy, '_process').and.callThrough() - - scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl).toHaveClass('active') - expect(scrollSpy._process).toHaveBeenCalled() - done() + it('should only switch "active" class on current target', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + '
', + '
', + ' ', + '
', + '
', + '
', + '
', + '
', + '

Overview

', + '

', + '
', + '
', + '

Detail

', + '

', + '
', + '
', + '
' + ].join('') + + const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') + const rootEl = fixtureEl.querySelector('#root') + const scrollSpy = new ScrollSpy(scrollSpyEl, { + target: 'ss-target' + }) + + spyOn(scrollSpy, '_process').and.callThrough() + + scrollSpyEl.addEventListener('scroll', () => { + expect(rootEl).toHaveClass('active') + expect(scrollSpy._process).toHaveBeenCalled() + resolve() + }) + + scrollSpyEl.scrollTop = 350 }) - - scrollSpyEl.scrollTop = 350 }) - it('should only switch "active" class on current target specified w element', done => { - fixtureEl.innerHTML = [ - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
', - '
', - '
', - '

Overview

', - '

', - '
', - '
', - '

Detail

', - '

', - '
', - '
', - '
' - ].join('') - - const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') - const rootEl = fixtureEl.querySelector('#root') - const scrollSpy = new ScrollSpy(scrollSpyEl, { - target: fixtureEl.querySelector('#ss-target') - }) - - spyOn(scrollSpy, '_process').and.callThrough() - - scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl).toHaveClass('active') - expect(scrollSpy._process).toHaveBeenCalled() - done() + it('should only switch "active" class on current target specified w element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + '
', + '
', + ' ', + '
', + '
', + '
', + '
', + '
', + '

Overview

', + '

', + '
', + '
', + '

Detail

', + '

', + '
', + '
', + '
' + ].join('') + + const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') + const rootEl = fixtureEl.querySelector('#root') + const scrollSpy = new ScrollSpy(scrollSpyEl, { + target: fixtureEl.querySelector('#ss-target') + }) + + spyOn(scrollSpy, '_process').and.callThrough() + + scrollSpyEl.addEventListener('scroll', () => { + expect(rootEl).toHaveClass('active') + expect(scrollSpy._process).toHaveBeenCalled() + resolve() + }) + + scrollSpyEl.scrollTop = 350 }) - - scrollSpyEl.scrollTop = 350 }) - it('should correctly select middle navigation option when large offset is used', done => { - fixtureEl.innerHTML = [ - '', - '', - '
', - '
', - '
', - '
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('#content') - const scrollSpy = new ScrollSpy(contentEl, { - target: '#navigation', - offset: Manipulator.position(contentEl).top - }) - - spyOn(scrollSpy, '_process').and.callThrough() - - contentEl.addEventListener('scroll', () => { - 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() + it('should correctly select middle navigation option when large offset is used', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '', + '
', + '
', + '
', + '
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('#content') + const scrollSpy = new ScrollSpy(contentEl, { + target: '#navigation', + offset: Manipulator.position(contentEl).top + }) + + spyOn(scrollSpy, '_process').and.callThrough() + + contentEl.addEventListener('scroll', () => { + 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() + resolve() + }) + + contentEl.scrollTop = 550 }) - - contentEl.scrollTop = 550 }) - it('should add the active class to the correct element', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
div 1
', - '
div 2
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('.content') - const scrollSpy = new ScrollSpy(contentEl, { - offset: 0, - target: '.navbar' - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - testElementIsActiveAfterScroll({ - elementSelector: '#a-1', - targetSelector: '#div-1', - contentEl, - scrollSpy, - spy, - cb: () => { - testElementIsActiveAfterScroll({ - elementSelector: '#a-2', - targetSelector: '#div-2', - contentEl, - scrollSpy, - spy, - cb: () => done() - }) - } + it('should add the active class to the correct element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
div 1
', + '
div 2
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('.content') + const scrollSpy = new ScrollSpy(contentEl, { + offset: 0, + target: '.navbar' + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + testElementIsActiveAfterScroll({ + elementSelector: '#a-1', + targetSelector: '#div-1', + contentEl, + scrollSpy, + spy, + cb: () => { + testElementIsActiveAfterScroll({ + elementSelector: '#a-2', + targetSelector: '#div-2', + contentEl, + scrollSpy, + spy, + cb: resolve + }) + } + }) }) }) - it('should add the active class to the correct element (nav markup)', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
div 1
', - '
div 2
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('.content') - const scrollSpy = new ScrollSpy(contentEl, { - offset: 0, - target: '.navbar' - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - testElementIsActiveAfterScroll({ - elementSelector: '#a-1', - targetSelector: '#div-1', - contentEl, - scrollSpy, - spy, - cb: () => { - testElementIsActiveAfterScroll({ - elementSelector: '#a-2', - targetSelector: '#div-2', - contentEl, - scrollSpy, - spy, - cb: () => done() - }) - } + it('should add the active class to the correct element (nav markup)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
div 1
', + '
div 2
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('.content') + const scrollSpy = new ScrollSpy(contentEl, { + offset: 0, + target: '.navbar' + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + testElementIsActiveAfterScroll({ + elementSelector: '#a-1', + targetSelector: '#div-1', + contentEl, + scrollSpy, + spy, + cb: () => { + testElementIsActiveAfterScroll({ + elementSelector: '#a-2', + targetSelector: '#div-2', + contentEl, + scrollSpy, + spy, + cb: resolve + }) + } + }) }) }) - it('should add the active class to the correct element (list-group markup)', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
div 1
', - '
div 2
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('.content') - const scrollSpy = new ScrollSpy(contentEl, { - offset: 0, - target: '.navbar' - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - testElementIsActiveAfterScroll({ - elementSelector: '#a-1', - targetSelector: '#div-1', - contentEl, - scrollSpy, - spy, - cb: () => { - testElementIsActiveAfterScroll({ - elementSelector: '#a-2', - targetSelector: '#div-2', - contentEl, - scrollSpy, - spy, - cb: () => done() - }) - } + it('should add the active class to the correct element (list-group markup)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
div 1
', + '
div 2
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('.content') + const scrollSpy = new ScrollSpy(contentEl, { + offset: 0, + target: '.navbar' + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + testElementIsActiveAfterScroll({ + elementSelector: '#a-1', + targetSelector: '#div-1', + contentEl, + scrollSpy, + spy, + cb: () => { + testElementIsActiveAfterScroll({ + elementSelector: '#a-2', + targetSelector: '#div-2', + contentEl, + scrollSpy, + spy, + cb: resolve + }) + } + }) }) }) - it('should clear selection if above the first section', done => { - fixtureEl.innerHTML = [ - '', - '', - '
', - '
', - '
', - '
', - '
', - '
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('#content') - const scrollSpy = new ScrollSpy(contentEl, { - target: '#navigation', - offset: Manipulator.position(contentEl).top - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - let firstTime = true - - contentEl.addEventListener('scroll', () => { - const active = fixtureEl.querySelector('.active') - - expect(spy).toHaveBeenCalled() - spy.calls.reset() - if (firstTime) { - expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) - expect(active.getAttribute('id')).toEqual('two-link') - firstTime = false - contentEl.scrollTop = 0 - } else { - expect(active).toBeNull() - done() - } + it('should clear selection if above the first section', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '', + '
', + '
', + '
', + '
', + '
', + '
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('#content') + const scrollSpy = new ScrollSpy(contentEl, { + target: '#navigation', + offset: Manipulator.position(contentEl).top + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + let firstTime = true + + contentEl.addEventListener('scroll', () => { + const active = fixtureEl.querySelector('.active') + + expect(spy).toHaveBeenCalled() + spy.calls.reset() + if (firstTime) { + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) + expect(active.getAttribute('id')).toEqual('two-link') + firstTime = false + contentEl.scrollTop = 0 + } else { + expect(active).toBeNull() + resolve() + } + }) + + contentEl.scrollTop = 201 }) - - contentEl.scrollTop = 201 }) - it('should not clear selection if above the first section and first section is at the top', done => { - fixtureEl.innerHTML = [ - '', - '', - '
', - '
', - '
', - '
', - '
', - '
' - ].join('') - - const negativeHeight = -10 - const startOfSectionTwo = 101 - const contentEl = fixtureEl.querySelector('#content') - const scrollSpy = new ScrollSpy(contentEl, { - target: '#navigation', - offset: contentEl.offsetTop - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - let firstTime = true - - contentEl.addEventListener('scroll', () => { - const active = fixtureEl.querySelector('.active') - - expect(spy).toHaveBeenCalled() - spy.calls.reset() - if (firstTime) { - expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) - expect(active.getAttribute('id')).toEqual('two-link') - firstTime = false - contentEl.scrollTop = negativeHeight - } else { - expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) - expect(active.getAttribute('id')).toEqual('one-link') - done() - } + it('should not clear selection if above the first section and first section is at the top', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '', + '
', + '
', + '
', + '
', + '
', + '
' + ].join('') + + const negativeHeight = -10 + const startOfSectionTwo = 101 + const contentEl = fixtureEl.querySelector('#content') + const scrollSpy = new ScrollSpy(contentEl, { + target: '#navigation', + offset: contentEl.offsetTop + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + let firstTime = true + + contentEl.addEventListener('scroll', () => { + const active = fixtureEl.querySelector('.active') + + expect(spy).toHaveBeenCalled() + spy.calls.reset() + if (firstTime) { + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) + expect(active.getAttribute('id')).toEqual('two-link') + firstTime = false + contentEl.scrollTop = negativeHeight + } else { + expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1) + expect(active.getAttribute('id')).toEqual('one-link') + resolve() + } + }) + + contentEl.scrollTop = startOfSectionTwo }) - - contentEl.scrollTop = startOfSectionTwo }) - it('should correctly select navigation element on backward scrolling when each target section height is 100%', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
div 1
', - '
div 2
', - '
div 3
', - '
div 4
', - '
div 5
', - '
' - ].join('') - - const contentEl = fixtureEl.querySelector('.content') - const scrollSpy = new ScrollSpy(contentEl, { - offset: 0, - target: '.navbar' - }) - const spy = spyOn(scrollSpy, '_process').and.callThrough() - - testElementIsActiveAfterScroll({ - elementSelector: '#li-100-5', - targetSelector: '#div-100-5', - scrollSpy, - spy, - contentEl, - cb() { - contentEl.scrollTop = 0 - testElementIsActiveAfterScroll({ - elementSelector: '#li-100-4', - targetSelector: '#div-100-4', - scrollSpy, - spy, - contentEl, - cb() { - contentEl.scrollTop = 0 - testElementIsActiveAfterScroll({ - elementSelector: '#li-100-3', - targetSelector: '#div-100-3', - scrollSpy, - spy, - contentEl, - cb() { - contentEl.scrollTop = 0 - testElementIsActiveAfterScroll({ - elementSelector: '#li-100-2', - targetSelector: '#div-100-2', - scrollSpy, - spy, - contentEl, - cb() { - contentEl.scrollTop = 0 - testElementIsActiveAfterScroll({ - elementSelector: '#li-100-1', - targetSelector: '#div-100-1', - scrollSpy, - spy, - contentEl, - cb: done - }) - } - }) - } - }) - } - }) - } + it('should correctly select navigation element on backward scrolling when each target section height is 100%', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
div 1
', + '
div 2
', + '
div 3
', + '
div 4
', + '
div 5
', + '
' + ].join('') + + const contentEl = fixtureEl.querySelector('.content') + const scrollSpy = new ScrollSpy(contentEl, { + offset: 0, + target: '.navbar' + }) + const spy = spyOn(scrollSpy, '_process').and.callThrough() + + testElementIsActiveAfterScroll({ + elementSelector: '#li-100-5', + targetSelector: '#div-100-5', + scrollSpy, + spy, + contentEl, + cb() { + contentEl.scrollTop = 0 + testElementIsActiveAfterScroll({ + elementSelector: '#li-100-4', + targetSelector: '#div-100-4', + scrollSpy, + spy, + contentEl, + cb() { + contentEl.scrollTop = 0 + testElementIsActiveAfterScroll({ + elementSelector: '#li-100-3', + targetSelector: '#div-100-3', + scrollSpy, + spy, + contentEl, + cb() { + contentEl.scrollTop = 0 + testElementIsActiveAfterScroll({ + elementSelector: '#li-100-2', + targetSelector: '#div-100-2', + scrollSpy, + spy, + contentEl, + cb() { + contentEl.scrollTop = 0 + testElementIsActiveAfterScroll({ + elementSelector: '#li-100-1', + targetSelector: '#div-100-1', + scrollSpy, + spy, + contentEl, + cb: resolve + }) + } + }) + } + }) + } + }) + } + }) }) }) diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index bafa08552..43adee53b 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -1,5 +1,5 @@ import Tab from '../../src/tab' -import { getFixture, clearFixture, jQueryMock } from '../helpers/fixture' +import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' describe('Tab', () => { let fixtureEl @@ -39,314 +39,336 @@ describe('Tab', () => { }) describe('show', () => { - it('should activate element by tab id (using buttons, the preferred semantic way)', done => { - fixtureEl.innerHTML = [ - '', - '
    ', - '
  • ', - '
  • ', - '
' - ].join('') - - const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') - const tab = new Tab(profileTriggerEl) + it('should activate element by tab id (using buttons, the preferred semantic way)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
    ', + '
  • ', + '
  • ', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') + resolve() + }) - profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') - done() + tab.show() }) - - tab.show() }) - it('should activate element by tab id (using links for tabs - not ideal, but still supported)', done => { - fixtureEl.innerHTML = [ - '', - '
    ', - '
  • ', - '
  • ', - '
' - ].join('') - - const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') - const tab = new Tab(profileTriggerEl) + it('should activate element by tab id (using links for tabs - not ideal, but still supported)', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
    ', + '
  • ', + '
  • ', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') + resolve() + }) - profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true') - done() + tab.show() }) - - tab.show() }) - it('should activate element by tab id in ordered list', done => { - fixtureEl.innerHTML = [ - '', - '
    ', - '
  1. ', - '
  2. ', - '
' - ].join('') - - const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') - const tab = new Tab(profileTriggerEl) + it('should activate element by tab id in ordered list', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
    ', + '
  1. ', + '
  2. ', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) - profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - done() + tab.show() }) - - tab.show() }) - it('should activate element by tab id in nav list', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') - - const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') - const tab = new Tab(profileTriggerEl) + it('should activate element by tab id in nav list', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) - profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - done() + tab.show() }) - - tab.show() }) - it('should activate element by tab id in list group', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - ' ', - '
', - '
', - '
', - '
', - '
' - ].join('') - - const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') - const tab = new Tab(profileTriggerEl) + it('should activate element by tab id in list group', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + ' ', + '
', + '
', + '
', + '
', + '
' + ].join('') + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) - profileTriggerEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - done() + tab.show() }) - - tab.show() }) - it('should not fire shown when show is prevented', done => { - fixtureEl.innerHTML = '' + it('should not fire shown when show is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const navEl = fixtureEl.querySelector('div') - const tab = new Tab(navEl) - const expectDone = () => { - setTimeout(() => { - expect().nothing() - done() - }, 30) - } + const navEl = fixtureEl.querySelector('div') + const tab = new Tab(navEl) + const expectDone = () => { + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + } - navEl.addEventListener('show.bs.tab', ev => { - ev.preventDefault() - expectDone() - }) + navEl.addEventListener('show.bs.tab', ev => { + ev.preventDefault() + expectDone() + }) - navEl.addEventListener('shown.bs.tab', () => { - throw new Error('should not trigger shown event') - }) + navEl.addEventListener('shown.bs.tab', () => { + throw new Error('should not trigger shown event') + }) - tab.show() + tab.show() + }) }) - it('should not fire shown when tab is already active', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') - - const triggerActive = fixtureEl.querySelector('button.active') - const tab = new Tab(triggerActive) + it('should not fire shown when tab is already active', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerActive = fixtureEl.querySelector('button.active') + const tab = new Tab(triggerActive) + + triggerActive.addEventListener('shown.bs.tab', () => { + throw new Error('should not trigger shown event') + }) - triggerActive.addEventListener('shown.bs.tab', () => { - throw new Error('should not trigger shown event') + tab.show() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) }) - - tab.show() - setTimeout(() => { - expect().nothing() - done() - }, 30) }) - it('show and shown events should reference correct relatedTarget', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') - - const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') - const secondTab = new Tab(secondTabTrigger) + it('show and shown events should reference correct relatedTarget', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') + const secondTab = new Tab(secondTabTrigger) + + secondTabTrigger.addEventListener('show.bs.tab', ev => { + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') + }) - secondTabTrigger.addEventListener('show.bs.tab', ev => { - expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') - }) + secondTabTrigger.addEventListener('shown.bs.tab', ev => { + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') + expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true') + expect(fixtureEl.querySelector('button:not(.active)').getAttribute('aria-selected')).toEqual('false') + resolve() + }) - secondTabTrigger.addEventListener('shown.bs.tab', ev => { - expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home') - expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true') - expect(fixtureEl.querySelector('button:not(.active)').getAttribute('aria-selected')).toEqual('false') - done() + secondTab.show() }) - - secondTab.show() }) - it('should fire hide and hidden events', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should fire hide and hidden events', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerList = fixtureEl.querySelectorAll('button') - const firstTab = new Tab(triggerList[0]) - const secondTab = new Tab(triggerList[1]) + const triggerList = fixtureEl.querySelectorAll('button') + const firstTab = new Tab(triggerList[0]) + const secondTab = new Tab(triggerList[1]) - let hideCalled = false - triggerList[0].addEventListener('shown.bs.tab', () => { - secondTab.show() - }) + let hideCalled = false + triggerList[0].addEventListener('shown.bs.tab', () => { + secondTab.show() + }) - triggerList[0].addEventListener('hide.bs.tab', ev => { - hideCalled = true - expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') - }) + triggerList[0].addEventListener('hide.bs.tab', ev => { + hideCalled = true + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') + }) - triggerList[0].addEventListener('hidden.bs.tab', ev => { - expect(hideCalled).toBeTrue() - expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') - done() - }) + triggerList[0].addEventListener('hidden.bs.tab', ev => { + expect(hideCalled).toBeTrue() + expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile') + resolve() + }) - firstTab.show() + firstTab.show() + }) }) - it('should not fire hidden when hide is prevented', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const triggerList = fixtureEl.querySelectorAll('button') - const firstTab = new Tab(triggerList[0]) - const secondTab = new Tab(triggerList[1]) - const expectDone = () => { - setTimeout(() => { - expect().nothing() - done() - }, 30) - } + it('should not fire hidden when hide is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const triggerList = fixtureEl.querySelectorAll('button') + const firstTab = new Tab(triggerList[0]) + const secondTab = new Tab(triggerList[1]) + const expectDone = () => { + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + } + + triggerList[0].addEventListener('shown.bs.tab', () => { + secondTab.show() + }) - triggerList[0].addEventListener('shown.bs.tab', () => { - secondTab.show() - }) + triggerList[0].addEventListener('hide.bs.tab', ev => { + ev.preventDefault() + expectDone() + }) - triggerList[0].addEventListener('hide.bs.tab', ev => { - ev.preventDefault() - expectDone() - }) + triggerList[0].addEventListener('hidden.bs.tab', () => { + throw new Error('should not trigger hidden') + }) - triggerList[0].addEventListener('hidden.bs.tab', () => { - throw new Error('should not trigger hidden') + firstTab.show() }) - - firstTab.show() }) - it('should handle removed tabs', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
test 1
', - '
test 2
', - '
test 3
', - '
' - ].join('') - - const secondNavEl = fixtureEl.querySelector('#secondNav') - const btnCloseEl = fixtureEl.querySelector('#btnClose') - const secondNavTab = new Tab(secondNavEl) + it('should handle removed tabs', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
test 3
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + const btnCloseEl = fixtureEl.querySelector('#btnClose') + const secondNavTab = new Tab(secondNavEl) + + secondNavEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelectorAll('.nav-tab')).toHaveSize(2) + resolve() + }) - secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.nav-tab')).toHaveSize(2) - done() - }) + btnCloseEl.addEventListener('click', () => { + const linkEl = btnCloseEl.parentNode + const liEl = linkEl.parentNode + const tabId = linkEl.getAttribute('href') + const tabIdEl = fixtureEl.querySelector(tabId) - btnCloseEl.addEventListener('click', () => { - const linkEl = btnCloseEl.parentNode - const liEl = linkEl.parentNode - const tabId = linkEl.getAttribute('href') - const tabIdEl = fixtureEl.querySelector(tabId) + liEl.remove() + tabIdEl.remove() + secondNavTab.show() + }) - liEl.remove() - tabIdEl.remove() - secondNavTab.show() + btnCloseEl.click() }) - - btnCloseEl.click() }) }) @@ -464,27 +486,29 @@ describe('Tab', () => { }) describe('data-api', () => { - it('should create dynamically a tab', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') - - const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') + it('should create dynamically a tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const secondTabTrigger = fixtureEl.querySelector('#triggerProfile') + + secondTabTrigger.addEventListener('shown.bs.tab', () => { + expect(secondTabTrigger).toHaveClass('active') + expect(fixtureEl.querySelector('#profile')).toHaveClass('active') + resolve() + }) - secondTabTrigger.addEventListener('shown.bs.tab', () => { - expect(secondTabTrigger).toHaveClass('active') - expect(fixtureEl.querySelector('#profile')).toHaveClass('active') - done() + secondTabTrigger.click() }) - - secondTabTrigger.click() }) it('selected tab should deactivate previous selected link in dropdown', () => { @@ -567,202 +591,216 @@ describe('Tab', () => { expect(fixtureEl.querySelector('.nav-link')).not.toHaveClass('active') }) - it('should handle nested tabs', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - ' ', - '
', - '
Nested Tab1 Content
', - '
Nested Tab2 Content
', - '
', - '
', - '
Tab2 Content
', - '
Tab3 Content
', - '
' - ].join('') - - const tab1El = fixtureEl.querySelector('#tab1') - const tabNested2El = fixtureEl.querySelector('#tabNested2') - const xTab1El = fixtureEl.querySelector('#x-tab1') + it('should handle nested tabs', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' ', + '
', + '
Nested Tab1 Content
', + '
Nested Tab2 Content
', + '
', + '
', + '
Tab2 Content
', + '
Tab3 Content
', + '
' + ].join('') + + const tab1El = fixtureEl.querySelector('#tab1') + const tabNested2El = fixtureEl.querySelector('#tabNested2') + const xTab1El = fixtureEl.querySelector('#x-tab1') + + tabNested2El.addEventListener('shown.bs.tab', () => { + expect(xTab1El).toHaveClass('active') + resolve() + }) - tabNested2El.addEventListener('shown.bs.tab', () => { - expect(xTab1El).toHaveClass('active') - done() - }) + tab1El.addEventListener('shown.bs.tab', () => { + expect(xTab1El).toHaveClass('active') + tabNested2El.click() + }) - tab1El.addEventListener('shown.bs.tab', () => { - expect(xTab1El).toHaveClass('active') - tabNested2El.click() + tab1El.click() }) - - tab1El.click() }) - it('should not remove fade class if no active pane is present', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') - - const triggerTabProfileEl = fixtureEl.querySelector('#tab-profile') - const triggerTabHomeEl = fixtureEl.querySelector('#tab-home') - const tabProfileEl = fixtureEl.querySelector('#profile') - const tabHomeEl = fixtureEl.querySelector('#home') + it('should not remove fade class if no active pane is present', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerTabProfileEl = fixtureEl.querySelector('#tab-profile') + const triggerTabHomeEl = fixtureEl.querySelector('#tab-home') + const tabProfileEl = fixtureEl.querySelector('#profile') + const tabHomeEl = fixtureEl.querySelector('#home') + + triggerTabProfileEl.addEventListener('shown.bs.tab', () => { + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).toHaveClass('show') - triggerTabProfileEl.addEventListener('shown.bs.tab', () => { - expect(tabProfileEl).toHaveClass('fade') - expect(tabProfileEl).toHaveClass('show') + triggerTabHomeEl.addEventListener('shown.bs.tab', () => { + expect(tabProfileEl).toHaveClass('fade') + expect(tabProfileEl).not.toHaveClass('show') - triggerTabHomeEl.addEventListener('shown.bs.tab', () => { - expect(tabProfileEl).toHaveClass('fade') - expect(tabProfileEl).not.toHaveClass('show') + expect(tabHomeEl).toHaveClass('fade') + expect(tabHomeEl).toHaveClass('show') - expect(tabHomeEl).toHaveClass('fade') - expect(tabHomeEl).toHaveClass('show') + resolve() + }) - done() + triggerTabHomeEl.click() }) - triggerTabHomeEl.click() + triggerTabProfileEl.click() }) - - triggerTabProfileEl.click() }) - it('should not add show class to tab panes if there is no `.fade` class', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
test 1
', - '
test 2
', - '
' - ].join('') - - const secondNavEl = fixtureEl.querySelector('#secondNav') + it('should not add show class to tab panes if there is no `.fade` class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + + secondNavEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelectorAll('.show')).toHaveSize(0) + resolve() + }) - secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.show')).toHaveSize(0) - done() + secondNavEl.click() }) - - secondNavEl.click() }) - it('should add show class to tab panes if there is a `.fade` class', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
test 1
', - '
test 2
', - '
' - ].join('') - - const secondNavEl = fixtureEl.querySelector('#secondNav') + it('should add show class to tab panes if there is a `.fade` class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
test 1
', + '
test 2
', + '
' + ].join('') + + const secondNavEl = fixtureEl.querySelector('#secondNav') + + secondNavEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelectorAll('.show')).toHaveSize(1) + resolve() + }) - secondNavEl.addEventListener('shown.bs.tab', () => { - expect(fixtureEl.querySelectorAll('.show')).toHaveSize(1) - done() + secondNavEl.click() }) - - secondNavEl.click() }) - it('should prevent default when the trigger is or ', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should prevent default when the trigger is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const tabEl = fixtureEl.querySelector('[href="#test2"]') - spyOn(Event.prototype, 'preventDefault').and.callThrough() + const tabEl = fixtureEl.querySelector('[href="#test2"]') + spyOn(Event.prototype, 'preventDefault').and.callThrough() - tabEl.addEventListener('shown.bs.tab', () => { - expect(tabEl).toHaveClass('active') - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() - }) + tabEl.addEventListener('shown.bs.tab', () => { + expect(tabEl).toHaveClass('active') + expect(Event.prototype.preventDefault).toHaveBeenCalled() + resolve() + }) - tabEl.click() + tabEl.click() + }) }) - it('should not fire shown when tab has disabled attribute', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') + it('should not fire shown when tab has disabled attribute', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') + + const triggerDisabled = fixtureEl.querySelector('button[disabled]') + triggerDisabled.addEventListener('shown.bs.tab', () => { + throw new Error('should not trigger shown event') + }) - const triggerDisabled = fixtureEl.querySelector('button[disabled]') - triggerDisabled.addEventListener('shown.bs.tab', () => { - throw new Error('should not trigger shown event') + triggerDisabled.click() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) }) - - triggerDisabled.click() - setTimeout(() => { - expect().nothing() - done() - }, 30) }) - it('should not fire shown when tab has disabled class', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - '
', - '
' - ].join('') + it('should not fire shown when tab has disabled class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + '
', + '
' + ].join('') - const triggerDisabled = fixtureEl.querySelector('a.disabled') + const triggerDisabled = fixtureEl.querySelector('a.disabled') - triggerDisabled.addEventListener('shown.bs.tab', () => { - throw new Error('should not trigger shown event') - }) + triggerDisabled.addEventListener('shown.bs.tab', () => { + throw new Error('should not trigger shown event') + }) - triggerDisabled.click() - setTimeout(() => { - expect().nothing() - done() - }, 30) + triggerDisabled.click() + setTimeout(() => { + expect().nothing() + resolve() + }, 30) + }) }) }) }) diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index c4ea43808..9134a8410 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -1,5 +1,5 @@ import Toast from '../../src/toast' -import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' describe('Toast', () => { let fixtureEl @@ -36,52 +36,56 @@ describe('Toast', () => { expect(toastByElement._element).toEqual(toastEl) }) - it('should allow to config in js', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') + it('should allow to config in js', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('div') + const toast = new Toast(toastEl, { + delay: 1 + }) - const toastEl = fixtureEl.querySelector('div') - const toast = new Toast(toastEl, { - delay: 1 - }) + toastEl.addEventListener('shown.bs.toast', () => { + expect(toastEl).toHaveClass('show') + resolve() + }) - toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl).toHaveClass('show') - done() + toast.show() }) - - toast.show() }) - it('should close toast when close element with data-bs-dismiss attribute is set', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') + it('should close toast when close element with data-bs-dismiss attribute is set', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - const toastEl = fixtureEl.querySelector('div') - const toast = new Toast(toastEl) + const toastEl = fixtureEl.querySelector('div') + const toast = new Toast(toastEl) - toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl).toHaveClass('show') + toastEl.addEventListener('shown.bs.toast', () => { + expect(toastEl).toHaveClass('show') - const button = toastEl.querySelector('.btn-close') + const button = toastEl.querySelector('.btn-close') - button.click() - }) + button.click() + }) - toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl).not.toHaveClass('show') - done() - }) + toastEl.addEventListener('hidden.bs.toast', () => { + expect(toastEl).not.toHaveClass('show') + resolve() + }) - toast.show() + toast.show() + }) }) }) @@ -111,304 +115,324 @@ describe('Toast', () => { }) describe('show', () => { - it('should auto hide', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) - - toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl).not.toHaveClass('show') - done() - }) - - toast.show() - }) - - it('should not add fade class', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + it('should auto hide', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + toastEl.addEventListener('hidden.bs.toast', () => { + expect(toastEl).not.toHaveClass('show') + resolve() + }) - toastEl.addEventListener('shown.bs.toast', () => { - expect(toastEl).not.toHaveClass('fade') - done() + toast.show() }) - - toast.show() }) - it('should not trigger shown if show is prevented', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') + it('should not add fade class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) - - const assertDone = () => { - setTimeout(() => { - expect(toastEl).not.toHaveClass('show') - done() - }, 20) - } + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - toastEl.addEventListener('show.bs.toast', event => { - event.preventDefault() - assertDone() - }) + toastEl.addEventListener('shown.bs.toast', () => { + expect(toastEl).not.toHaveClass('fade') + resolve() + }) - toastEl.addEventListener('shown.bs.toast', () => { - throw new Error('shown event should not be triggered if show is prevented') + toast.show() }) - - toast.show() }) - it('should clear timeout if toast is shown again before it is hidden', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + it('should not trigger shown if show is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + const assertDone = () => { + setTimeout(() => { + expect(toastEl).not.toHaveClass('show') + resolve() + }, 20) + } + + toastEl.addEventListener('show.bs.toast', event => { + event.preventDefault() + assertDone() + }) - setTimeout(() => { - toast._config.autohide = false toastEl.addEventListener('shown.bs.toast', () => { - expect(toast._clearTimeout).toHaveBeenCalled() - expect(toast._timeout).toBeNull() - done() + throw new Error('shown event should not be triggered if show is prevented') }) - toast.show() - }, toast._config.delay / 2) - spyOn(toast, '_clearTimeout').and.callThrough() - - toast.show() + toast.show() + }) }) - it('should clear timeout if toast is interacted with mouse', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) - const spy = spyOn(toast, '_clearTimeout').and.callThrough() + it('should clear timeout if toast is shown again before it is hidden', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') - setTimeout(() => { - spy.calls.reset() + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - toastEl.addEventListener('mouseover', () => { - expect(toast._clearTimeout).toHaveBeenCalledTimes(1) - expect(toast._timeout).toBeNull() - done() - }) + setTimeout(() => { + toast._config.autohide = false + toastEl.addEventListener('shown.bs.toast', () => { + expect(toast._clearTimeout).toHaveBeenCalled() + expect(toast._timeout).toBeNull() + resolve() + }) + toast.show() + }, toast._config.delay / 2) - const mouseOverEvent = createEvent('mouseover') - toastEl.dispatchEvent(mouseOverEvent) - }, toast._config.delay / 2) + spyOn(toast, '_clearTimeout').and.callThrough() - toast.show() + toast.show() + }) }) - it('should clear timeout if toast is interacted with keyboard', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - ' a simple toast', - ' ', - '
', - '
' - ].join('') + it('should clear timeout if toast is interacted with mouse', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) - const spy = spyOn(toast, '_clearTimeout').and.callThrough() + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + const spy = spyOn(toast, '_clearTimeout').and.callThrough() - setTimeout(() => { - spy.calls.reset() + setTimeout(() => { + spy.calls.reset() - toastEl.addEventListener('focusin', () => { - expect(toast._clearTimeout).toHaveBeenCalledTimes(1) - expect(toast._timeout).toBeNull() - done() - }) + toastEl.addEventListener('mouseover', () => { + expect(toast._clearTimeout).toHaveBeenCalledTimes(1) + expect(toast._timeout).toBeNull() + resolve() + }) - const insideFocusable = toastEl.querySelector('button') - insideFocusable.focus() - }, toast._config.delay / 2) + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) - toast.show() + toast.show() + }) }) - it('should still auto hide after being interacted with mouse and keyboard', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - ' a simple toast', - ' ', - '
', - '
' - ].join('') + it('should clear timeout if toast is interacted with keyboard', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' a simple toast', + ' ', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + const spy = spyOn(toast, '_clearTimeout').and.callThrough() - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + setTimeout(() => { + spy.calls.reset() + + toastEl.addEventListener('focusin', () => { + expect(toast._clearTimeout).toHaveBeenCalledTimes(1) + expect(toast._timeout).toBeNull() + resolve() + }) - setTimeout(() => { - toastEl.addEventListener('mouseover', () => { const insideFocusable = toastEl.querySelector('button') insideFocusable.focus() - }) + }, toast._config.delay / 2) - toastEl.addEventListener('focusin', () => { - const mouseOutEvent = createEvent('mouseout') - toastEl.dispatchEvent(mouseOutEvent) - }) + toast.show() + }) + }) - toastEl.addEventListener('mouseout', () => { - const outsideFocusable = document.getElementById('outside-focusable') - outsideFocusable.focus() - }) + it('should still auto hide after being interacted with mouse and keyboard', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' a simple toast', + ' ', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - toastEl.addEventListener('focusout', () => { - expect(toast._timeout).not.toBeNull() - done() - }) - - const mouseOverEvent = createEvent('mouseover') - toastEl.dispatchEvent(mouseOverEvent) - }, toast._config.delay / 2) + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) + + toastEl.addEventListener('focusin', () => { + const mouseOutEvent = createEvent('mouseout') + toastEl.dispatchEvent(mouseOutEvent) + }) + + toastEl.addEventListener('mouseout', () => { + const outsideFocusable = document.getElementById('outside-focusable') + outsideFocusable.focus() + }) + + toastEl.addEventListener('focusout', () => { + expect(toast._timeout).not.toBeNull() + resolve() + }) + + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) - toast.show() + toast.show() + }) }) - it('should not auto hide if focus leaves but mouse pointer remains inside', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - ' a simple toast', - ' ', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + it('should not auto hide if focus leaves but mouse pointer remains inside', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' a simple toast', + ' ', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - setTimeout(() => { - toastEl.addEventListener('mouseover', () => { - const insideFocusable = toastEl.querySelector('button') - insideFocusable.focus() - }) + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) - toastEl.addEventListener('focusin', () => { - const outsideFocusable = document.getElementById('outside-focusable') - outsideFocusable.focus() - }) + toastEl.addEventListener('focusin', () => { + const outsideFocusable = document.getElementById('outside-focusable') + outsideFocusable.focus() + }) - toastEl.addEventListener('focusout', () => { - expect(toast._timeout).toBeNull() - done() - }) + toastEl.addEventListener('focusout', () => { + expect(toast._timeout).toBeNull() + resolve() + }) - const mouseOverEvent = createEvent('mouseover') - toastEl.dispatchEvent(mouseOverEvent) - }, toast._config.delay / 2) + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) - toast.show() + toast.show() + }) }) - it('should not auto hide if mouse pointer leaves but focus remains inside', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
', - ' a simple toast', - ' ', - '
', - '
' - ].join('') + it('should not auto hide if mouse pointer leaves but focus remains inside', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
', + ' a simple toast', + ' ', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) - - setTimeout(() => { - toastEl.addEventListener('mouseover', () => { - const insideFocusable = toastEl.querySelector('button') - insideFocusable.focus() - }) + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) - toastEl.addEventListener('focusin', () => { - const mouseOutEvent = createEvent('mouseout') - toastEl.dispatchEvent(mouseOutEvent) - }) + toastEl.addEventListener('focusin', () => { + const mouseOutEvent = createEvent('mouseout') + toastEl.dispatchEvent(mouseOutEvent) + }) - toastEl.addEventListener('mouseout', () => { - expect(toast._timeout).toBeNull() - done() - }) + toastEl.addEventListener('mouseout', () => { + expect(toast._timeout).toBeNull() + resolve() + }) - const mouseOverEvent = createEvent('mouseover') - toastEl.dispatchEvent(mouseOverEvent) - }, toast._config.delay / 2) + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) - toast.show() + toast.show() + }) }) }) describe('hide', () => { - it('should allow to hide toast manually', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') + it('should allow to hide toast manually', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + toastEl.addEventListener('shown.bs.toast', () => { + toast.hide() + }) - toastEl.addEventListener('shown.bs.toast', () => { - toast.hide() - }) + toastEl.addEventListener('hidden.bs.toast', () => { + expect(toastEl).not.toHaveClass('show') + resolve() + }) - toastEl.addEventListener('hidden.bs.toast', () => { - expect(toastEl).not.toHaveClass('show') - done() + toast.show() }) - - toast.show() }) it('should do nothing when we call hide on a non shown toast', () => { @@ -424,39 +448,41 @@ describe('Toast', () => { expect(toastEl.classList.contains).toHaveBeenCalled() }) - it('should not trigger hidden if hide is prevented', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') - - const toastEl = fixtureEl.querySelector('.toast') - const toast = new Toast(toastEl) + it('should not trigger hidden if hide is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + const assertDone = () => { + setTimeout(() => { + expect(toastEl).toHaveClass('show') + resolve() + }, 20) + } - const assertDone = () => { - setTimeout(() => { - expect(toastEl).toHaveClass('show') - done() - }, 20) - } + toastEl.addEventListener('shown.bs.toast', () => { + toast.hide() + }) - toastEl.addEventListener('shown.bs.toast', () => { - toast.hide() - }) + toastEl.addEventListener('hide.bs.toast', event => { + event.preventDefault() + assertDone() + }) - toastEl.addEventListener('hide.bs.toast', event => { - event.preventDefault() - assertDone() - }) + toastEl.addEventListener('hidden.bs.toast', () => { + throw new Error('hidden event should not be triggered if hide is prevented') + }) - toastEl.addEventListener('hidden.bs.toast', () => { - throw new Error('hidden event should not be triggered if hide is prevented') + toast.show() }) - - toast.show() }) }) @@ -475,34 +501,36 @@ describe('Toast', () => { expect(Toast.getInstance(toastEl)).toBeNull() }) - it('should allow to destroy toast and hide it before that', done => { - fixtureEl.innerHTML = [ - '
', - '
', - ' a simple toast', - '
', - '
' - ].join('') + it('should allow to destroy toast and hide it before that', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + ' a simple toast', + '
', + '
' + ].join('') + + const toastEl = fixtureEl.querySelector('div') + const toast = new Toast(toastEl) + const expected = () => { + expect(toastEl).toHaveClass('show') + expect(Toast.getInstance(toastEl)).not.toBeNull() - const toastEl = fixtureEl.querySelector('div') - const toast = new Toast(toastEl) - const expected = () => { - expect(toastEl).toHaveClass('show') - expect(Toast.getInstance(toastEl)).not.toBeNull() + toast.dispose() - toast.dispose() + expect(Toast.getInstance(toastEl)).toBeNull() + expect(toastEl).not.toHaveClass('show') - expect(Toast.getInstance(toastEl)).toBeNull() - expect(toastEl).not.toHaveClass('show') + resolve() + } - done() - } + toastEl.addEventListener('shown.bs.toast', () => { + setTimeout(expected, 1) + }) - toastEl.addEventListener('shown.bs.toast', () => { - setTimeout(expected, 1) + toast.show() }) - - toast.show() }) }) diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 3feacf7b4..4a9a6d3bb 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -94,52 +94,56 @@ describe('Tooltip', () => { expect(tooltip._config.content).toEqual('7') }) - it('should enable selector delegation', done => { - fixtureEl.innerHTML = '
' + it('should enable selector delegation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const containerEl = fixtureEl.querySelector('div') + const tooltipContainer = new Tooltip(containerEl, { + selector: 'a[rel="tooltip"]', + trigger: 'click' + }) - const containerEl = fixtureEl.querySelector('div') - const tooltipContainer = new Tooltip(containerEl, { - selector: 'a[rel="tooltip"]', - trigger: 'click' - }) + containerEl.innerHTML = '' - containerEl.innerHTML = '' + const tooltipInContainerEl = containerEl.querySelector('a') - const tooltipInContainerEl = containerEl.querySelector('a') + tooltipInContainerEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() + tooltipContainer.dispose() + resolve() + }) - tooltipInContainerEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() - tooltipContainer.dispose() - done() + tooltipInContainerEl.click() }) - - tooltipInContainerEl.click() }) - it('should create offset modifier when offset is passed as a function', done => { - fixtureEl.innerHTML = '' + it('should create offset modifier when offset is passed as a function', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const getOffset = jasmine.createSpy('getOffset').and.returnValue([10, 20]) - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - offset: getOffset, - popperConfig: { - onFirstUpdate: state => { - expect(getOffset).toHaveBeenCalledWith({ - popper: state.rects.popper, - reference: state.rects.reference, - placement: state.placement - }, tooltipEl) - done() + const getOffset = jasmine.createSpy('getOffset').and.returnValue([10, 20]) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + offset: getOffset, + popperConfig: { + onFirstUpdate: state => { + expect(getOffset).toHaveBeenCalledWith({ + popper: state.rects.popper, + reference: state.rects.reference, + placement: state.placement + }, tooltipEl) + resolve() + } } - } - }) + }) - const offset = tooltip._getOffset() + const offset = tooltip._getOffset() - expect(offset).toEqual(jasmine.any(Function)) + expect(offset).toEqual(jasmine.any(Function)) - tooltip.show() + tooltip.show() + }) }) it('should create offset modifier when offset option is passed in data attribute', () => { @@ -192,42 +196,46 @@ describe('Tooltip', () => { }) describe('enable', () => { - it('should enable a tooltip', done => { - fixtureEl.innerHTML = '' + it('should enable a tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltip.enable() + tooltip.enable() - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) }) describe('disable', () => { - it('should disable tooltip', done => { - fixtureEl.innerHTML = '' + it('should disable tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltip.disable() + tooltip.disable() - tooltipEl.addEventListener('show.bs.tooltip', () => { - throw new Error('should not show a disabled tooltip') - }) + tooltipEl.addEventListener('show.bs.tooltip', () => { + throw new Error('should not show a disabled tooltip') + }) - tooltip.show() + tooltip.show() - setTimeout(() => { - expect().nothing() - done() - }, 10) + setTimeout(() => { + expect().nothing() + resolve() + }, 10) + }) }) }) @@ -247,96 +255,106 @@ describe('Tooltip', () => { }) describe('toggle', () => { - it('should do nothing if disabled', done => { - fixtureEl.innerHTML = '' + it('should do nothing if disabled', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltip.disable() + tooltip.disable() - tooltipEl.addEventListener('show.bs.tooltip', () => { - throw new Error('should not show a disabled tooltip') - }) + tooltipEl.addEventListener('show.bs.tooltip', () => { + throw new Error('should not show a disabled tooltip') + }) - tooltip.toggle() + tooltip.toggle() - setTimeout(() => { - expect().nothing() - done() - }, 10) + setTimeout(() => { + expect().nothing() + resolve() + }, 10) + }) }) - it('should show a tooltip', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() + resolve() + }) - tooltip.toggle() + tooltip.toggle() + }) }) - it('should call toggle and show the tooltip when trigger is "click"', done => { - fixtureEl.innerHTML = '' + it('should call toggle and show the tooltip when trigger is "click"', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - trigger: 'click' - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + trigger: 'click' + }) - spyOn(tooltip, 'toggle').and.callThrough() + spyOn(tooltip, 'toggle').and.callThrough() - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(tooltip.toggle).toHaveBeenCalled() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(tooltip.toggle).toHaveBeenCalled() + resolve() + }) - tooltipEl.click() + tooltipEl.click() + }) }) - it('should hide a tooltip', done => { - fixtureEl.innerHTML = '' + it('should hide a tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + tooltipEl.addEventListener('shown.bs.tooltip', () => { + tooltip.toggle() + }) + + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).toBeNull() + resolve() + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { tooltip.toggle() }) + }) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).toBeNull() - done() - }) + it('should call toggle and hide the tooltip when trigger is "click"', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - tooltip.toggle() - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + trigger: 'click' + }) - it('should call toggle and hide the tooltip when trigger is "click"', done => { - fixtureEl.innerHTML = '' + spyOn(tooltip, 'toggle').and.callThrough() - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - trigger: 'click' - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + tooltipEl.click() + }) - spyOn(tooltip, 'toggle').and.callThrough() + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + expect(tooltip.toggle).toHaveBeenCalled() + resolve() + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { tooltipEl.click() }) - - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - expect(tooltip.toggle).toHaveBeenCalled() - done() - }) - - tooltipEl.click() }) }) @@ -367,239 +385,263 @@ describe('Tooltip', () => { expect(removeEventSpy.calls.allArgs()).toEqual(expectedArgs) }) - it('should destroy a tooltip after it is shown and hidden', done => { - fixtureEl.innerHTML = '' + it('should destroy a tooltip after it is shown and hidden', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - tooltip.hide() - }) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - tooltip.dispose() - expect(tooltip.tip).toBeNull() - expect(Tooltip.getInstance(tooltipEl)).toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + tooltip.hide() + }) + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + tooltip.dispose() + expect(tooltip.tip).toBeNull() + expect(Tooltip.getInstance(tooltipEl)).toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should destroy a tooltip and remove it from the dom', done => { - fixtureEl.innerHTML = '' + it('should destroy a tooltip and remove it from the dom', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() - tooltip.dispose() + tooltip.dispose() - expect(document.querySelector('.tooltip')).toBeNull() - done() - }) + expect(document.querySelector('.tooltip')).toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) }) describe('show', () => { - it('should show a tooltip', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tooltipShown = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') - expect(tooltipShown).not.toBeNull() - expect(tooltipEl.getAttribute('aria-describedby')).toEqual(tooltipShown.getAttribute('id')) - expect(tooltipShown.getAttribute('id')).toContain('tooltip') - done() - }) + expect(tooltipShown).not.toBeNull() + expect(tooltipEl.getAttribute('aria-describedby')).toEqual(tooltipShown.getAttribute('id')) + expect(tooltipShown.getAttribute('id')).toContain('tooltip') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip when hovering a child element', done => { - fixtureEl.innerHTML = [ - '', - ' ', - ' ', - ' ', - ' ', - '' - ].join('') + it('should show a tooltip when hovering a child element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + ' ', + ' ', + ' ', + ' ', + '' + ].join('') - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - spyOn(tooltip, 'show') + spyOn(tooltip, 'show') - tooltipEl.querySelector('rect').dispatchEvent(createEvent('mouseover', { bubbles: true })) + tooltipEl.querySelector('rect').dispatchEvent(createEvent('mouseover', { bubbles: true })) - setTimeout(() => { - expect(tooltip.show).toHaveBeenCalled() - done() - }, 0) + setTimeout(() => { + expect(tooltip.show).toHaveBeenCalled() + resolve() + }, 0) + }) }) - it('should show a tooltip on mobile', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip on mobile', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) - document.documentElement.ontouchstart = noop + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + document.documentElement.ontouchstart = noop - spyOn(EventHandler, 'on').and.callThrough() + spyOn(EventHandler, 'on').and.callThrough() - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() - expect(EventHandler.on).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) - document.documentElement.ontouchstart = undefined - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() + expect(EventHandler.on).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) + document.documentElement.ontouchstart = undefined + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip relative to placement option', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip relative to placement option', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: 'bottom' - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + placement: 'bottom' + }) - tooltipEl.addEventListener('inserted.bs.tooltip', () => { - expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') - }) + tooltipEl.addEventListener('inserted.bs.tooltip', () => { + expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') - expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('bottom') - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(tooltip._getTipElement()).toHaveClass('bs-tooltip-auto') + expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('bottom') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should not error when trying to show a tooltip that has been removed from the dom', done => { - fixtureEl.innerHTML = '' + it('should not error when trying to show a tooltip that has been removed from the dom', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - const firstCallback = () => { - tooltipEl.removeEventListener('shown.bs.tooltip', firstCallback) - let tooltipShown = document.querySelector('.tooltip') + const firstCallback = () => { + tooltipEl.removeEventListener('shown.bs.tooltip', firstCallback) + let tooltipShown = document.querySelector('.tooltip') - tooltipShown.remove() + tooltipShown.remove() - tooltipEl.addEventListener('shown.bs.tooltip', () => { - tooltipShown = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + tooltipShown = document.querySelector('.tooltip') - expect(tooltipShown).not.toBeNull() - done() - }) + expect(tooltipShown).not.toBeNull() + resolve() + }) - tooltip.show() - } + tooltip.show() + } - tooltipEl.addEventListener('shown.bs.tooltip', firstCallback) + tooltipEl.addEventListener('shown.bs.tooltip', firstCallback) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with a dom element container', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with a dom element container', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - container: fixtureEl - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + container: fixtureEl + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with a jquery element container', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with a jquery element container', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - container: { - 0: fixtureEl, - jquery: 'jQuery' - } - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + container: { + 0: fixtureEl, + jquery: 'jQuery' + } + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with a selector in container', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with a selector in container', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - container: '#fixture' - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + container: '#fixture' + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(fixtureEl.querySelector('.tooltip')).not.toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with placement as a function', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with placement as a function', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const spy = jasmine.createSpy('placement').and.returnValue('top') - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - placement: spy - }) + const spy = jasmine.createSpy('placement').and.returnValue('top') + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + placement: spy + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).not.toBeNull() - expect(spy).toHaveBeenCalled() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).not.toBeNull() + expect(spy).toHaveBeenCalled() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip without the animation', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip without the animation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - animation: false - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + animation: false + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tip = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tip = document.querySelector('.tooltip') - expect(tip).not.toBeNull() - expect(tip).not.toHaveClass('fade') - done() - }) + expect(tip).not.toBeNull() + expect(tip).not.toHaveClass('fade') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) it('should throw an error the element is not visible', () => { @@ -615,352 +657,382 @@ describe('Tooltip', () => { } }) - it('should not show a tooltip if show.bs.tooltip is prevented', done => { - fixtureEl.innerHTML = '' - - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) - - const expectedDone = () => { - setTimeout(() => { - expect(document.querySelector('.tooltip')).toBeNull() - done() - }, 10) - } + it('should not show a tooltip if show.bs.tooltip is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - tooltipEl.addEventListener('show.bs.tooltip', ev => { - ev.preventDefault() - expectedDone() - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - throw new Error('Tooltip should not be shown') - }) + const expectedDone = () => { + setTimeout(() => { + expect(document.querySelector('.tooltip')).toBeNull() + resolve() + }, 10) + } - tooltip.show() - }) + tooltipEl.addEventListener('show.bs.tooltip', ev => { + ev.preventDefault() + expectedDone() + }) - it('should show tooltip if leave event hasn\'t occurred before delay expires', done => { - fixtureEl.innerHTML = '' + tooltipEl.addEventListener('shown.bs.tooltip', () => { + throw new Error('Tooltip should not be shown') + }) - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - delay: 150 + tooltip.show() }) - - spyOn(tooltip, 'show') - - setTimeout(() => { - expect(tooltip.show).not.toHaveBeenCalled() - }, 100) - - setTimeout(() => { - expect(tooltip.show).toHaveBeenCalled() - done() - }, 200) - - tooltipEl.dispatchEvent(createEvent('mouseover')) }) - it('should not show tooltip if leave event occurs before delay expires', done => { - fixtureEl.innerHTML = '' + it('should show tooltip if leave event hasn\'t occurred before delay expires', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - delay: 150 - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + delay: 150 + }) - spyOn(tooltip, 'show') + spyOn(tooltip, 'show') - setTimeout(() => { - expect(tooltip.show).not.toHaveBeenCalled() - tooltipEl.dispatchEvent(createEvent('mouseover')) - }, 100) + setTimeout(() => { + expect(tooltip.show).not.toHaveBeenCalled() + }, 100) - setTimeout(() => { - expect(tooltip.show).toHaveBeenCalled() - expect(document.querySelectorAll('.tooltip')).toHaveSize(0) - done() - }, 200) + setTimeout(() => { + expect(tooltip.show).toHaveBeenCalled() + resolve() + }, 200) - tooltipEl.dispatchEvent(createEvent('mouseover')) + tooltipEl.dispatchEvent(createEvent('mouseover')) + }) }) - it('should not hide tooltip if leave event occurs and enter event occurs within the hide delay', done => { - fixtureEl.innerHTML = '' + it('should not show tooltip if leave event occurs before delay expires', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - delay: { - show: 0, - hide: 150 - } - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + delay: 150 + }) - setTimeout(() => { - expect(tooltip._getTipElement()).toHaveClass('show') - tooltipEl.dispatchEvent(createEvent('mouseout')) + spyOn(tooltip, 'show') setTimeout(() => { - expect(tooltip._getTipElement()).toHaveClass('show') + expect(tooltip.show).not.toHaveBeenCalled() tooltipEl.dispatchEvent(createEvent('mouseover')) }, 100) setTimeout(() => { - expect(tooltip._getTipElement()).toHaveClass('show') - expect(document.querySelectorAll('.tooltip')).toHaveSize(1) - done() + expect(tooltip.show).toHaveBeenCalled() + expect(document.querySelectorAll('.tooltip')).toHaveSize(0) + resolve() }, 200) - }, 10) - tooltipEl.dispatchEvent(createEvent('mouseover')) + tooltipEl.dispatchEvent(createEvent('mouseover')) + }) }) - it('should not hide tooltip if leave event occurs and interaction remains inside trigger', done => { - fixtureEl.innerHTML = [ - '', - 'Trigger', - 'the tooltip', - '' - ].join('') - - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) - const triggerChild = tooltipEl.querySelector('b') - - spyOn(tooltip, 'hide').and.callThrough() + it('should not hide tooltip if leave event occurs and enter event occurs within the hide delay', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - tooltipEl.addEventListener('mouseover', () => { - const moveMouseToChildEvent = createEvent('mouseout') - Object.defineProperty(moveMouseToChildEvent, 'relatedTarget', { - value: triggerChild + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + delay: { + show: 0, + hide: 150 + } }) - tooltipEl.dispatchEvent(moveMouseToChildEvent) - }) + setTimeout(() => { + expect(tooltip._getTipElement()).toHaveClass('show') + tooltipEl.dispatchEvent(createEvent('mouseout')) + + setTimeout(() => { + expect(tooltip._getTipElement()).toHaveClass('show') + tooltipEl.dispatchEvent(createEvent('mouseover')) + }, 100) + + setTimeout(() => { + expect(tooltip._getTipElement()).toHaveClass('show') + expect(document.querySelectorAll('.tooltip')).toHaveSize(1) + resolve() + }, 200) + }, 10) - tooltipEl.addEventListener('mouseout', () => { - expect(tooltip.hide).not.toHaveBeenCalled() - done() + tooltipEl.dispatchEvent(createEvent('mouseover')) }) - - tooltipEl.dispatchEvent(createEvent('mouseover')) }) - it('should properly maintain tooltip state if leave event occurs and enter event occurs during hide transition', done => { - // Style this tooltip to give it plenty of room for popper to do what it wants - fixtureEl.innerHTML = 'Trigger' + it('should not hide tooltip if leave event occurs and interaction remains inside trigger', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + 'Trigger', + 'the tooltip', + '' + ].join('') - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + const triggerChild = tooltipEl.querySelector('b') + + spyOn(tooltip, 'hide').and.callThrough() + + tooltipEl.addEventListener('mouseover', () => { + const moveMouseToChildEvent = createEvent('mouseout') + Object.defineProperty(moveMouseToChildEvent, 'relatedTarget', { + value: triggerChild + }) + + tooltipEl.dispatchEvent(moveMouseToChildEvent) + }) - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.15s', - transitionDelay: '0s' + tooltipEl.addEventListener('mouseout', () => { + expect(tooltip.hide).not.toHaveBeenCalled() + resolve() + }) + + tooltipEl.dispatchEvent(createEvent('mouseover')) }) + }) - setTimeout(() => { - expect(tooltip._popper).not.toBeNull() - expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('top') - tooltipEl.dispatchEvent(createEvent('mouseout')) + it('should properly maintain tooltip state if leave event occurs and enter event occurs during hide transition', () => { + return new Promise(resolve => { + // Style this tooltip to give it plenty of room for popper to do what it wants + fixtureEl.innerHTML = 'Trigger' - setTimeout(() => { - expect(tooltip._getTipElement()).not.toHaveClass('show') - tooltipEl.dispatchEvent(createEvent('mouseover')) - }, 100) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.15s', + transitionDelay: '0s' + }) setTimeout(() => { expect(tooltip._popper).not.toBeNull() expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('top') - done() - }, 200) - }, 10) + tooltipEl.dispatchEvent(createEvent('mouseout')) + + setTimeout(() => { + expect(tooltip._getTipElement()).not.toHaveClass('show') + tooltipEl.dispatchEvent(createEvent('mouseover')) + }, 100) + + setTimeout(() => { + expect(tooltip._popper).not.toBeNull() + expect(tooltip._getTipElement().getAttribute('data-popper-placement')).toEqual('top') + resolve() + }, 200) + }, 10) - tooltipEl.dispatchEvent(createEvent('mouseover')) + tooltipEl.dispatchEvent(createEvent('mouseover')) + }) }) - it('should only trigger inserted event if a new tooltip element was created', done => { - fixtureEl.innerHTML = '' - - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + it('should only trigger inserted event if a new tooltip element was created', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.15s', - transitionDelay: '0s' - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - const insertedFunc = jasmine.createSpy() - tooltipEl.addEventListener('inserted.bs.tooltip', insertedFunc) - - setTimeout(() => { - expect(insertedFunc).toHaveBeenCalledTimes(1) - tooltip.hide() + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.15s', + transitionDelay: '0s' + }) - setTimeout(() => { - tooltip.show() - }, 100) + const insertedFunc = jasmine.createSpy() + tooltipEl.addEventListener('inserted.bs.tooltip', insertedFunc) setTimeout(() => { expect(insertedFunc).toHaveBeenCalledTimes(1) - done() - }, 200) - }, 0) + tooltip.hide() - tooltip.show() + setTimeout(() => { + tooltip.show() + }, 100) + + setTimeout(() => { + expect(insertedFunc).toHaveBeenCalledTimes(1) + resolve() + }, 200) + }, 0) + + tooltip.show() + }) }) - it('should show a tooltip with custom class provided in data attributes', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with custom class provided in data attributes', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tip = document.querySelector('.tooltip') - expect(tip).not.toBeNull() - expect(tip).toHaveClass('custom-class') - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tip = document.querySelector('.tooltip') + expect(tip).not.toBeNull() + expect(tip).toHaveClass('custom-class') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with custom class provided as a string in config', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with custom class provided as a string in config', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - customClass: 'custom-class custom-class-2' - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + customClass: 'custom-class custom-class-2' + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tip = document.querySelector('.tooltip') - expect(tip).not.toBeNull() - expect(tip).toHaveClass('custom-class') - expect(tip).toHaveClass('custom-class-2') - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tip = document.querySelector('.tooltip') + expect(tip).not.toBeNull() + expect(tip).toHaveClass('custom-class') + expect(tip).toHaveClass('custom-class-2') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should show a tooltip with custom class provided as a function in config', done => { - fixtureEl.innerHTML = '' + it('should show a tooltip with custom class provided as a function in config', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const spy = jasmine.createSpy('customClass').and.returnValue('custom-class') - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - customClass: spy - }) + const spy = jasmine.createSpy('customClass').and.returnValue('custom-class') + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + customClass: spy + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tip = document.querySelector('.tooltip') - expect(tip).not.toBeNull() - expect(spy).toHaveBeenCalled() - expect(tip).toHaveClass('custom-class') - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tip = document.querySelector('.tooltip') + expect(tip).not.toBeNull() + expect(spy).toHaveBeenCalled() + expect(tip).toHaveClass('custom-class') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should remove `title` attribute if exists', done => { - fixtureEl.innerHTML = '' + it('should remove `title` attribute if exists', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - expect(tooltipEl.getAttribute('title')).toBeNull() - done() + tooltipEl.addEventListener('shown.bs.tooltip', () => { + expect(tooltipEl.getAttribute('title')).toBeNull() + resolve() + }) + tooltip.show() }) - tooltip.show() }) }) describe('hide', () => { - it('should hide a tooltip', done => { - fixtureEl.innerHTML = '' + it('should hide a tooltip', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).toBeNull() - expect(tooltipEl.getAttribute('aria-describedby')).toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).toBeNull() + expect(tooltipEl.getAttribute('aria-describedby')).toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should hide a tooltip on mobile', done => { - fixtureEl.innerHTML = '' + it('should hide a tooltip on mobile', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - document.documentElement.ontouchstart = noop - spyOn(EventHandler, 'off') - tooltip.hide() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => { + document.documentElement.ontouchstart = noop + spyOn(EventHandler, 'off') + tooltip.hide() + }) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).toBeNull() - expect(EventHandler.off).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) - document.documentElement.ontouchstart = undefined - done() - }) + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).toBeNull() + expect(EventHandler.off).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop) + document.documentElement.ontouchstart = undefined + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should hide a tooltip without animation', done => { - fixtureEl.innerHTML = '' + it('should hide a tooltip without animation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - animation: false - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + animation: false + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - expect(document.querySelector('.tooltip')).toBeNull() - expect(tooltipEl.getAttribute('aria-describedby')).toBeNull() - done() - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + expect(document.querySelector('.tooltip')).toBeNull() + expect(tooltipEl.getAttribute('aria-describedby')).toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should not hide a tooltip if hide event is prevented', done => { - fixtureEl.innerHTML = '' + it('should not hide a tooltip if hide event is prevented', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const assertDone = () => { - setTimeout(() => { - expect(document.querySelector('.tooltip')).not.toBeNull() - done() - }, 20) - } + const assertDone = () => { + setTimeout(() => { + expect(document.querySelector('.tooltip')).not.toBeNull() + resolve() + }, 20) + } - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl, { - animation: false - }) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + animation: false + }) - tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) - tooltipEl.addEventListener('hide.bs.tooltip', event => { - event.preventDefault() - assertDone() - }) - tooltipEl.addEventListener('hidden.bs.tooltip', () => { - throw new Error('should not trigger hidden event') - }) + tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide()) + tooltipEl.addEventListener('hide.bs.tooltip', event => { + event.preventDefault() + assertDone() + }) + tooltipEl.addEventListener('hidden.bs.tooltip', () => { + throw new Error('should not trigger hidden event') + }) - tooltip.show() + tooltip.show() + }) }) it('should not throw error running hide if popper hasn\'t been shown', () => { @@ -979,22 +1051,24 @@ describe('Tooltip', () => { }) describe('update', () => { - it('should call popper update', done => { - fixtureEl.innerHTML = '' + it('should call popper update', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - spyOn(tooltip._popper, 'update') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + spyOn(tooltip._popper, 'update') - tooltip.update() + tooltip.update() - expect(tooltip._popper.update).toHaveBeenCalled() - done() - }) + expect(tooltip._popper.update).toHaveBeenCalled() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) it('should do nothing if the tooltip is not shown', () => { @@ -1272,55 +1346,61 @@ describe('Tooltip', () => { }) describe('aria-label', () => { - it('should add the aria-label attribute for referencing original title', done => { - fixtureEl.innerHTML = '' + it('should add the aria-label attribute for referencing original title', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tooltipShown = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') - expect(tooltipShown).not.toBeNull() - expect(tooltipEl.getAttribute('aria-label')).toEqual('Another tooltip') - done() - }) + expect(tooltipShown).not.toBeNull() + expect(tooltipEl.getAttribute('aria-label')).toEqual('Another tooltip') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should not add the aria-label attribute if the attribute already exists', done => { - fixtureEl.innerHTML = '' + it('should not add the aria-label attribute if the attribute already exists', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tooltipShown = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') - expect(tooltipShown).not.toBeNull() - expect(tooltipEl.getAttribute('aria-label')).toEqual('Different label') - done() - }) + expect(tooltipShown).not.toBeNull() + expect(tooltipEl.getAttribute('aria-label')).toEqual('Different label') + resolve() + }) - tooltip.show() + tooltip.show() + }) }) - it('should not add the aria-label attribute if the element has text content', done => { - fixtureEl.innerHTML = 'text content' + it('should not add the aria-label attribute if the element has text content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'text content' - const tooltipEl = fixtureEl.querySelector('a') - const tooltip = new Tooltip(tooltipEl) + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) - tooltipEl.addEventListener('shown.bs.tooltip', () => { - const tooltipShown = document.querySelector('.tooltip') + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') - expect(tooltipShown).not.toBeNull() - expect(tooltipEl.getAttribute('aria-label')).toBeNull() - done() - }) + expect(tooltipShown).not.toBeNull() + expect(tooltipEl.getAttribute('aria-label')).toBeNull() + resolve() + }) - tooltip.show() + tooltip.show() + }) }) }) diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index f9903c832..73384fc90 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -23,267 +23,297 @@ describe('Backdrop', () => { }) describe('show', () => { - 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) + it('should append the backdrop html once on show and include the "show" class if it is "shown"', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + isAnimated: false + }) + const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements()).toHaveSize(0) + expect(getElements()).toHaveSize(0) - instance.show() - instance.show(() => { - expect(getElements()).toHaveSize(1) - for (const el of getElements()) { - expect(el).toHaveClass(CLASS_NAME_SHOW) - } + instance.show() + instance.show(() => { + expect(getElements()).toHaveSize(1) + for (const el of getElements()) { + expect(el).toHaveClass(CLASS_NAME_SHOW) + } - done() + resolve() + }) }) }) - 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) + it('should not append the backdrop html if it is not "shown"', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: false, + isAnimated: true + }) + const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements()).toHaveSize(0) - instance.show(() => { expect(getElements()).toHaveSize(0) - done() + instance.show(() => { + expect(getElements()).toHaveSize(0) + resolve() + }) }) }) - 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) + it('should append the backdrop html once and include the "fade" class if it is "shown" and "animated"', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + isAnimated: true + }) + const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - expect(getElements()).toHaveSize(0) + expect(getElements()).toHaveSize(0) - instance.show(() => { - expect(getElements()).toHaveSize(1) - for (const el of getElements()) { - expect(el).toHaveClass(CLASS_NAME_FADE) - } + instance.show(() => { + expect(getElements()).toHaveSize(1) + for (const el of getElements()) { + expect(el).toHaveClass(CLASS_NAME_FADE) + } - done() + resolve() + }) }) }) }) describe('hide', () => { - it('should remove the backdrop html', done => { - const instance = new Backdrop({ - isVisible: true, - isAnimated: true - }) + it('should remove the backdrop html', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + isAnimated: true + }) - const getElements = () => document.body.querySelectorAll(CLASS_BACKDROP) + const getElements = () => document.body.querySelectorAll(CLASS_BACKDROP) - expect(getElements()).toHaveSize(0) - instance.show(() => { - expect(getElements()).toHaveSize(1) - instance.hide(() => { - expect(getElements()).toHaveSize(0) - done() + expect(getElements()).toHaveSize(0) + instance.show(() => { + expect(getElements()).toHaveSize(1) + instance.hide(() => { + expect(getElements()).toHaveSize(0) + resolve() + }) }) }) }) - it('should remove the "show" class', done => { - const instance = new Backdrop({ - isVisible: true, - isAnimated: true - }) - const elem = instance._getElement() + it('should remove the "show" class', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + isAnimated: true + }) + const elem = instance._getElement() - instance.show() - instance.hide(() => { - expect(elem).not.toHaveClass(CLASS_NAME_SHOW) - done() + instance.show() + instance.hide(() => { + expect(elem).not.toHaveClass(CLASS_NAME_SHOW) + resolve() + }) }) }) - it('should not try to remove Node on remove method if it is not "shown"', done => { - const instance = new Backdrop({ - isVisible: false, - isAnimated: true - }) - const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - const spy = spyOn(instance, 'dispose').and.callThrough() + it('should not try to remove Node on remove method if it is not "shown"', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: false, + isAnimated: true + }) + const getElements = () => document.querySelectorAll(CLASS_BACKDROP) + const spy = spyOn(instance, 'dispose').and.callThrough() - expect(getElements()).toHaveSize(0) - expect(instance._isAppended).toBeFalse() - instance.show(() => { - instance.hide(() => { - expect(getElements()).toHaveSize(0) - expect(spy).not.toHaveBeenCalled() - expect(instance._isAppended).toBeFalse() - done() + expect(getElements()).toHaveSize(0) + expect(instance._isAppended).toBeFalse() + instance.show(() => { + instance.hide(() => { + expect(getElements()).toHaveSize(0) + expect(spy).not.toHaveBeenCalled() + expect(instance._isAppended).toBeFalse() + resolve() + }) }) }) }) - it('should not error if the backdrop no longer has a parent', done => { - fixtureEl.innerHTML = '
' + it('should not error if the backdrop no longer has a parent', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const wrapper = fixtureEl.querySelector('#wrapper') - const instance = new Backdrop({ - isVisible: true, - isAnimated: true, - rootElement: wrapper - }) + const wrapper = fixtureEl.querySelector('#wrapper') + const instance = new Backdrop({ + isVisible: true, + isAnimated: true, + rootElement: wrapper + }) - const getElements = () => document.querySelectorAll(CLASS_BACKDROP) + const getElements = () => document.querySelectorAll(CLASS_BACKDROP) - instance.show(() => { - wrapper.remove() - instance.hide(() => { - expect(getElements()).toHaveSize(0) - done() + instance.show(() => { + wrapper.remove() + instance.hide(() => { + expect(getElements()).toHaveSize(0) + resolve() + }) }) }) }) }) describe('click callback', () => { - it('should execute callback on click', done => { - const spy = jasmine.createSpy('spy') + it('should execute callback on click', () => { + return new Promise(resolve => { + const spy = jasmine.createSpy('spy') - const instance = new Backdrop({ - isVisible: true, - isAnimated: false, - clickCallback: () => spy() - }) - const endTest = () => { - setTimeout(() => { - expect(spy).toHaveBeenCalled() - done() - }, 10) - } - - instance.show(() => { - const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) - document.querySelector(CLASS_BACKDROP).dispatchEvent(clickEvent) - endTest() - }) - }) - }) + const instance = new Backdrop({ + isVisible: true, + isAnimated: false, + clickCallback: () => spy() + }) + const endTest = () => { + setTimeout(() => { + expect(spy).toHaveBeenCalled() + resolve() + }, 10) + } - describe('animation callbacks', () => { - it('should show and hide backdrop after counting transition duration if it is animated', done => { - const instance = new Backdrop({ - isVisible: true, - isAnimated: true - }) - const spy2 = jasmine.createSpy('spy2') - - const execDone = () => { - setTimeout(() => { - expect(spy2).toHaveBeenCalledTimes(2) - done() - }, 10) - } - - instance.show(spy2) - instance.hide(() => { - spy2() - execDone() + instance.show(() => { + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) + document.querySelector(CLASS_BACKDROP).dispatchEvent(clickEvent) + endTest() + }) }) - expect(spy2).not.toHaveBeenCalled() }) - 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, - isAnimated: false + describe('animation callbacks', () => { + it('should show and hide backdrop after counting transition duration if it is animated', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + isAnimated: true + }) + const spy2 = jasmine.createSpy('spy2') + + const execDone = () => { + setTimeout(() => { + expect(spy2).toHaveBeenCalledTimes(2) + resolve() + }, 10) + } + + instance.show(spy2) + instance.hide(() => { + spy2() + execDone() + }) + expect(spy2).not.toHaveBeenCalled() + }) }) - const spy2 = jasmine.createSpy('spy2') - instance.show(spy2) - instance.hide(spy2) - - setTimeout(() => { - expect(spy2).toHaveBeenCalled() - expect(spy).not.toHaveBeenCalled() - done() - }, 10) - }) - - it('should not call delay callbacks if it is not "shown"', done => { - const instance = new Backdrop({ - isVisible: false, - isAnimated: true + it('should show and hide backdrop without a delay if it is not animated', () => { + return new Promise(resolve => { + const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) + const instance = new Backdrop({ + isVisible: true, + isAnimated: false + }) + const spy2 = jasmine.createSpy('spy2') + + instance.show(spy2) + instance.hide(spy2) + + setTimeout(() => { + expect(spy2).toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() + resolve() + }, 10) + }) }) - const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) - instance.show() - instance.hide(() => { - expect(spy).not.toHaveBeenCalled() - done() + it('should not call delay callbacks if it is not "shown"', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: false, + isAnimated: true + }) + const spy = jasmine.createSpy('spy', getTransitionDurationFromElement) + + instance.show() + instance.hide(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }) + }) }) }) - }) - describe('Config', () => { - describe('rootElement initialization', () => { - it('should be appended on "document.body" by default', done => { - const instance = new Backdrop({ - isVisible: true - }) - const getElement = () => document.querySelector(CLASS_BACKDROP) - instance.show(() => { - expect(getElement().parentElement).toEqual(document.body) - done() + describe('Config', () => { + describe('rootElement initialization', () => { + it('should be appended on "document.body" by default', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true + }) + const getElement = () => document.querySelector(CLASS_BACKDROP) + instance.show(() => { + expect(getElement().parentElement).toEqual(document.body) + resolve() + }) + }) }) - }) - it('should find the rootElement if passed as a string', done => { - const instance = new Backdrop({ - isVisible: true, - rootElement: 'body' - }) - const getElement = () => document.querySelector(CLASS_BACKDROP) - instance.show(() => { - expect(getElement().parentElement).toEqual(document.body) - done() + it('should find the rootElement if passed as a string', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + rootElement: 'body' + }) + const getElement = () => document.querySelector(CLASS_BACKDROP) + instance.show(() => { + expect(getElement().parentElement).toEqual(document.body) + resolve() + }) + }) }) - }) - - it('should be appended on any element given by the proper config', done => { - fixtureEl.innerHTML = '
' - const wrapper = fixtureEl.querySelector('#wrapper') - const instance = new Backdrop({ - isVisible: true, - rootElement: wrapper - }) - const getElement = () => document.querySelector(CLASS_BACKDROP) - instance.show(() => { - expect(getElement().parentElement).toEqual(wrapper) - done() + it('should be appended on any element given by the proper config', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const wrapper = fixtureEl.querySelector('#wrapper') + const instance = new Backdrop({ + isVisible: true, + rootElement: wrapper + }) + const getElement = () => document.querySelector(CLASS_BACKDROP) + instance.show(() => { + expect(getElement().parentElement).toEqual(wrapper) + resolve() + }) + }) }) }) - }) - describe('ClassName', () => { - it('should allow configuring className', done => { - const instance = new Backdrop({ - isVisible: true, - className: 'foo' - }) - const getElement = () => document.querySelector('.foo') - instance.show(() => { - expect(getElement()).toEqual(instance._getElement()) - instance.dispose() - done() + describe('ClassName', () => { + it('should allow configuring className', () => { + return new Promise(resolve => { + const instance = new Backdrop({ + isVisible: true, + className: 'foo' + }) + const getElement = () => document.querySelector('.foo') + instance.show(() => { + expect(getElement()).toEqual(instance._getElement()) + instance.dispose() + resolve() + }) + }) }) }) }) diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index 52a757397..55f6a23a7 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -1,7 +1,7 @@ import FocusTrap from '../../../src/util/focustrap' import EventHandler from '../../../src/dom/event-handler' import SelectorEngine from '../../../src/dom/selector-engine' -import { clearFixture, getFixture, createEvent } from '../../helpers/fixture' +import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' describe('FocusTrap', () => { let fixtureEl @@ -41,140 +41,148 @@ describe('FocusTrap', () => { expect(trapElement.focus).not.toHaveBeenCalled() }) - it('should force focus inside focus trap if it can', done => { - fixtureEl.innerHTML = [ - 'outside', - '
', - ' inside', - '
' - ].join('') + it('should force focus inside focus trap if it can', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + 'outside', + '
', + ' inside', + '
' + ].join('') - const trapElement = fixtureEl.querySelector('div') - const focustrap = new FocusTrap({ trapElement }) - focustrap.activate() + const trapElement = fixtureEl.querySelector('div') + const focustrap = new FocusTrap({ trapElement }) + focustrap.activate() - const inside = document.getElementById('inside') + const inside = document.getElementById('inside') - const focusInListener = () => { - expect(inside.focus).toHaveBeenCalled() - document.removeEventListener('focusin', focusInListener) - done() - } + const focusInListener = () => { + expect(inside.focus).toHaveBeenCalled() + document.removeEventListener('focusin', focusInListener) + resolve() + } - spyOn(inside, 'focus') - spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [inside]) + spyOn(inside, 'focus') + spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [inside]) - document.addEventListener('focusin', focusInListener) + document.addEventListener('focusin', focusInListener) - const focusInEvent = createEvent('focusin', { bubbles: true }) - Object.defineProperty(focusInEvent, 'target', { - value: document.getElementById('outside') - }) + const focusInEvent = createEvent('focusin', { bubbles: true }) + Object.defineProperty(focusInEvent, 'target', { + value: document.getElementById('outside') + }) - document.dispatchEvent(focusInEvent) + document.dispatchEvent(focusInEvent) + }) }) - it('should wrap focus around forward on tab', done => { - fixtureEl.innerHTML = [ - 'outside', - '
', - ' first', - ' inside', - ' last', - '
' - ].join('') - - const trapElement = fixtureEl.querySelector('div') - const focustrap = new FocusTrap({ trapElement }) - focustrap.activate() - - const first = document.getElementById('first') - const inside = document.getElementById('inside') - const last = document.getElementById('last') - const outside = document.getElementById('outside') - - spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last]) - spyOn(first, 'focus').and.callThrough() - - const focusInListener = () => { - expect(first.focus).toHaveBeenCalled() - first.removeEventListener('focusin', focusInListener) - done() - } - - first.addEventListener('focusin', focusInListener) - - const keydown = createEvent('keydown') - keydown.key = 'Tab' - - document.dispatchEvent(keydown) - outside.focus() + it('should wrap focus around forward on tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + 'outside', + '
', + ' first', + ' inside', + ' last', + '
' + ].join('') + + const trapElement = fixtureEl.querySelector('div') + const focustrap = new FocusTrap({ trapElement }) + focustrap.activate() + + const first = document.getElementById('first') + const inside = document.getElementById('inside') + const last = document.getElementById('last') + const outside = document.getElementById('outside') + + spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last]) + spyOn(first, 'focus').and.callThrough() + + const focusInListener = () => { + expect(first.focus).toHaveBeenCalled() + first.removeEventListener('focusin', focusInListener) + resolve() + } + + first.addEventListener('focusin', focusInListener) + + const keydown = createEvent('keydown') + keydown.key = 'Tab' + + document.dispatchEvent(keydown) + outside.focus() + }) }) - it('should wrap focus around backwards on shift-tab', done => { - fixtureEl.innerHTML = [ - 'outside', - '
', - ' first', - ' inside', - ' last', - '
' - ].join('') - - const trapElement = fixtureEl.querySelector('div') - const focustrap = new FocusTrap({ trapElement }) - focustrap.activate() - - const first = document.getElementById('first') - const inside = document.getElementById('inside') - const last = document.getElementById('last') - const outside = document.getElementById('outside') - - spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last]) - spyOn(last, 'focus').and.callThrough() - - const focusInListener = () => { - expect(last.focus).toHaveBeenCalled() - last.removeEventListener('focusin', focusInListener) - done() - } - - last.addEventListener('focusin', focusInListener) - - const keydown = createEvent('keydown') - keydown.key = 'Tab' - keydown.shiftKey = true - - document.dispatchEvent(keydown) - outside.focus() + it('should wrap focus around backwards on shift-tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + 'outside', + '
', + ' first', + ' inside', + ' last', + '
' + ].join('') + + const trapElement = fixtureEl.querySelector('div') + const focustrap = new FocusTrap({ trapElement }) + focustrap.activate() + + const first = document.getElementById('first') + const inside = document.getElementById('inside') + const last = document.getElementById('last') + const outside = document.getElementById('outside') + + spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last]) + spyOn(last, 'focus').and.callThrough() + + const focusInListener = () => { + expect(last.focus).toHaveBeenCalled() + last.removeEventListener('focusin', focusInListener) + resolve() + } + + last.addEventListener('focusin', focusInListener) + + const keydown = createEvent('keydown') + keydown.key = 'Tab' + keydown.shiftKey = true + + document.dispatchEvent(keydown) + outside.focus() + }) }) - it('should force focus on itself if there is no focusable content', done => { - fixtureEl.innerHTML = [ - 'outside', - '
' - ].join('') + it('should force focus on itself if there is no focusable content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + 'outside', + '
' + ].join('') - const trapElement = fixtureEl.querySelector('div') - const focustrap = new FocusTrap({ trapElement }) - focustrap.activate() + const trapElement = fixtureEl.querySelector('div') + const focustrap = new FocusTrap({ trapElement }) + focustrap.activate() - const focusInListener = () => { - expect(focustrap._config.trapElement.focus).toHaveBeenCalled() - document.removeEventListener('focusin', focusInListener) - done() - } + const focusInListener = () => { + expect(focustrap._config.trapElement.focus).toHaveBeenCalled() + document.removeEventListener('focusin', focusInListener) + resolve() + } - spyOn(focustrap._config.trapElement, 'focus') + spyOn(focustrap._config.trapElement, 'focus') - document.addEventListener('focusin', focusInListener) + document.addEventListener('focusin', focusInListener) - const focusInEvent = createEvent('focusin', { bubbles: true }) - Object.defineProperty(focusInEvent, 'target', { - value: document.getElementById('outside') - }) + const focusInEvent = createEvent('focusin', { bubbles: true }) + Object.defineProperty(focusInEvent, 'target', { + value: document.getElementById('outside') + }) - document.dispatchEvent(focusInEvent) + document.dispatchEvent(focusInEvent) + }) }) }) diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 9d8c5ed98..0d60ca989 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -1,5 +1,6 @@ import * as Util from '../../../src/util/index' import { clearFixture, getFixture } from '../../helpers/fixture' +import { noop } from '../../../src/util/index' describe('Util', () => { let fixtureEl @@ -154,18 +155,20 @@ describe('Util', () => { }) describe('triggerTransitionEnd', () => { - it('should trigger transitionend event', done => { - fixtureEl.innerHTML = '
' + it('should trigger transitionend event', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const el = fixtureEl.querySelector('div') - const spy = spyOn(el, 'dispatchEvent').and.callThrough() + const el = fixtureEl.querySelector('div') + const spy = spyOn(el, 'dispatchEvent').and.callThrough() - el.addEventListener('transitionend', () => { - expect(spy).toHaveBeenCalled() - done() - }) + el.addEventListener('transitionend', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - Util.triggerTransitionEnd(el) + Util.triggerTransitionEnd(el) + }) }) }) @@ -611,9 +614,9 @@ describe('Util', () => { }) it('should define a plugin on the jQuery instance', () => { - const pluginMock = function () {} + const pluginMock = Util.noop pluginMock.NAME = 'test' - pluginMock.jQueryInterface = function () {} + pluginMock.jQueryInterface = Util.noop Util.defineJQueryPlugin(pluginMock) expect(fakejQuery.fn.test).toEqual(pluginMock.jQueryInterface) @@ -658,96 +661,104 @@ describe('Util', () => { expect(callbackSpy).toHaveBeenCalled() }) - it('should execute a function after a computed CSS transition duration and there was no transitionend event dispatched', done => { - const el = document.createElement('div') - const callbackSpy = jasmine.createSpy('callback spy') + it('should execute a function after a computed CSS transition duration and there was no transitionend event dispatched', () => { + return new Promise(resolve => { + const el = document.createElement('div') + const callbackSpy = jasmine.createSpy('callback spy') - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.05s', - transitionDelay: '0s' - }) + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.05s', + transitionDelay: '0s' + }) - Util.executeAfterTransition(callbackSpy, el) + Util.executeAfterTransition(callbackSpy, el) - setTimeout(() => { - expect(callbackSpy).toHaveBeenCalled() - done() - }, 70) + setTimeout(() => { + expect(callbackSpy).toHaveBeenCalled() + resolve() + }, 70) + }) }) - it('should not execute a function a second time after a computed CSS transition duration and if a transitionend event has already been dispatched', done => { - const el = document.createElement('div') - const callbackSpy = jasmine.createSpy('callback spy') + it('should not execute a function a second time after a computed CSS transition duration and if a transitionend event has already been dispatched', () => { + return new Promise(resolve => { + const el = document.createElement('div') + const callbackSpy = jasmine.createSpy('callback spy') - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.05s', - transitionDelay: '0s' - }) + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.05s', + transitionDelay: '0s' + }) - Util.executeAfterTransition(callbackSpy, el) + Util.executeAfterTransition(callbackSpy, el) - setTimeout(() => { - el.dispatchEvent(new TransitionEvent('transitionend')) - }, 50) + setTimeout(() => { + el.dispatchEvent(new TransitionEvent('transitionend')) + }, 50) - setTimeout(() => { - expect(callbackSpy).toHaveBeenCalledTimes(1) - done() - }, 70) + setTimeout(() => { + expect(callbackSpy).toHaveBeenCalledTimes(1) + resolve() + }, 70) + }) }) - it('should not trigger a transitionend event if another transitionend event had already happened', done => { - const el = document.createElement('div') + it('should not trigger a transitionend event if another transitionend event had already happened', () => { + return new Promise(resolve => { + const el = document.createElement('div') - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.05s', - transitionDelay: '0s' - }) + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.05s', + transitionDelay: '0s' + }) - Util.executeAfterTransition(() => {}, el) + Util.executeAfterTransition(noop, el) - // simulate a event dispatched by the browser - el.dispatchEvent(new TransitionEvent('transitionend')) + // simulate a event dispatched by the browser + el.dispatchEvent(new TransitionEvent('transitionend')) - const dispatchSpy = spyOn(el, 'dispatchEvent').and.callThrough() + const dispatchSpy = spyOn(el, 'dispatchEvent').and.callThrough() - setTimeout(() => { - // setTimeout should not have triggered another transitionend event. - expect(dispatchSpy).not.toHaveBeenCalled() - done() - }, 70) + setTimeout(() => { + // setTimeout should not have triggered another transitionend event. + expect(dispatchSpy).not.toHaveBeenCalled() + resolve() + }, 70) + }) }) - it('should ignore transitionend events from nested elements', done => { - fixtureEl.innerHTML = [ - '
', - '
', - '
' - ].join('') + it('should ignore transitionend events from nested elements', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + '
' + ].join('') - const outer = fixtureEl.querySelector('.outer') - const nested = fixtureEl.querySelector('.nested') - const callbackSpy = jasmine.createSpy('callback spy') + const outer = fixtureEl.querySelector('.outer') + const nested = fixtureEl.querySelector('.nested') + const callbackSpy = jasmine.createSpy('callback spy') - spyOn(window, 'getComputedStyle').and.returnValue({ - transitionDuration: '0.05s', - transitionDelay: '0s' - }) + spyOn(window, 'getComputedStyle').and.returnValue({ + transitionDuration: '0.05s', + transitionDelay: '0s' + }) - Util.executeAfterTransition(callbackSpy, outer) + Util.executeAfterTransition(callbackSpy, outer) - nested.dispatchEvent(new TransitionEvent('transitionend', { - bubbles: true - })) + nested.dispatchEvent(new TransitionEvent('transitionend', { + bubbles: true + })) - setTimeout(() => { - expect(callbackSpy).not.toHaveBeenCalled() - }, 20) + setTimeout(() => { + expect(callbackSpy).not.toHaveBeenCalled() + }, 20) - setTimeout(() => { - expect(callbackSpy).toHaveBeenCalled() - done() - }, 70) + setTimeout(() => { + expect(callbackSpy).toHaveBeenCalled() + resolve() + }, 70) + }) }) }) diff --git a/js/tests/unit/util/scrollbar.spec.js b/js/tests/unit/util/scrollbar.spec.js index fc3a6f4e8..6fcf5718b 100644 --- a/js/tests/unit/util/scrollbar.spec.js +++ b/js/tests/unit/util/scrollbar.spec.js @@ -101,7 +101,7 @@ describe('ScrollBar', () => { }) describe('hide - reset', () => { - it('should adjust the inline padding of fixed elements which are full-width', done => { + it('should adjust the inline padding of fixed elements which are full-width', () => { fixtureEl.innerHTML = [ '
', '
', @@ -134,10 +134,9 @@ describe('ScrollBar', () => { expect(getPaddingAttr(fixedEl2)).toBeNull() expect(currentPadding).toEqual(originalPadding) expect(currentPadding2).toEqual(originalPadding2) - done() }) - it('should remove padding & margin if not existed before adjustment', done => { + it('should remove padding & margin if not existed before adjustment', () => { fixtureEl.innerHTML = [ '
', '
', @@ -155,10 +154,9 @@ describe('ScrollBar', () => { expect(fixedEl.getAttribute('style').includes('padding-right')).toBeFalse() expect(stickyEl.getAttribute('style').includes('margin-right')).toBeFalse() - done() }) - it('should adjust the inline margin and padding of sticky elements', done => { + it('should adjust the inline margin and padding of sticky elements', () => { fixtureEl.innerHTML = [ '
', '
', @@ -184,7 +182,6 @@ describe('ScrollBar', () => { 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', () => { diff --git a/js/tests/unit/util/swipe.spec.js b/js/tests/unit/util/swipe.spec.js index 93131b8fd..054aab695 100644 --- a/js/tests/unit/util/swipe.spec.js +++ b/js/tests/unit/util/swipe.spec.js @@ -78,74 +78,80 @@ describe('Swipe', () => { }) describe('Config', () => { - it('Test leftCallback', done => { - const spyRight = jasmine.createSpy('spy') - clearPointerEvents() - defineDocumentElementOntouchstart() - // eslint-disable-next-line no-new - new Swipe(swipeEl, { - leftCallback: () => { - expect(spyRight).not.toHaveBeenCalled() - restorePointerEvents() - done() - }, - rightCallback: spyRight - }) - - mockSwipeGesture(swipeEl, { - pos: [300, 10], - deltaX: -300 + it('Test leftCallback', () => { + return new Promise(resolve => { + const spyRight = jasmine.createSpy('spy') + clearPointerEvents() + defineDocumentElementOntouchstart() + // eslint-disable-next-line no-new + new Swipe(swipeEl, { + leftCallback: () => { + expect(spyRight).not.toHaveBeenCalled() + restorePointerEvents() + resolve() + }, + rightCallback: spyRight + }) + + mockSwipeGesture(swipeEl, { + pos: [300, 10], + deltaX: -300 + }) }) }) - it('Test rightCallback', done => { - const spyLeft = jasmine.createSpy('spy') - clearPointerEvents() - defineDocumentElementOntouchstart() - // eslint-disable-next-line no-new - new Swipe(swipeEl, { - rightCallback: () => { - expect(spyLeft).not.toHaveBeenCalled() - restorePointerEvents() - done() - }, - leftCallback: spyLeft - }) - - mockSwipeGesture(swipeEl, { - pos: [10, 10], - deltaX: 300 + it('Test rightCallback', () => { + return new Promise(resolve => { + const spyLeft = jasmine.createSpy('spy') + clearPointerEvents() + defineDocumentElementOntouchstart() + // eslint-disable-next-line no-new + new Swipe(swipeEl, { + rightCallback: () => { + expect(spyLeft).not.toHaveBeenCalled() + restorePointerEvents() + resolve() + }, + leftCallback: spyLeft + }) + + mockSwipeGesture(swipeEl, { + pos: [10, 10], + deltaX: 300 + }) }) }) - it('Test endCallback', done => { - clearPointerEvents() - defineDocumentElementOntouchstart() - let isFirstTime = true - - const callback = () => { - if (isFirstTime) { - isFirstTime = false - return - } + it('Test endCallback', () => { + return new Promise(resolve => { + clearPointerEvents() + defineDocumentElementOntouchstart() + let isFirstTime = true - expect().nothing() - restorePointerEvents() - done() - } + const callback = () => { + if (isFirstTime) { + isFirstTime = false + return + } - // eslint-disable-next-line no-new - new Swipe(swipeEl, { - endCallback: callback - }) - mockSwipeGesture(swipeEl, { - pos: [10, 10], - deltaX: 300 - }) + expect().nothing() + restorePointerEvents() + resolve() + } - mockSwipeGesture(swipeEl, { - pos: [300, 10], - deltaX: -300 + // eslint-disable-next-line no-new + new Swipe(swipeEl, { + endCallback: callback + }) + mockSwipeGesture(swipeEl, { + pos: [10, 10], + deltaX: 300 + }) + + mockSwipeGesture(swipeEl, { + pos: [300, 10], + deltaX: -300 + }) }) }) }) @@ -170,53 +176,57 @@ describe('Swipe', () => { expect(swipe._handleSwipe).not.toHaveBeenCalled() }) - it('should allow swipeRight and call "rightCallback" with pointer events', done => { - if (!supportPointerEvent) { - expect().nothing() - done() - return - } - - const style = '#fixture .pointer-event { touch-action: none !important; }' - fixtureEl.innerHTML += style - - defineDocumentElementOntouchstart() - // eslint-disable-next-line no-new - new Swipe(swipeEl, { - rightCallback: () => { - deleteDocumentElementOntouchstart() + it('should allow swipeRight and call "rightCallback" with pointer events', () => { + return new Promise(resolve => { + if (!supportPointerEvent) { expect().nothing() - done() + resolve() + return } - }) - mockSwipeGesture(swipeEl, { deltaX: 300 }, 'pointer') - }) + const style = '#fixture .pointer-event { touch-action: none !important; }' + fixtureEl.innerHTML += style - it('should allow swipeLeft and call "leftCallback" with pointer events', done => { - if (!supportPointerEvent) { - expect().nothing() - done() - return - } + defineDocumentElementOntouchstart() + // eslint-disable-next-line no-new + new Swipe(swipeEl, { + rightCallback: () => { + deleteDocumentElementOntouchstart() + expect().nothing() + resolve() + } + }) - const style = '#fixture .pointer-event { touch-action: none !important; }' - fixtureEl.innerHTML += style + mockSwipeGesture(swipeEl, { deltaX: 300 }, 'pointer') + }) + }) - defineDocumentElementOntouchstart() - // eslint-disable-next-line no-new - new Swipe(swipeEl, { - leftCallback: () => { + it('should allow swipeLeft and call "leftCallback" with pointer events', () => { + return new Promise(resolve => { + if (!supportPointerEvent) { expect().nothing() - deleteDocumentElementOntouchstart() - done() + resolve() + return } - }) - mockSwipeGesture(swipeEl, { - pos: [300, 10], - deltaX: -300 - }, 'pointer') + const style = '#fixture .pointer-event { touch-action: none !important; }' + fixtureEl.innerHTML += style + + defineDocumentElementOntouchstart() + // eslint-disable-next-line no-new + new Swipe(swipeEl, { + leftCallback: () => { + expect().nothing() + deleteDocumentElementOntouchstart() + resolve() + } + }) + + mockSwipeGesture(swipeEl, { + pos: [300, 10], + deltaX: -300 + }, 'pointer') + }) }) }) -- cgit v1.2.3 From 28c9002573e6cb6982697e50e1d1ebfe2ae0fc4c Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 15 Dec 2021 19:54:02 +0200 Subject: Modal: handle click event from backdrop callback --- js/tests/unit/modal.spec.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index bf796411b..5d3f5cd9d 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -642,8 +642,11 @@ describe('Modal', () => { modalEl.addEventListener('shown.bs.modal', () => { const spy = spyOn(modal, '_queueCallback').and.callThrough() - modalEl.click() - modalEl.click() + const mouseOverEvent = createEvent('mousedown') + const backdrop = document.querySelector('.modal-backdrop') + + backdrop.dispatchEvent(mouseOverEvent) + backdrop.dispatchEvent(mouseOverEvent) setTimeout(() => { expect(spy).toHaveBeenCalledTimes(1) @@ -710,9 +713,9 @@ describe('Modal', () => { const modalEl = fixtureEl.querySelector('.modal') const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() + const mouseOverEvent = createEvent('mousedown') + document.querySelector('.modal-backdrop').dispatchEvent(mouseOverEvent) }) modalEl.addEventListener('hidden.bs.modal', () => { -- cgit v1.2.3 From dcbe7b6f31d5383ea9e0203fd68c0a5e99fa97b7 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 15 Dec 2021 19:55:05 +0200 Subject: Modal.js: remove unnecessary checks from test --- js/tests/unit/modal.spec.js | 4 ---- 1 file changed, 4 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index 5d3f5cd9d..0471a1b9f 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -719,10 +719,6 @@ describe('Modal', () => { }) modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') expect(document.querySelector('.modal-backdrop')).toBeNull() resolve() }) -- cgit v1.2.3 From 89f88762c52f4c7dfca0fe1de6d41386bb673289 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Sun, 30 Jan 2022 16:12:24 +0200 Subject: Fix visual tests (#35585) * Fix visual tests They broke in #34509 * load bundle.js in visual tests Co-authored-by: GeoSot --- js/tests/visual/alert.html | 6 +----- js/tests/visual/button.html | 6 +----- js/tests/visual/carousel.html | 7 +------ js/tests/visual/collapse.html | 7 +------ js/tests/visual/dropdown.html | 9 +-------- js/tests/visual/modal.html | 17 ++++------------- js/tests/visual/popover.html | 11 ++--------- js/tests/visual/scrollspy.html | 9 +-------- js/tests/visual/tab.html | 7 +------ js/tests/visual/toast.html | 12 ++++-------- js/tests/visual/tooltip.html | 18 ++++++------------ 11 files changed, 23 insertions(+), 86 deletions(-) (limited to 'js/tests') diff --git a/js/tests/visual/alert.html b/js/tests/visual/alert.html index c5e2efafa..2433b9e8e 100644 --- a/js/tests/visual/alert.html +++ b/js/tests/visual/alert.html @@ -43,10 +43,6 @@
- - - - - + diff --git a/js/tests/visual/button.html b/js/tests/visual/button.html index 0bd2f1097..0c54934f0 100644 --- a/js/tests/visual/button.html +++ b/js/tests/visual/button.html @@ -44,10 +44,6 @@
- - - - - + diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index 561b6ce5a..b26895fd0 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -45,12 +45,7 @@ - - - - - - + - - - - - + diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html index f1dd705f3..bc4d79542 100644 --- a/js/tests/visual/dropdown.html +++ b/js/tests/visual/dropdown.html @@ -200,13 +200,6 @@ - - - - - - - - + diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index 719e9cc10..f11edea95 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -199,16 +199,7 @@ - - - - - - - - - - + - - - - - - - + diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html index 1e3215b6f..7999b0ee7 100644 --- a/js/tests/visual/scrollspy.html +++ b/js/tests/visual/scrollspy.html @@ -86,13 +86,6 @@

Ad leggings keytar, brunch id art party dolor labore.

- - - - - - - - + diff --git a/js/tests/visual/tab.html b/js/tests/visual/tab.html index 0ce8be03c..4cbc86ccc 100644 --- a/js/tests/visual/tab.html +++ b/js/tests/visual/tab.html @@ -218,11 +218,6 @@ - - - - - - + diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index f9e1741cf..9e6c897df 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -50,22 +50,18 @@ - - - - - + - - - - - - + + + + -- cgit v1.2.3 From 6f65df4faea2694840572626f8a02f4399bd0dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Broutier?= Date: Thu, 15 Sep 2022 12:30:51 +0200 Subject: Fix modal event listeners (#37128) * Fix modal event listeners (#37126) Co-authored-by: GeoSot --- js/tests/unit/modal.spec.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index e774fc4e8..fdee29e95 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -734,6 +734,36 @@ describe('Modal', () => { }) }) + it('should not close modal when clicking on an element removed from modal content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const buttonEl = modalEl.querySelector('.btn') + const modal = new Modal(modalEl) + + const spy = spyOn(modal, 'hide') + buttonEl.addEventListener('click', () => { + buttonEl.remove() + }) + + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.dispatchEvent(createEvent('mousedown')) + buttonEl.click() + expect(spy).not.toHaveBeenCalled() + resolve() + }) + + modal.show() + }) + }) + it('should do nothing is the modal is not shown', () => { fixtureEl.innerHTML = '' -- cgit v1.2.3 From d0117a17d807df05dfd6f6ce72a0d63f081ca529 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Tue, 20 Sep 2022 08:09:14 +0300 Subject: Update devDependencies (#37177) --- js/tests/karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js/tests') diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index a1b96d041..6636ff15d 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -2,7 +2,7 @@ 'use strict' -const path = require('path') +const path = require('node:path') const ip = require('ip') const { babel } = require('@rollup/plugin-babel') const istanbul = require('rollup-plugin-istanbul') -- cgit v1.2.3 From 1510c25e9be4d8f7f2ba23622bfdfd9afebb6598 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Tue, 20 Sep 2022 17:20:47 +0300 Subject: Drop tabs auto-focus (#37146) * fix: drop tabs auto-focus --- js/tests/unit/tab.spec.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index f1c1d695c..15d581173 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -36,9 +36,7 @@ describe('Tab', () => { expect(tabBySelector._element).toEqual(tabEl) expect(tabByElement._element).toEqual(tabEl) }) - }) - describe('constructor', () => { it('Do not Throw exception if not parent', () => { fixtureEl.innerHTML = [ fixtureEl.innerHTML = '
' @@ -383,6 +381,35 @@ describe('Tab', () => { btnCloseEl.click() }) }) + + it('should not focus on opened tab', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
    ', + '
  • ', + '
  • ', + '
' + ].join('') + + const firstTab = fixtureEl.querySelector('#home') + firstTab.focus() + + const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(document.activeElement).toBe(firstTab) + expect(document.activeElement).not.toBe(profileTriggerEl) + resolve() + }) + + tab.show() + }) + }) }) describe('dispose', () => { -- cgit v1.2.3 From 27f20257ebd092b2e5d11a62de0cd5e9cf5a9949 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Thu, 22 Sep 2022 01:48:23 +0300 Subject: Use es6 on visual tests (#36915) --- js/tests/visual/carousel.html | 10 +++++----- js/tests/visual/modal.html | 43 ++++++++++++++++++------------------------- js/tests/visual/popover.html | 5 +---- js/tests/visual/toast.html | 23 ++++++----------------- 4 files changed, 30 insertions(+), 51 deletions(-) (limited to 'js/tests') diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index b26895fd0..153c86604 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -47,17 +47,17 @@ diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index ab0986c58..5056c6e7c 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -201,8 +201,8 @@ diff --git a/js/tests/visual/popover.html b/js/tests/visual/popover.html index eed69c341..96b746b72 100644 --- a/js/tests/visual/popover.html +++ b/js/tests/visual/popover.html @@ -33,10 +33,7 @@ diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index 9e6c897df..cacc7da70 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -52,26 +52,15 @@ -- cgit v1.2.3 From 2b46842af908fe54bd7f7982ed07c7cd07bc934a Mon Sep 17 00:00:00 2001 From: Carson Sievert Date: Wed, 21 Sep 2022 18:29:58 -0500 Subject: Fix active class toggling of tabs within dropdown (#37151) * Close #36947: fix active class toggling tabs within dropdown --- js/tests/unit/tab.spec.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index 15d581173..b00014eed 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -840,10 +840,11 @@ describe('Tab', () => { '' ].join('') - const firstDropItem = fixtureEl.querySelector('.dropdown-item') + const dropItems = fixtureEl.querySelectorAll('.dropdown-item') - firstDropItem.click() - expect(firstDropItem).toHaveClass('active') + dropItems[1].click() + expect(dropItems[0]).not.toHaveClass('active') + expect(dropItems[1]).toHaveClass('active') expect(fixtureEl.querySelector('.nav-link')).not.toHaveClass('active') }) -- cgit v1.2.3 From 24f6e2764a557afdf0cabfc28067fe1078e0a0ee Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 23 Sep 2022 23:18:57 +0300 Subject: Tests: add testcase to Tabs, keyboard handler (#37189) --- js/tests/unit/tab.spec.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'js/tests') diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index b00014eed..5ffc73383 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -513,15 +513,19 @@ describe('Tab', () => { '' ].join('') - const tabEl = fixtureEl.querySelector('#tab1') + const tabEl1 = fixtureEl.querySelector('#tab1') const tabEl2 = fixtureEl.querySelector('#tab2') - const tab = new Tab(tabEl) + const tabEl3 = fixtureEl.querySelector('#tab3') + const tab1 = new Tab(tabEl1) const tab2 = new Tab(tabEl2) - const spyShow1 = spyOn(tab, 'show').and.callThrough() + const tab3 = new Tab(tabEl3) + const spyShow1 = spyOn(tab1, 'show').and.callThrough() const spyShow2 = spyOn(tab2, 'show').and.callThrough() + const spyShow3 = spyOn(tab3, 'show').and.callThrough() const spyStop = spyOn(Event.prototype, 'stopPropagation').and.callThrough() const spyPrevent = spyOn(Event.prototype, 'preventDefault').and.callThrough() @@ -529,17 +533,20 @@ describe('Tab', () => { let keydown = createEvent('keydown') keydown.key = 'ArrowRight' - tabEl.dispatchEvent(keydown) + tabEl1.dispatchEvent(keydown) expect(spyShow2).toHaveBeenCalled() keydown = createEvent('keydown') keydown.key = 'ArrowDown' tabEl2.dispatchEvent(keydown) + expect(spyShow3).toHaveBeenCalled() + + tabEl3.dispatchEvent(keydown) expect(spyShow1).toHaveBeenCalled() - expect(spyStop).toHaveBeenCalledTimes(2) - expect(spyPrevent).toHaveBeenCalledTimes(2) + expect(spyStop).toHaveBeenCalledTimes(3) + expect(spyPrevent).toHaveBeenCalledTimes(3) }) it('if keydown event is left arrow, handle it', () => { -- cgit v1.2.3 From 597c4023141dc48868889b85676b2d7269411d23 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Tue, 27 Sep 2022 10:39:11 +0300 Subject: Dropdown: fix case with invalid markup (#37190) This fixes a backward incompatible change in v5.2.1 where `.drodown-toggle` isn't present in the markup. --- js/tests/unit/dropdown.spec.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'js/tests') diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index ea7ddace3..2bbd7c00a 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -57,6 +57,28 @@ describe('Dropdown', () => { expect(dropdownByElement._element).toEqual(btnDropdown) }) + it('should work on invalid markup', () => { + return new Promise(resolve => { + // TODO: REMOVE in v6 + fixtureEl.innerHTML = [ + '' + ].join('') + + const dropdownElem = fixtureEl.querySelector('.dropdown-menu') + const dropdown = new Dropdown(dropdownElem) + + dropdownElem.addEventListener('shown.bs.dropdown', () => { + resolve() + }) + + dropdown.show() + }) + }) + it('should create offset modifier correctly when offset option is a function', () => { return new Promise(resolve => { fixtureEl.innerHTML = [ -- cgit v1.2.3 From abb1cf529fb8dfb8e66e44506eb32f8a9e0e0ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20D=C3=A9ramond?= Date: Tue, 27 Sep 2022 21:53:59 +0200 Subject: Add eslint-plugin-html to lint JS in HTML files (#37186) --- js/tests/visual/.eslintrc.json | 19 +++++++++++++++++++ js/tests/visual/modal.html | 9 ++++----- js/tests/visual/popover.html | 2 ++ js/tests/visual/toast.html | 6 ++++-- js/tests/visual/tooltip.html | 17 +++++++++++------ 5 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 js/tests/visual/.eslintrc.json (limited to 'js/tests') diff --git a/js/tests/visual/.eslintrc.json b/js/tests/visual/.eslintrc.json new file mode 100644 index 000000000..8a3322572 --- /dev/null +++ b/js/tests/visual/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "plugins": [ + "html" + ], + "extends": "../../../.eslintrc.json", + "parserOptions": { + "sourceType": "module" + }, + "settings": { + "html/html-extensions": [ + ".html" + ] + }, + "rules": { + "no-console": "off", + "no-new": "off", + "unicorn/no-array-for-each": "off" + } +} diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index 5056c6e7c..fd93c068a 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -201,6 +201,8 @@ diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index cacc7da70..f86926d01 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -52,15 +52,17 @@ diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html index 9a65640b4..1a3b9f21d 100644 --- a/js/tests/visual/tooltip.html +++ b/js/tests/visual/tooltip.html @@ -85,6 +85,8 @@ -- cgit v1.2.3 From 0a5f6e078c9cb9ecca9ab90b3984c5f792a11bae Mon Sep 17 00:00:00 2001 From: "Patrick H. Lauke" Date: Sun, 2 Oct 2022 11:02:36 +0100 Subject: Use `

` for all `modal-title` examples/uses (#37210) * Use `fs-` font sizing classes where needed * Also add info callout about heading hierarchy in modals --- js/tests/visual/modal.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'js/tests') diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index fd93c068a..b738d9e81 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -38,7 +38,7 @@