Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoSot <geo.sotis@gmail.com>2022-01-30 15:30:04 +0300
committerGitHub <noreply@github.com>2022-01-30 15:30:04 +0300
commitaa650f0f1e30279f0868433a4afab9c3efa93b2c (patch)
tree88cf537f2e7b6613bc2e53d4e38ca93798786d07
parentd09281705988690b63a5364548447c603cb557fd (diff)
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<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> for more information.
-rw-r--r--js/tests/README.md28
-rw-r--r--js/tests/unit/alert.spec.js84
-rw-r--r--js/tests/unit/carousel.spec.js1208
-rw-r--r--js/tests/unit/collapse.spec.js1164
-rw-r--r--js/tests/unit/dom/event-handler.spec.js541
-rw-r--r--js/tests/unit/dom/manipulator.spec.js60
-rw-r--r--js/tests/unit/dropdown.spec.js2856
-rw-r--r--js/tests/unit/jquery.spec.js32
-rw-r--r--js/tests/unit/modal.spec.js1362
-rw-r--r--js/tests/unit/offcanvas.spec.js586
-rw-r--r--js/tests/unit/popover.spec.js270
-rw-r--r--js/tests/unit/scrollspy.spec.js796
-rw-r--r--js/tests/unit/tab.spec.js914
-rw-r--r--js/tests/unit/toast.spec.js678
-rw-r--r--js/tests/unit/tooltip.spec.js1222
-rw-r--r--js/tests/unit/util/backdrop.spec.js428
-rw-r--r--js/tests/unit/util/focustrap.spec.js240
-rw-r--r--js/tests/unit/util/index.spec.js165
-rw-r--r--js/tests/unit/util/scrollbar.spec.js9
-rw-r--r--js/tests/unit/util/swipe.spec.js204
20 files changed, 6715 insertions, 6132 deletions
diff --git a/js/tests/README.md b/js/tests/README.md
index ca99c0ede0..79d05d444f 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 = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
+it('should show a tooltip without the animation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
- 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 210ae9a25e..e2fe49246a 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 = '<div class="alert"></div>'
+ it('should close an alert', () => {
+ return new Promise(resolve => {
+ const spy = jasmine.createSpy('spy', getTransitionDurationFromElement)
+ fixtureEl.innerHTML = '<div class="alert"></div>'
- 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 = '<div class="alert fade"></div>'
+ it('should close alert with fade class', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="alert fade"></div>'
- 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 = '<div class="alert"></div>'
+ it('should not remove alert if close event is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="alert"></div>'
- 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 7b58b9de9e..1c91cebec4 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 = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should go to next item if right arrow key is pressed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div id="item2" class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="item1" class="carousel-item">item 1</div>',
- ' <div class="carousel-item active">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should go to previous item if left arrow key is pressed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div id="item1" class="carousel-item">item 1</div>',
+ ' <div class="carousel-item active">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].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 <input>s and <textarea>s', () => {
@@ -222,70 +228,74 @@ describe('Carousel', () => {
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
})
- it('should wrap around from end to start when wrap option is true', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="one" class="carousel-item active"></div>',
- ' <div id="two" class="carousel-item"></div>',
- ' <div id="three" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, { wrap: true })
- const getActiveId = () => carouselEl.querySelector('.carousel-item.active').getAttribute('id')
-
- carouselEl.addEventListener('slid.bs.carousel', event => {
- const activeId = getActiveId()
-
- if (activeId === 'two') {
- carousel.next()
- return
- }
-
- if (activeId === 'three') {
- carousel.next()
- return
- }
-
- if (activeId === 'one') {
- // carousel wrapped around and slid from 3rd to 1st slide
- expect(activeId).toEqual('one')
- expect(event.from + 1).toEqual(3)
- done()
- }
+ it('should wrap around from end to start when wrap option is true', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div id="one" class="carousel-item active"></div>',
+ ' <div id="two" class="carousel-item"></div>',
+ ' <div id="three" class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, { wrap: true })
+ const getActiveId = () => carouselEl.querySelector('.carousel-item.active').getAttribute('id')
+
+ carouselEl.addEventListener('slid.bs.carousel', event => {
+ const activeId = getActiveId()
+
+ if (activeId === 'two') {
+ carousel.next()
+ return
+ }
+
+ if (activeId === 'three') {
+ carousel.next()
+ return
+ }
+
+ if (activeId === 'one') {
+ // carousel wrapped around and slid from 3rd to 1st slide
+ expect(activeId).toEqual('one')
+ expect(event.from + 1).toEqual(3)
+ resolve()
+ }
+ })
+
+ carousel.next()
})
-
- carousel.next()
})
- it('should stay at the start when the prev method is called and wrap is false', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="one" class="carousel-item active"></div>',
- ' <div id="two" class="carousel-item"></div>',
- ' <div id="three" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should stay at the start when the prev method is called and wrap is false', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div id="one" class="carousel-item active"></div>',
+ ' <div id="two" class="carousel-item"></div>',
+ ' <div id="three" class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const firstElement = fixtureEl.querySelector('#one')
- const carousel = new Carousel(carouselEl, { wrap: false })
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const firstElement = fixtureEl.querySelector('#one')
+ const carousel = new Carousel(carouselEl, { wrap: false })
- carouselEl.addEventListener('slid.bs.carousel', () => {
- throw new Error('carousel slid when it should not have slid')
- })
+ carouselEl.addEventListener('slid.bs.carousel', () => {
+ throw new Error('carousel slid when it should not have slid')
+ })
- carousel.prev()
+ carousel.prev()
- setTimeout(() => {
- expect(firstElement).toHaveClass('active')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(firstElement).toHaveClass('active')
+ resolve()
+ }, 10)
+ })
})
it('should not add touch event listeners if touch = false', () => {
@@ -335,274 +345,290 @@ describe('Carousel', () => {
expect(carousel._addTouchEventListeners).toHaveBeenCalled()
})
- it('should allow swiperight and call _slide (prev) with pointer events', done => {
- if (!supportPointerEvent) {
- expect().nothing()
- done()
- return
- }
-
- document.documentElement.ontouchstart = noop
- document.head.append(stylesCarousel)
- Simulator.setType('pointer')
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-bs-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, '_slide').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', event => {
- expect(item).toHaveClass('active')
- expect(carousel._slide).toHaveBeenCalledWith('right')
- expect(event.direction).toEqual('right')
- stylesCarousel.remove()
- delete document.documentElement.ontouchstart
- done()
- })
+ it('should allow swiperight and call _slide (prev) with pointer events', () => {
+ return new Promise(resolve => {
+ if (!supportPointerEvent) {
+ expect().nothing()
+ resolve()
+ return
+ }
- Simulator.gestures.swipe(carouselEl, {
- deltaX: 300,
- deltaY: 0
+ document.documentElement.ontouchstart = noop
+ document.head.append(stylesCarousel)
+ Simulator.setType('pointer')
+
+ fixtureEl.innerHTML = [
+ '<div class="carousel" data-bs-interval="false">',
+ ' <div class="carousel-inner">',
+ ' <div id="item" class="carousel-item">',
+ ' <img alt="">',
+ ' </div>',
+ ' <div class="carousel-item active">',
+ ' <img alt="">',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const item = fixtureEl.querySelector('#item')
+ const carousel = new Carousel(carouselEl)
+
+ spyOn(carousel, '_slide').and.callThrough()
+
+ carouselEl.addEventListener('slid.bs.carousel', event => {
+ expect(item).toHaveClass('active')
+ expect(carousel._slide).toHaveBeenCalledWith('right')
+ expect(event.direction).toEqual('right')
+ stylesCarousel.remove()
+ delete document.documentElement.ontouchstart
+ resolve()
+ })
+
+ Simulator.gestures.swipe(carouselEl, {
+ deltaX: 300,
+ deltaY: 0
+ })
})
})
- it('should allow swipeleft and call next with pointer events', done => {
- if (!supportPointerEvent) {
- expect().nothing()
- done()
- return
- }
-
- document.documentElement.ontouchstart = noop
- document.head.append(stylesCarousel)
- Simulator.setType('pointer')
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-bs-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, '_slide').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', event => {
- expect(item).not.toHaveClass('active')
- expect(carousel._slide).toHaveBeenCalledWith('left')
- expect(event.direction).toEqual('left')
- stylesCarousel.remove()
- delete document.documentElement.ontouchstart
- done()
- })
+ it('should allow swipeleft and call next with pointer events', () => {
+ return new Promise(resolve => {
+ if (!supportPointerEvent) {
+ expect().nothing()
+ resolve()
+ return
+ }
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0
+ document.documentElement.ontouchstart = noop
+ document.head.append(stylesCarousel)
+ Simulator.setType('pointer')
+
+ fixtureEl.innerHTML = [
+ '<div class="carousel" data-bs-interval="false">',
+ ' <div class="carousel-inner">',
+ ' <div id="item" class="carousel-item active">',
+ ' <img alt="">',
+ ' </div>',
+ ' <div class="carousel-item">',
+ ' <img alt="">',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const item = fixtureEl.querySelector('#item')
+ const carousel = new Carousel(carouselEl)
+
+ spyOn(carousel, '_slide').and.callThrough()
+
+ carouselEl.addEventListener('slid.bs.carousel', event => {
+ expect(item).not.toHaveClass('active')
+ expect(carousel._slide).toHaveBeenCalledWith('left')
+ expect(event.direction).toEqual('left')
+ stylesCarousel.remove()
+ delete document.documentElement.ontouchstart
+ resolve()
+ })
+
+ Simulator.gestures.swipe(carouselEl, {
+ pos: [300, 10],
+ deltaX: -300,
+ deltaY: 0
+ })
})
})
- it('should allow swiperight and call _slide (prev) with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = noop
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-bs-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, '_slide').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', event => {
- expect(item).toHaveClass('active')
- expect(carousel._slide).toHaveBeenCalledWith('right')
- expect(event.direction).toEqual('right')
- delete document.documentElement.ontouchstart
- restorePointerEvents()
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- deltaX: 300,
- deltaY: 0
+ it('should allow swiperight and call _slide (prev) with touch events', () => {
+ return new Promise(resolve => {
+ Simulator.setType('touch')
+ clearPointerEvents()
+ document.documentElement.ontouchstart = noop
+
+ fixtureEl.innerHTML = [
+ '<div class="carousel" data-bs-interval="false">',
+ ' <div class="carousel-inner">',
+ ' <div id="item" class="carousel-item">',
+ ' <img alt="">',
+ ' </div>',
+ ' <div class="carousel-item active">',
+ ' <img alt="">',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const item = fixtureEl.querySelector('#item')
+ const carousel = new Carousel(carouselEl)
+
+ spyOn(carousel, '_slide').and.callThrough()
+
+ carouselEl.addEventListener('slid.bs.carousel', event => {
+ expect(item).toHaveClass('active')
+ expect(carousel._slide).toHaveBeenCalledWith('right')
+ expect(event.direction).toEqual('right')
+ delete document.documentElement.ontouchstart
+ restorePointerEvents()
+ resolve()
+ })
+
+ Simulator.gestures.swipe(carouselEl, {
+ deltaX: 300,
+ deltaY: 0
+ })
})
})
- it('should allow swipeleft and call _slide (next) with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = noop
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-bs-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, '_slide').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', event => {
- expect(item).not.toHaveClass('active')
- expect(carousel._slide).toHaveBeenCalledWith('left')
- expect(event.direction).toEqual('left')
- delete document.documentElement.ontouchstart
- restorePointerEvents()
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0
+ it('should allow swipeleft and call _slide (next) with touch events', () => {
+ return new Promise(resolve => {
+ Simulator.setType('touch')
+ clearPointerEvents()
+ document.documentElement.ontouchstart = noop
+
+ fixtureEl.innerHTML = [
+ '<div class="carousel" data-bs-interval="false">',
+ ' <div class="carousel-inner">',
+ ' <div id="item" class="carousel-item active">',
+ ' <img alt="">',
+ ' </div>',
+ ' <div class="carousel-item">',
+ ' <img alt="">',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const item = fixtureEl.querySelector('#item')
+ const carousel = new Carousel(carouselEl)
+
+ spyOn(carousel, '_slide').and.callThrough()
+
+ carouselEl.addEventListener('slid.bs.carousel', event => {
+ expect(item).not.toHaveClass('active')
+ expect(carousel._slide).toHaveBeenCalledWith('left')
+ expect(event.direction).toEqual('left')
+ delete document.documentElement.ontouchstart
+ restorePointerEvents()
+ resolve()
+ })
+
+ Simulator.gestures.swipe(carouselEl, {
+ pos: [300, 10],
+ deltaX: -300,
+ deltaY: 0
+ })
})
})
- it('should not slide when swiping and carousel is sliding', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = noop
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-bs-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not slide when swiping and carousel is sliding', () => {
+ return new Promise(resolve => {
+ Simulator.setType('touch')
+ clearPointerEvents()
+ document.documentElement.ontouchstart = noop
+
+ fixtureEl.innerHTML = [
+ '<div class="carousel" data-bs-interval="false">',
+ ' <div class="carousel-inner">',
+ ' <div id="item" class="carousel-item active">',
+ ' <img alt="">',
+ ' </div>',
+ ' <div class="carousel-item">',
+ ' <img alt="">',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const carousel = new Carousel(carouselEl)
+ carousel._isSliding = true
+
+ spyOn(carousel, '_triggerSlideEvent')
+
+ Simulator.gestures.swipe(carouselEl, {
+ deltaX: 300,
+ deltaY: 0
+ })
+
+ Simulator.gestures.swipe(carouselEl, {
+ pos: [300, 10],
+ deltaX: -300,
+ deltaY: 0
+ })
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
- carousel._isSliding = true
-
- spyOn(carousel, '_triggerSlideEvent')
-
- Simulator.gestures.swipe(carouselEl, {
- deltaX: 300,
- deltaY: 0
- })
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0
+ setTimeout(() => {
+ expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
+ delete document.documentElement.ontouchstart
+ restorePointerEvents()
+ resolve()
+ }, 300)
})
-
- setTimeout(() => {
- expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
- delete document.documentElement.ontouchstart
- restorePointerEvents()
- done()
- }, 300)
})
- it('should not allow pinch with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = noop
-
- fixtureEl.innerHTML = '<div class="carousel" data-bs-interval="false"></div>'
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0,
- touches: 2
- }, () => {
- restorePointerEvents()
- delete document.documentElement.ontouchstart
- expect(carousel._swipeHelper._deltaX).toEqual(0)
- done()
+ it('should not allow pinch with touch events', () => {
+ return new Promise(resolve => {
+ Simulator.setType('touch')
+ clearPointerEvents()
+ document.documentElement.ontouchstart = noop
+
+ fixtureEl.innerHTML = '<div class="carousel" data-bs-interval="false"></div>'
+
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const carousel = new Carousel(carouselEl)
+
+ Simulator.gestures.swipe(carouselEl, {
+ pos: [300, 10],
+ deltaX: -300,
+ deltaY: 0,
+ touches: 2
+ }, () => {
+ restorePointerEvents()
+ delete document.documentElement.ontouchstart
+ expect(carousel._swipeHelper._deltaX).toEqual(0)
+ resolve()
+ })
})
})
- it('should call pause method on mouse over with pause equal to hover', done => {
- fixtureEl.innerHTML = '<div class="carousel"></div>'
+ it('should call pause method on mouse over with pause equal to hover', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="carousel"></div>'
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'pause')
+ spyOn(carousel, 'pause')
- const mouseOverEvent = createEvent('mouseover')
- carouselEl.dispatchEvent(mouseOverEvent)
+ const mouseOverEvent = createEvent('mouseover')
+ carouselEl.dispatchEvent(mouseOverEvent)
- setTimeout(() => {
- expect(carousel.pause).toHaveBeenCalled()
- done()
- }, 10)
+ setTimeout(() => {
+ expect(carousel.pause).toHaveBeenCalled()
+ resolve()
+ }, 10)
+ })
})
- it('should call cycle on mouse out with pause equal to hover', done => {
- fixtureEl.innerHTML = '<div class="carousel"></div>'
+ it('should call cycle on mouse out with pause equal to hover', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="carousel"></div>'
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
+ const carouselEl = fixtureEl.querySelector('.carousel')
+ const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'cycle')
+ spyOn(carousel, 'cycle')
- const mouseOutEvent = createEvent('mouseout')
- carouselEl.dispatchEvent(mouseOutEvent)
+ const mouseOutEvent = createEvent('mouseout')
+ carouselEl.dispatchEvent(mouseOutEvent)
- setTimeout(() => {
- expect(carousel.cycle).toHaveBeenCalled()
- done()
- }, 10)
+ setTimeout(() => {
+ expect(carousel.cycle).toHaveBeenCalled()
+ resolve()
+ }, 10)
+ })
})
})
@@ -621,100 +647,106 @@ describe('Carousel', () => {
expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
})
- it('should not fire slid when slide is prevented', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should not fire slid when slide is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const carouselEl = fixtureEl.querySelector('div')
- const carousel = new Carousel(carouselEl, {})
- let slidEvent = false
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+ let slidEvent = false
- const doneTest = () => {
- setTimeout(() => {
- expect(slidEvent).toBeFalse()
- done()
- }, 20)
- }
+ const doneTest = () => {
+ setTimeout(() => {
+ expect(slidEvent).toBeFalse()
+ resolve()
+ }, 20)
+ }
- carouselEl.addEventListener('slide.bs.carousel', event => {
- event.preventDefault()
- doneTest()
- })
+ carouselEl.addEventListener('slide.bs.carousel', event => {
+ event.preventDefault()
+ doneTest()
+ })
- carouselEl.addEventListener('slid.bs.carousel', () => {
- slidEvent = true
- })
+ carouselEl.addEventListener('slid.bs.carousel', () => {
+ slidEvent = true
+ })
- carousel.next()
+ carousel.next()
+ })
})
- it('should fire slide event with: direction, relatedTarget, from and to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should fire slide event with: direction, relatedTarget, from and to', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, {})
- const onSlide = event => {
- expect(event.direction).toEqual('left')
- expect(event.relatedTarget).toHaveClass('carousel-item')
- expect(event.from).toEqual(0)
- expect(event.to).toEqual(1)
+ const onSlide = event => {
+ expect(event.direction).toEqual('left')
+ expect(event.relatedTarget).toHaveClass('carousel-item')
+ expect(event.from).toEqual(0)
+ expect(event.to).toEqual(1)
- carouselEl.removeEventListener('slide.bs.carousel', onSlide)
- carouselEl.addEventListener('slide.bs.carousel', onSlide2)
+ carouselEl.removeEventListener('slide.bs.carousel', onSlide)
+ carouselEl.addEventListener('slide.bs.carousel', onSlide2)
- carousel.prev()
- }
+ carousel.prev()
+ }
- const onSlide2 = event => {
- expect(event.direction).toEqual('right')
- done()
- }
+ const onSlide2 = event => {
+ expect(event.direction).toEqual('right')
+ resolve()
+ }
- carouselEl.addEventListener('slide.bs.carousel', onSlide)
- carousel.next()
+ carouselEl.addEventListener('slide.bs.carousel', onSlide)
+ carousel.next()
+ })
})
- it('should fire slid event with: direction, relatedTarget, from and to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should fire slid event with: direction, relatedTarget, from and to', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, {})
- const onSlid = event => {
- expect(event.direction).toEqual('left')
- expect(event.relatedTarget).toHaveClass('carousel-item')
- expect(event.from).toEqual(0)
- expect(event.to).toEqual(1)
+ const onSlid = event => {
+ expect(event.direction).toEqual('left')
+ expect(event.relatedTarget).toHaveClass('carousel-item')
+ expect(event.from).toEqual(0)
+ expect(event.to).toEqual(1)
- carouselEl.removeEventListener('slid.bs.carousel', onSlid)
- carouselEl.addEventListener('slid.bs.carousel', onSlid2)
+ carouselEl.removeEventListener('slid.bs.carousel', onSlid)
+ carouselEl.addEventListener('slid.bs.carousel', onSlid2)
- carousel.prev()
- }
+ carousel.prev()
+ }
- const onSlid2 = event => {
- expect(event.direction).toEqual('right')
- done()
- }
+ const onSlid2 = event => {
+ expect(event.direction).toEqual('right')
+ resolve()
+ }
- carouselEl.addEventListener('slid.bs.carousel', onSlid)
- carousel.next()
+ carouselEl.addEventListener('slid.bs.carousel', onSlid)
+ carousel.next()
+ })
})
it('should update the active element to the next item before sliding', () => {
@@ -737,36 +769,38 @@ describe('Carousel', () => {
expect(carousel._activeElement).toEqual(secondItemEl)
})
- it('should update indicators if present', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-indicators">',
- ' <button type="button" id="firstIndicator" data-bs-target="myCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>',
- ' <button type="button" id="secondIndicator" data-bs-target="myCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button>',
- ' <button type="button" data-bs-target="myCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button>',
- ' </div>',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-bs-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const firstIndicator = fixtureEl.querySelector('#firstIndicator')
- const secondIndicator = fixtureEl.querySelector('#secondIndicator')
- const carousel = new Carousel(carouselEl)
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(firstIndicator).not.toHaveClass('active')
- expect(firstIndicator.hasAttribute('aria-current')).toBeFalse()
- expect(secondIndicator).toHaveClass('active')
- expect(secondIndicator.getAttribute('aria-current')).toEqual('true')
- done()
+ it('should update indicators if present', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-indicators">',
+ ' <button type="button" id="firstIndicator" data-bs-target="myCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>',
+ ' <button type="button" id="secondIndicator" data-bs-target="myCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button>',
+ ' <button type="button" data-bs-target="myCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button>',
+ ' </div>',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item" data-bs-interval="7">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const firstIndicator = fixtureEl.querySelector('#firstIndicator')
+ const secondIndicator = fixtureEl.querySelector('#secondIndicator')
+ const carousel = new Carousel(carouselEl)
+
+ carouselEl.addEventListener('slid.bs.carousel', () => {
+ expect(firstIndicator).not.toHaveClass('active')
+ expect(firstIndicator.hasAttribute('aria-current')).toBeFalse()
+ expect(secondIndicator).toHaveClass('active')
+ expect(secondIndicator.getAttribute('aria-current')).toEqual('true')
+ resolve()
+ })
+
+ carousel.next()
})
-
- carousel.next()
})
it('should call next()/prev() instance methods when clicking the respective direction buttons', () => {
@@ -1018,51 +1052,55 @@ describe('Carousel', () => {
})
describe('to', () => {
- it('should go directly to the provided index', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="item1" class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div id="item3" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should go directly to the provided index', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div id="item1" class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item">item 2</div>',
+ ' <div id="item3" class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, {})
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1'))
+ expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1'))
- carousel.to(2)
+ carousel.to(2)
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
- done()
+ carouselEl.addEventListener('slid.bs.carousel', () => {
+ expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
+ resolve()
+ })
})
})
- it('should return to a previous slide if the provided index is lower than the current', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div id="item3" class="carousel-item active">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should return to a previous slide if the provided index is lower than the current', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item">item 1</div>',
+ ' <div id="item2" class="carousel-item">item 2</div>',
+ ' <div id="item3" class="carousel-item active">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, {})
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
+ expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
- carousel.to(1)
+ carousel.to(1)
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2'))
- done()
+ carouselEl.addEventListener('slid.bs.carousel', () => {
+ expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2'))
+ resolve()
+ })
})
})
@@ -1118,36 +1156,38 @@ describe('Carousel', () => {
expect(carousel.cycle).toHaveBeenCalled()
})
- it('should wait before performing to if a slide is sliding', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-bs-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should wait before performing to if a slide is sliding', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div class="carousel-item" data-bs-interval="7">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carousel = new Carousel(carouselEl, {})
- spyOn(EventHandler, 'one').and.callThrough()
- spyOn(carousel, '_slide')
+ spyOn(EventHandler, 'one').and.callThrough()
+ spyOn(carousel, '_slide')
- carousel._isSliding = true
- carousel.to(1)
+ carousel._isSliding = true
+ carousel.to(1)
- expect(carousel._slide).not.toHaveBeenCalled()
- expect(EventHandler.one).toHaveBeenCalled()
+ expect(carousel._slide).not.toHaveBeenCalled()
+ expect(EventHandler.one).toHaveBeenCalled()
- spyOn(carousel, 'to')
+ spyOn(carousel, 'to')
- EventHandler.trigger(carouselEl, 'slid.bs.carousel')
+ EventHandler.trigger(carouselEl, 'slid.bs.carousel')
- setTimeout(() => {
- expect(carousel.to).toHaveBeenCalledWith(1)
- done()
+ setTimeout(() => {
+ expect(carousel.to).toHaveBeenCalledWith(1)
+ resolve()
+ })
})
})
})
@@ -1421,75 +1461,81 @@ describe('Carousel', () => {
expect(Carousel.getInstance(carouselEl)).not.toBeNull()
})
- it('should create carousel and go to the next slide on click (with real button controls)', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></button>',
- ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></button>',
- '</div>'
- ].join('')
+ it('should create carousel and go to the next slide on click (with real button controls)', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div id="item2" class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></button>',
+ ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></button>',
+ '</div>'
+ ].join('')
- const next = fixtureEl.querySelector('#next')
- const item2 = fixtureEl.querySelector('#item2')
+ const next = fixtureEl.querySelector('#next')
+ const item2 = fixtureEl.querySelector('#item2')
- next.click()
+ next.click()
- setTimeout(() => {
- expect(item2).toHaveClass('active')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(item2).toHaveClass('active')
+ resolve()
+ }, 10)
+ })
})
- it('should create carousel and go to the next slide on click (using links as controls)', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <a class="carousel-control-prev" href="#myCarousel" role="button" data-bs-slide="prev"></a>',
- ' <a id="next" class="carousel-control-next" href="#myCarousel" role="button" data-bs-slide="next"></a>',
- '</div>'
- ].join('')
+ it('should create carousel and go to the next slide on click (using links as controls)', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div id="item2" class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ ' <a class="carousel-control-prev" href="#myCarousel" role="button" data-bs-slide="prev"></a>',
+ ' <a id="next" class="carousel-control-next" href="#myCarousel" role="button" data-bs-slide="next"></a>',
+ '</div>'
+ ].join('')
- const next = fixtureEl.querySelector('#next')
- const item2 = fixtureEl.querySelector('#item2')
+ const next = fixtureEl.querySelector('#next')
+ const item2 = fixtureEl.querySelector('#item2')
- next.click()
+ next.click()
- setTimeout(() => {
- expect(item2).toHaveClass('active')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(item2).toHaveClass('active')
+ resolve()
+ }, 10)
+ })
})
- it('should create carousel and go to the next slide on click with data-bs-slide-to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div id="next" data-bs-target="#myCarousel" data-bs-slide-to="1"></div>',
- '</div>'
- ].join('')
+ it('should create carousel and go to the next slide on click with data-bs-slide-to', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="myCarousel" class="carousel slide">',
+ ' <div class="carousel-inner">',
+ ' <div class="carousel-item active">item 1</div>',
+ ' <div id="item2" class="carousel-item">item 2</div>',
+ ' <div class="carousel-item">item 3</div>',
+ ' </div>',
+ ' <div id="next" data-bs-target="#myCarousel" data-bs-slide-to="1"></div>',
+ '</div>'
+ ].join('')
- const next = fixtureEl.querySelector('#next')
- const item2 = fixtureEl.querySelector('#item2')
+ const next = fixtureEl.querySelector('#next')
+ const item2 = fixtureEl.querySelector('#item2')
- next.click()
+ next.click()
- setTimeout(() => {
- expect(item2).toHaveClass('active')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(item2).toHaveClass('active')
+ resolve()
+ }, 10)
+ })
})
it('should do nothing if no selector on click on arrows', () => {
diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js
index 327a68449b..e2d2864905 100644
--- a/js/tests/unit/collapse.spec.js
+++ b/js/tests/unit/collapse.spec.js
@@ -134,37 +134,39 @@ describe('Collapse', () => {
expect(collapse.hide).toHaveBeenCalled()
})
- it('should find collapse children if they have collapse class too not only data-bs-parent', done => {
- fixtureEl.innerHTML = [
- '<div class="my-collapse">',
- ' <div class="item">',
- ' <a data-bs-toggle="collapse" href="#">Toggle item 1</a>',
- ' <div id="collapse1" class="collapse show">Lorem ipsum 1</div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="triggerCollapse2" data-bs-toggle="collapse" href="#">Toggle item 2</a>',
- ' <div id="collapse2" class="collapse">Lorem ipsum 2</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const parent = fixtureEl.querySelector('.my-collapse')
- const collapseEl1 = fixtureEl.querySelector('#collapse1')
- const collapseEl2 = fixtureEl.querySelector('#collapse2')
-
- const collapseList = [].concat(...fixtureEl.querySelectorAll('.collapse'))
- .map(el => new Collapse(el, {
- parent,
- toggle: false
- }))
+ it('should find collapse children if they have collapse class too not only data-bs-parent', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="my-collapse">',
+ ' <div class="item">',
+ ' <a data-bs-toggle="collapse" href="#">Toggle item 1</a>',
+ ' <div id="collapse1" class="collapse show">Lorem ipsum 1</div>',
+ ' </div>',
+ ' <div class="item">',
+ ' <a id="triggerCollapse2" data-bs-toggle="collapse" href="#">Toggle item 2</a>',
+ ' <div id="collapse2" class="collapse">Lorem ipsum 2</div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const parent = fixtureEl.querySelector('.my-collapse')
+ const collapseEl1 = fixtureEl.querySelector('#collapse1')
+ const collapseEl2 = fixtureEl.querySelector('#collapse2')
+
+ const collapseList = [].concat(...fixtureEl.querySelectorAll('.collapse'))
+ .map(el => new Collapse(el, {
+ parent,
+ toggle: false
+ }))
+
+ collapseEl2.addEventListener('shown.bs.collapse', () => {
+ expect(collapseEl2).toHaveClass('show')
+ expect(collapseEl1).not.toHaveClass('show')
+ resolve()
+ })
- collapseEl2.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl2).toHaveClass('show')
- expect(collapseEl1).not.toHaveClass('show')
- done()
+ collapseList[1].toggle()
})
-
- collapseList[1].toggle()
})
})
@@ -200,203 +202,215 @@ describe('Collapse', () => {
expect(EventHandler.trigger).not.toHaveBeenCalled()
})
- it('should show a collapsed element', done => {
- fixtureEl.innerHTML = '<div class="collapse" style="height: 0px;"></div>'
+ it('should show a collapsed element', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="collapse" style="height: 0px;"></div>'
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
+ const collapseEl = fixtureEl.querySelector('div')
+ const collapse = new Collapse(collapseEl, {
+ toggle: false
+ })
- collapseEl.addEventListener('show.bs.collapse', () => {
- expect(collapseEl.style.height).toEqual('0px')
- })
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl).toHaveClass('show')
- expect(collapseEl.style.height).toEqual('')
- done()
- })
+ collapseEl.addEventListener('show.bs.collapse', () => {
+ expect(collapseEl.style.height).toEqual('0px')
+ })
+ collapseEl.addEventListener('shown.bs.collapse', () => {
+ expect(collapseEl).toHaveClass('show')
+ expect(collapseEl.style.height).toEqual('')
+ resolve()
+ })
- collapse.show()
+ collapse.show()
+ })
})
- it('should show a collapsed element on width', done => {
- fixtureEl.innerHTML = '<div class="collapse collapse-horizontal" style="width: 0px;"></div>'
+ it('should show a collapsed element on width', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="collapse collapse-horizontal" style="width: 0px;"></div>'
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
+ const collapseEl = fixtureEl.querySelector('div')
+ const collapse = new Collapse(collapseEl, {
+ toggle: false
+ })
- collapseEl.addEventListener('show.bs.collapse', () => {
- expect(collapseEl.style.width).toEqual('0px')
- })
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl).toHaveClass('show')
- expect(collapseEl.style.width).toEqual('')
- done()
- })
+ collapseEl.addEventListener('show.bs.collapse', () => {
+ expect(collapseEl.style.width).toEqual('0px')
+ })
+ collapseEl.addEventListener('shown.bs.collapse', () => {
+ expect(collapseEl).toHaveClass('show')
+ expect(collapseEl.style.width).toEqual('')
+ resolve()
+ })
- collapse.show()
+ collapse.show()
+ })
})
- it('should collapse only the first collapse', done => {
- fixtureEl.innerHTML = [
- '<div class="card" id="accordion1">',
- ' <div id="collapse1" class="collapse"></div>',
- '</div>',
- '<div class="card" id="accordion2">',
- ' <div id="collapse2" class="collapse show"></div>',
- '</div>'
- ].join('')
+ it('should collapse only the first collapse', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="card" id="accordion1">',
+ ' <div id="collapse1" class="collapse"></div>',
+ '</div>',
+ '<div class="card" id="accordion2">',
+ ' <div id="collapse2" class="collapse show"></div>',
+ '</div>'
+ ].join('')
+
+ const el1 = fixtureEl.querySelector('#collapse1')
+ const el2 = fixtureEl.querySelector('#collapse2')
+ const collapse = new Collapse(el1, {
+ toggle: false
+ })
- const el1 = fixtureEl.querySelector('#collapse1')
- const el2 = fixtureEl.querySelector('#collapse2')
- const collapse = new Collapse(el1, {
- toggle: false
- })
+ el1.addEventListener('shown.bs.collapse', () => {
+ expect(el1).toHaveClass('show')
+ expect(el2).toHaveClass('show')
+ resolve()
+ })
- el1.addEventListener('shown.bs.collapse', () => {
- expect(el1).toHaveClass('show')
- expect(el2).toHaveClass('show')
- done()
+ collapse.show()
})
-
- collapse.show()
})
- it('should be able to handle toggling of other children siblings', done => {
- fixtureEl.innerHTML = [
- '<div id="parentGroup" class="accordion">',
- ' <div id="parentHeader" class="accordion-header">',
- ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" role="button" class="accordion-toggle">Parent</button>',
- ' </div>',
- ' <div id="parentContent" class="accordion-collapse collapse" aria-labelledby="parentHeader" data-bs-parent="#parentGroup">',
- ' <div class="accordion-body">',
- ' <div id="childGroup" class="accordion">',
- ' <div class="accordion-item">',
- ' <div id="childHeader1" class="accordion-header">',
- ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 1</button>',
- ' </div>',
- ' <div id="childContent1" class="accordion-collapse collapse" aria-labelledby="childHeader1" data-bs-parent="#childGroup">',
- ' <div>content</div>',
- ' </div>',
- ' </div>',
- ' <div class="accordion-item">',
- ' <div id="childHeader2" class="accordion-header">',
- ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 2</button>',
- ' </div>',
- ' <div id="childContent2" class="accordion-collapse collapse" aria-labelledby="childHeader2" data-bs-parent="#childGroup">',
- ' <div>content</div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const el = selector => fixtureEl.querySelector(selector)
-
- const parentBtn = el('[data-bs-target="#parentContent"]')
- const childBtn1 = el('[data-bs-target="#childContent1"]')
- const childBtn2 = el('[data-bs-target="#childContent2"]')
-
- const parentCollapseEl = el('#parentContent')
- const childCollapseEl1 = el('#childContent1')
- const childCollapseEl2 = el('#childContent2')
+ it('should be able to handle toggling of other children siblings', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="parentGroup" class="accordion">',
+ ' <div id="parentHeader" class="accordion-header">',
+ ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" role="button" class="accordion-toggle">Parent</button>',
+ ' </div>',
+ ' <div id="parentContent" class="accordion-collapse collapse" aria-labelledby="parentHeader" data-bs-parent="#parentGroup">',
+ ' <div class="accordion-body">',
+ ' <div id="childGroup" class="accordion">',
+ ' <div class="accordion-item">',
+ ' <div id="childHeader1" class="accordion-header">',
+ ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 1</button>',
+ ' </div>',
+ ' <div id="childContent1" class="accordion-collapse collapse" aria-labelledby="childHeader1" data-bs-parent="#childGroup">',
+ ' <div>content</div>',
+ ' </div>',
+ ' </div>',
+ ' <div class="accordion-item">',
+ ' <div id="childHeader2" class="accordion-header">',
+ ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 2</button>',
+ ' </div>',
+ ' <div id="childContent2" class="accordion-collapse collapse" aria-labelledby="childHeader2" data-bs-parent="#childGroup">',
+ ' <div>content</div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const el = selector => fixtureEl.querySelector(selector)
+
+ const parentBtn = el('[data-bs-target="#parentContent"]')
+ const childBtn1 = el('[data-bs-target="#childContent1"]')
+ const childBtn2 = el('[data-bs-target="#childContent2"]')
+
+ const parentCollapseEl = el('#parentContent')
+ const childCollapseEl1 = el('#childContent1')
+ const childCollapseEl2 = el('#childContent2')
+
+ parentCollapseEl.addEventListener('shown.bs.collapse', () => {
+ expect(parentCollapseEl).toHaveClass('show')
+ childBtn1.click()
+ })
+ childCollapseEl1.addEventListener('shown.bs.collapse', () => {
+ expect(childCollapseEl1).toHaveClass('show')
+ childBtn2.click()
+ })
+ childCollapseEl2.addEventListener('shown.bs.collapse', () => {
+ expect(childCollapseEl2).toHaveClass('show')
+ expect(childCollapseEl1).not.toHaveClass('show')
+ resolve()
+ })
- parentCollapseEl.addEventListener('shown.bs.collapse', () => {
- expect(parentCollapseEl).toHaveClass('show')
- childBtn1.click()
+ parentBtn.click()
})
- childCollapseEl1.addEventListener('shown.bs.collapse', () => {
- expect(childCollapseEl1).toHaveClass('show')
- childBtn2.click()
- })
- childCollapseEl2.addEventListener('shown.bs.collapse', () => {
- expect(childCollapseEl2).toHaveClass('show')
- expect(childCollapseEl1).not.toHaveClass('show')
- done()
- })
-
- parentBtn.click()
})
- it('should not change tab tabpanels descendants on accordion', done => {
- fixtureEl.innerHTML = [
- '<div class="accordion" id="accordionExample">',
- ' <div class="accordion-item">',
- ' <h2 class="accordion-header" id="headingOne">',
- ' <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">',
- ' Accordion Item #1',
- ' </button>',
- ' </h2>',
- ' <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">',
- ' <div class="accordion-body">',
- ' <nav>',
- ' <div class="nav nav-tabs" id="nav-tab" role="tablist">',
- ' <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>',
- ' <button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>',
- ' </div>',
- ' </nav>',
- ' <div class="tab-content" id="nav-tabContent">',
- ' <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">Home</div>',
- ' <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">Profile</div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const el = fixtureEl.querySelector('#collapseOne')
- const activeTabPane = fixtureEl.querySelector('#nav-home')
- const collapse = new Collapse(el)
- let times = 1
+ it('should not change tab tabpanels descendants on accordion', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="accordion" id="accordionExample">',
+ ' <div class="accordion-item">',
+ ' <h2 class="accordion-header" id="headingOne">',
+ ' <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">',
+ ' Accordion Item #1',
+ ' </button>',
+ ' </h2>',
+ ' <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">',
+ ' <div class="accordion-body">',
+ ' <nav>',
+ ' <div class="nav nav-tabs" id="nav-tab" role="tablist">',
+ ' <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>',
+ ' <button class="nav-link" id="nav-profile-tab" data-bs-toggle="tab" data-bs-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>',
+ ' </div>',
+ ' </nav>',
+ ' <div class="tab-content" id="nav-tabContent">',
+ ' <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">Home</div>',
+ ' <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">Profile</div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const el = fixtureEl.querySelector('#collapseOne')
+ const activeTabPane = fixtureEl.querySelector('#nav-home')
+ const collapse = new Collapse(el)
+ let times = 1
+
+ el.addEventListener('hidden.bs.collapse', () => {
+ collapse.show()
+ })
- el.addEventListener('hidden.bs.collapse', () => {
- collapse.show()
- })
+ el.addEventListener('shown.bs.collapse', () => {
+ expect(activeTabPane).toHaveClass('show')
+ times++
+ if (times === 2) {
+ resolve()
+ }
- el.addEventListener('shown.bs.collapse', () => {
- expect(activeTabPane).toHaveClass('show')
- times++
- if (times === 2) {
- done()
- }
+ collapse.hide()
+ })
- collapse.hide()
+ collapse.show()
})
-
- collapse.show()
})
- it('should not fire shown when show is prevented', done => {
- fixtureEl.innerHTML = '<div class="collapse"></div>'
+ it('should not fire shown when show is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="collapse"></div>'
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
+ const collapseEl = fixtureEl.querySelector('div')
+ const collapse = new Collapse(collapseEl, {
+ toggle: false
+ })
- const expectEnd = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- }
+ const expectEnd = () => {
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ }
- collapseEl.addEventListener('show.bs.collapse', event => {
- event.preventDefault()
- expectEnd()
- })
+ collapseEl.addEventListener('show.bs.collapse', event => {
+ event.preventDefault()
+ expectEnd()
+ })
- collapseEl.addEventListener('shown.bs.collapse', () => {
- throw new Error('should not fire shown event')
- })
+ collapseEl.addEventListener('shown.bs.collapse', () => {
+ throw new Error('should not fire shown event')
+ })
- collapse.show()
+ collapse.show()
+ })
})
})
@@ -432,48 +446,52 @@ describe('Collapse', () => {
expect(EventHandler.trigger).not.toHaveBeenCalled()
})
- it('should hide a collapsed element', done => {
- fixtureEl.innerHTML = '<div class="collapse show"></div>'
+ it('should hide a collapsed element', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="collapse show"></div>'
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
+ const collapseEl = fixtureEl.querySelector('div')
+ const collapse = new Collapse(collapseEl, {
+ toggle: false
+ })
- collapseEl.addEventListener('hidden.bs.collapse', () => {
- expect(collapseEl).not.toHaveClass('show')
- expect(collapseEl.style.height).toEqual('')
- done()
- })
+ collapseEl.addEventListener('hidden.bs.collapse', () => {
+ expect(collapseEl).not.toHaveClass('show')
+ expect(collapseEl.style.height).toEqual('')
+ resolve()
+ })
- collapse.hide()
+ collapse.hide()
+ })
})
- it('should not fire hidden when hide is prevented', done => {
- fixtureEl.innerHTML = '<div class="collapse show"></div>'
+ it('should not fire hidden when hide is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="collapse show"></div>'
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
+ const collapseEl = fixtureEl.querySelector('div')
+ const collapse = new Collapse(collapseEl, {
+ toggle: false
+ })
- const expectEnd = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- }
+ const expectEnd = () => {
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ }
- collapseEl.addEventListener('hide.bs.collapse', event => {
- event.preventDefault()
- expectEnd()
- })
+ collapseEl.addEventListener('hide.bs.collapse', event => {
+ event.preventDefault()
+ expectEnd()
+ })
- collapseEl.addEventListener('hidden.bs.collapse', () => {
- throw new Error('should not fire hidden event')
- })
+ collapseEl.addEventListener('hidden.bs.collapse', () => {
+ throw new Error('should not fire hidden event')
+ })
- collapse.hide()
+ collapse.hide()
+ })
})
})
@@ -495,411 +513,433 @@ describe('Collapse', () => {
})
describe('data-api', () => {
- it('should prevent url change if click on nested elements', done => {
- fixtureEl.innerHTML = [
- '<a role="button" data-bs-toggle="collapse" class="collapsed" href="#collapse">',
- ' <span id="nested"></span>',
- '</a>',
- '<div id="collapse" class="collapse"></div>'
- ].join('')
-
- const triggerEl = fixtureEl.querySelector('a')
- const nestedTriggerEl = fixtureEl.querySelector('#nested')
-
- spyOn(Event.prototype, 'preventDefault').and.callThrough()
+ it('should prevent url change if click on nested elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a role="button" data-bs-toggle="collapse" class="collapsed" href="#collapse">',
+ ' <span id="nested"></span>',
+ '</a>',
+ '<div id="collapse" class="collapse"></div>'
+ ].join('')
+
+ const triggerEl = fixtureEl.querySelector('a')
+ const nestedTriggerEl = fixtureEl.querySelector('#nested')
+
+ spyOn(Event.prototype, 'preventDefault').and.callThrough()
+
+ triggerEl.addEventListener('click', event => {
+ expect(event.target.isEqualNode(nestedTriggerEl)).toBeTrue()
+ expect(event.delegateTarget.isEqualNode(triggerEl)).toBeTrue()
+ expect(Event.prototype.preventDefault).toHaveBeenCalled()
+ resolve()
+ })
- triggerEl.addEventListener('click', event => {
- expect(event.target.isEqualNode(nestedTriggerEl)).toBeTrue()
- expect(event.delegateTarget.isEqualNode(triggerEl)).toBeTrue()
- expect(Event.prototype.preventDefault).toHaveBeenCalled()
- done()
+ nestedTriggerEl.click()
})
-
- nestedTriggerEl.click()
})
- it('should show multiple collapsed elements', done => {
- fixtureEl.innerHTML = [
- '<a role="button" data-bs-toggle="collapse" class="collapsed" href=".multi"></a>',
- '<div id="collapse1" class="collapse multi"></div>',
- '<div id="collapse2" class="collapse multi"></div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('a')
- const collapse1 = fixtureEl.querySelector('#collapse1')
- const collapse2 = fixtureEl.querySelector('#collapse2')
+ it('should show multiple collapsed elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a role="button" data-bs-toggle="collapse" class="collapsed" href=".multi"></a>',
+ '<div id="collapse1" class="collapse multi"></div>',
+ '<div id="collapse2" class="collapse multi"></div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('a')
+ const collapse1 = fixtureEl.querySelector('#collapse1')
+ const collapse2 = fixtureEl.querySelector('#collapse2')
+
+ collapse2.addEventListener('shown.bs.collapse', () => {
+ expect(trigger.getAttribute('aria-expanded')).toEqual('true')
+ expect(trigger).not.toHaveClass('collapsed')
+ expect(collapse1).toHaveClass('show')
+ expect(collapse1).toHaveClass('show')
+ resolve()
+ })
- collapse2.addEventListener('shown.bs.collapse', () => {
- expect(trigger.getAttribute('aria-expanded')).toEqual('true')
- expect(trigger).not.toHaveClass('collapsed')
- expect(collapse1).toHaveClass('show')
- expect(collapse1).toHaveClass('show')
- done()
+ trigger.click()
})
-
- trigger.click()
})
- it('should hide multiple collapsed elements', done => {
- fixtureEl.innerHTML = [
- '<a role="button" data-bs-toggle="collapse" href=".multi"></a>',
- '<div id="collapse1" class="collapse multi show"></div>',
- '<div id="collapse2" class="collapse multi show"></div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('a')
- const collapse1 = fixtureEl.querySelector('#collapse1')
- const collapse2 = fixtureEl.querySelector('#collapse2')
+ it('should hide multiple collapsed elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a role="button" data-bs-toggle="collapse" href=".multi"></a>',
+ '<div id="collapse1" class="collapse multi show"></div>',
+ '<div id="collapse2" class="collapse multi show"></div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('a')
+ const collapse1 = fixtureEl.querySelector('#collapse1')
+ const collapse2 = fixtureEl.querySelector('#collapse2')
+
+ collapse2.addEventListener('hidden.bs.collapse', () => {
+ expect(trigger.getAttribute('aria-expanded')).toEqual('false')
+ expect(trigger).toHaveClass('collapsed')
+ expect(collapse1).not.toHaveClass('show')
+ expect(collapse1).not.toHaveClass('show')
+ resolve()
+ })
- collapse2.addEventListener('hidden.bs.collapse', () => {
- expect(trigger.getAttribute('aria-expanded')).toEqual('false')
- expect(trigger).toHaveClass('collapsed')
- expect(collapse1).not.toHaveClass('show')
- expect(collapse1).not.toHaveClass('show')
- done()
+ trigger.click()
})
-
- trigger.click()
})
- it('should remove "collapsed" class from target when collapse is shown', done => {
- fixtureEl.innerHTML = [
- '<a id="link1" role="button" data-bs-toggle="collapse" class="collapsed" href="#" data-bs-target="#test1"></a>',
- '<a id="link2" role="button" data-bs-toggle="collapse" class="collapsed" href="#" data-bs-target="#test1"></a>',
- '<div id="test1"></div>'
- ].join('')
-
- const link1 = fixtureEl.querySelector('#link1')
- const link2 = fixtureEl.querySelector('#link2')
- const collapseTest1 = fixtureEl.querySelector('#test1')
+ it('should remove "collapsed" class from target when collapse is shown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a id="link1" role="button" data-bs-toggle="collapse" class="collapsed" href="#" data-bs-target="#test1"></a>',
+ '<a id="link2" role="button" data-bs-toggle="collapse" class="collapsed" href="#" data-bs-target="#test1"></a>',
+ '<div id="test1"></div>'
+ ].join('')
+
+ const link1 = fixtureEl.querySelector('#link1')
+ const link2 = fixtureEl.querySelector('#link2')
+ const collapseTest1 = fixtureEl.querySelector('#test1')
+
+ collapseTest1.addEventListener('shown.bs.collapse', () => {
+ expect(link1.getAttribute('aria-expanded')).toEqual('true')
+ expect(link2.getAttribute('aria-expanded')).toEqual('true')
+ expect(link1).not.toHaveClass('collapsed')
+ expect(link2).not.toHaveClass('collapsed')
+ resolve()
+ })
- collapseTest1.addEventListener('shown.bs.collapse', () => {
- expect(link1.getAttribute('aria-expanded')).toEqual('true')
- expect(link2.getAttribute('aria-expanded')).toEqual('true')
- expect(link1).not.toHaveClass('collapsed')
- expect(link2).not.toHaveClass('collapsed')
- done()
+ link1.click()
})
-
- link1.click()
})
- it('should add "collapsed" class to target when collapse is hidden', done => {
- fixtureEl.innerHTML = [
- '<a id="link1" role="button" data-bs-toggle="collapse" href="#" data-bs-target="#test1"></a>',
- '<a id="link2" role="button" data-bs-toggle="collapse" href="#" data-bs-target="#test1"></a>',
- '<div id="test1" class="show"></div>'
- ].join('')
-
- const link1 = fixtureEl.querySelector('#link1')
- const link2 = fixtureEl.querySelector('#link2')
- const collapseTest1 = fixtureEl.querySelector('#test1')
+ it('should add "collapsed" class to target when collapse is hidden', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a id="link1" role="button" data-bs-toggle="collapse" href="#" data-bs-target="#test1"></a>',
+ '<a id="link2" role="button" data-bs-toggle="collapse" href="#" data-bs-target="#test1"></a>',
+ '<div id="test1" class="show"></div>'
+ ].join('')
+
+ const link1 = fixtureEl.querySelector('#link1')
+ const link2 = fixtureEl.querySelector('#link2')
+ const collapseTest1 = fixtureEl.querySelector('#test1')
+
+ collapseTest1.addEventListener('hidden.bs.collapse', () => {
+ expect(link1.getAttribute('aria-expanded')).toEqual('false')
+ expect(link2.getAttribute('aria-expanded')).toEqual('false')
+ expect(link1).toHaveClass('collapsed')
+ expect(link2).toHaveClass('collapsed')
+ resolve()
+ })
- collapseTest1.addEventListener('hidden.bs.collapse', () => {
- expect(link1.getAttribute('aria-expanded')).toEqual('false')
- expect(link2.getAttribute('aria-expanded')).toEqual('false')
- expect(link1).toHaveClass('collapsed')
- expect(link2).toHaveClass('collapsed')
- done()
+ link1.click()
})
-
- link1.click()
})
- it('should allow accordion to use children other than card', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('#linkTrigger')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOne = fixtureEl.querySelector('#collapseOne')
- const collapseTwo = fixtureEl.querySelector('#collapseTwo')
-
- collapseOne.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne).toHaveClass('show')
- expect(collapseTwo).not.toHaveClass('show')
+ it('should allow accordion to use children other than card', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="accordion">',
+ ' <div class="item">',
+ ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
+ ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>',
+ ' </div>',
+ ' <div class="item">',
+ ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
+ ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('#linkTrigger')
+ const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
+ const collapseOne = fixtureEl.querySelector('#collapseOne')
+ const collapseTwo = fixtureEl.querySelector('#collapseTwo')
+
+ collapseOne.addEventListener('shown.bs.collapse', () => {
+ expect(collapseOne).toHaveClass('show')
+ expect(collapseTwo).not.toHaveClass('show')
+
+ collapseTwo.addEventListener('shown.bs.collapse', () => {
+ expect(collapseOne).not.toHaveClass('show')
+ expect(collapseTwo).toHaveClass('show')
+ resolve()
+ })
- collapseTwo.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne).not.toHaveClass('show')
- expect(collapseTwo).toHaveClass('show')
- done()
+ triggerTwo.click()
})
- triggerTwo.click()
+ trigger.click()
})
-
- trigger.click()
})
- it('should not prevent event for input', done => {
- fixtureEl.innerHTML = [
- '<input type="checkbox" data-bs-toggle="collapse" data-bs-target="#collapsediv1">',
- '<div id="collapsediv1"></div>'
- ].join('')
+ it('should not prevent event for input', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<input type="checkbox" data-bs-toggle="collapse" data-bs-target="#collapsediv1">',
+ '<div id="collapsediv1"></div>'
+ ].join('')
- const target = fixtureEl.querySelector('input')
- const collapseEl = fixtureEl.querySelector('#collapsediv1')
+ const target = fixtureEl.querySelector('input')
+ const collapseEl = fixtureEl.querySelector('#collapsediv1')
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl).toHaveClass('show')
- expect(target.checked).toBeTrue()
- done()
- })
+ collapseEl.addEventListener('shown.bs.collapse', () => {
+ expect(collapseEl).toHaveClass('show')
+ expect(target.checked).toBeTrue()
+ resolve()
+ })
- target.click()
+ target.click()
+ })
})
- it('should allow accordion to contain nested elements', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="row">',
- ' <div class="col-lg-6">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>',
- ' </div>',
- ' </div>',
- ' <div class="col-lg-6">',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>',
- ' </div>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerEl = fixtureEl.querySelector('#linkTrigger')
- const triggerTwoEl = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOneEl = fixtureEl.querySelector('#collapseOne')
- const collapseTwoEl = fixtureEl.querySelector('#collapseTwo')
-
- collapseOneEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseOneEl).toHaveClass('show')
- expect(triggerEl).not.toHaveClass('collapsed')
- expect(triggerEl.getAttribute('aria-expanded')).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).not.toHaveClass('show')
- expect(triggerEl).toHaveClass('collapsed')
- expect(triggerEl.getAttribute('aria-expanded')).toEqual('false')
+ it('should allow accordion to contain nested elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="accordion">',
+ ' <div class="row">',
+ ' <div class="col-lg-6">',
+ ' <div class="item">',
+ ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
+ ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>',
+ ' </div>',
+ ' </div>',
+ ' <div class="col-lg-6">',
+ ' <div class="item">',
+ ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
+ ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const triggerEl = fixtureEl.querySelector('#linkTrigger')
+ const triggerTwoEl = fixtureEl.querySelector('#linkTriggerTwo')
+ const collapseOneEl = fixtureEl.querySelector('#collapseOne')
+ const collapseTwoEl = fixtureEl.querySelector('#collapseTwo')
+
+ collapseOneEl.addEventListener('shown.bs.collapse', () => {
+ expect(collapseOneEl).toHaveClass('show')
+ expect(triggerEl).not.toHaveClass('collapsed')
+ expect(triggerEl.getAttribute('aria-expanded')).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).not.toHaveClass('show')
+ expect(triggerEl).toHaveClass('collapsed')
+ expect(triggerEl.getAttribute('aria-expanded')).toEqual('false')
+
+ expect(collapseTwoEl).toHaveClass('show')
+ expect(triggerTwoEl).not.toHaveClass('collapsed')
+ expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- expect(collapseTwoEl).toHaveClass('show')
- expect(triggerTwoEl).not.toHaveClass('collapsed')
- expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('true')
- done()
+ triggerTwoEl.click()
})
- triggerTwoEl.click()
+ triggerEl.click()
})
-
- triggerEl.click()
})
- it('should allow accordion to target multiple elements', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <a id="linkTriggerOne" data-bs-toggle="collapse" data-bs-target=".collapseOne" href="#" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <a id="linkTriggerTwo" data-bs-toggle="collapse" data-bs-target=".collapseTwo" href="#" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseOneOne" class="collapse collapseOne" role="tabpanel" data-bs-parent="#accordion"></div>',
- ' <div id="collapseOneTwo" class="collapse collapseOne" role="tabpanel" data-bs-parent="#accordion"></div>',
- ' <div id="collapseTwoOne" class="collapse collapseTwo" role="tabpanel" data-bs-parent="#accordion"></div>',
- ' <div id="collapseTwoTwo" class="collapse collapseTwo" role="tabpanel" data-bs-parent="#accordion"></div>',
- '</div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('#linkTriggerOne')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOneOne = fixtureEl.querySelector('#collapseOneOne')
- const collapseOneTwo = fixtureEl.querySelector('#collapseOneTwo')
- const collapseTwoOne = fixtureEl.querySelector('#collapseTwoOne')
- const collapseTwoTwo = fixtureEl.querySelector('#collapseTwoTwo')
- const collapsedElements = {
- one: false,
- two: false
- }
-
- function firstTest() {
- expect(collapseOneOne).toHaveClass('show')
- expect(collapseOneTwo).toHaveClass('show')
-
- expect(collapseTwoOne).not.toHaveClass('show')
- expect(collapseTwoTwo).not.toHaveClass('show')
-
- triggerTwo.click()
- }
-
- function secondTest() {
- expect(collapseOneOne).not.toHaveClass('show')
- expect(collapseOneTwo).not.toHaveClass('show')
-
- expect(collapseTwoOne).toHaveClass('show')
- expect(collapseTwoTwo).toHaveClass('show')
- done()
- }
-
- collapseOneOne.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.one) {
- firstTest()
- } else {
- collapsedElements.one = true
+ it('should allow accordion to target multiple elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="accordion">',
+ ' <a id="linkTriggerOne" data-bs-toggle="collapse" data-bs-target=".collapseOne" href="#" aria-expanded="false" aria-controls="collapseOne"></a>',
+ ' <a id="linkTriggerTwo" data-bs-toggle="collapse" data-bs-target=".collapseTwo" href="#" aria-expanded="false" aria-controls="collapseTwo"></a>',
+ ' <div id="collapseOneOne" class="collapse collapseOne" role="tabpanel" data-bs-parent="#accordion"></div>',
+ ' <div id="collapseOneTwo" class="collapse collapseOne" role="tabpanel" data-bs-parent="#accordion"></div>',
+ ' <div id="collapseTwoOne" class="collapse collapseTwo" role="tabpanel" data-bs-parent="#accordion"></div>',
+ ' <div id="collapseTwoTwo" class="collapse collapseTwo" role="tabpanel" data-bs-parent="#accordion"></div>',
+ '</div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('#linkTriggerOne')
+ const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
+ const collapseOneOne = fixtureEl.querySelector('#collapseOneOne')
+ const collapseOneTwo = fixtureEl.querySelector('#collapseOneTwo')
+ const collapseTwoOne = fixtureEl.querySelector('#collapseTwoOne')
+ const collapseTwoTwo = fixtureEl.querySelector('#collapseTwoTwo')
+ const collapsedElements = {
+ one: false,
+ two: false
}
- })
- collapseOneTwo.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.one) {
- firstTest()
- } else {
- collapsedElements.one = true
- }
- })
+ function firstTest() {
+ expect(collapseOneOne).toHaveClass('show')
+ expect(collapseOneTwo).toHaveClass('show')
- collapseTwoOne.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.two) {
- secondTest()
- } else {
- collapsedElements.two = true
- }
- })
+ expect(collapseTwoOne).not.toHaveClass('show')
+ expect(collapseTwoTwo).not.toHaveClass('show')
- collapseTwoTwo.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.two) {
- secondTest()
- } else {
- collapsedElements.two = true
+ triggerTwo.click()
}
- })
- trigger.click()
- })
+ function secondTest() {
+ expect(collapseOneOne).not.toHaveClass('show')
+ expect(collapseOneTwo).not.toHaveClass('show')
- it('should collapse accordion children but not nested accordion children', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" data-bs-parent="#accordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">',
- ' <div id="nestedAccordion">',
- ' <div class="item">',
- ' <a id="nestedLinkTrigger" data-bs-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>',
- ' <div id="nestedCollapseOne" data-bs-parent="#nestedAccordion" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" data-bs-parent="#accordion" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>',
- ' </div>',
- '</div>'
- ].join('')
+ expect(collapseTwoOne).toHaveClass('show')
+ expect(collapseTwoTwo).toHaveClass('show')
+ resolve()
+ }
- const trigger = fixtureEl.querySelector('#linkTrigger')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const nestedTrigger = fixtureEl.querySelector('#nestedLinkTrigger')
- const collapseOne = fixtureEl.querySelector('#collapseOne')
- const collapseTwo = fixtureEl.querySelector('#collapseTwo')
- const nestedCollapseOne = fixtureEl.querySelector('#nestedCollapseOne')
-
- function handlerCollapseOne() {
- expect(collapseOne).toHaveClass('show')
- expect(collapseTwo).not.toHaveClass('show')
- expect(nestedCollapseOne).not.toHaveClass('show')
-
- nestedCollapseOne.addEventListener('shown.bs.collapse', handlerNestedCollapseOne)
- nestedTrigger.click()
- collapseOne.removeEventListener('shown.bs.collapse', handlerCollapseOne)
- }
+ collapseOneOne.addEventListener('shown.bs.collapse', () => {
+ if (collapsedElements.one) {
+ firstTest()
+ } else {
+ collapsedElements.one = true
+ }
+ })
- function handlerNestedCollapseOne() {
- expect(collapseOne).toHaveClass('show')
- expect(collapseTwo).not.toHaveClass('show')
- expect(nestedCollapseOne).toHaveClass('show')
+ collapseOneTwo.addEventListener('shown.bs.collapse', () => {
+ if (collapsedElements.one) {
+ firstTest()
+ } else {
+ collapsedElements.one = true
+ }
+ })
- collapseTwo.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne).not.toHaveClass('show')
- expect(collapseTwo).toHaveClass('show')
- expect(nestedCollapseOne).toHaveClass('show')
- done()
+ collapseTwoOne.addEventListener('shown.bs.collapse', () => {
+ if (collapsedElements.two) {
+ secondTest()
+ } else {
+ collapsedElements.two = true
+ }
})
- triggerTwo.click()
- nestedCollapseOne.removeEventListener('shown.bs.collapse', handlerNestedCollapseOne)
- }
+ collapseTwoTwo.addEventListener('shown.bs.collapse', () => {
+ if (collapsedElements.two) {
+ secondTest()
+ } else {
+ collapsedElements.two = true
+ }
+ })
- collapseOne.addEventListener('shown.bs.collapse', handlerCollapseOne)
- trigger.click()
+ trigger.click()
+ })
})
- it('should add "collapsed" class and set aria-expanded to triggers only when all the targeted collapse are hidden', done => {
- fixtureEl.innerHTML = [
- '<a id="trigger1" role="button" data-bs-toggle="collapse" href="#test1"></a>',
- '<a id="trigger2" role="button" data-bs-toggle="collapse" href="#test2"></a>',
- '<a id="trigger3" role="button" data-bs-toggle="collapse" href=".multi"></a>',
- '<div id="test1" class="multi"></div>',
- '<div id="test2" class="multi"></div>'
- ].join('')
+ it('should collapse accordion children but not nested accordion children', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="accordion">',
+ ' <div class="item">',
+ ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
+ ' <div id="collapseOne" data-bs-parent="#accordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">',
+ ' <div id="nestedAccordion">',
+ ' <div class="item">',
+ ' <a id="nestedLinkTrigger" data-bs-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>',
+ ' <div id="nestedCollapseOne" data-bs-parent="#nestedAccordion" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' <div class="item">',
+ ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
+ ' <div id="collapseTwo" data-bs-parent="#accordion" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('#linkTrigger')
+ const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
+ const nestedTrigger = fixtureEl.querySelector('#nestedLinkTrigger')
+ const collapseOne = fixtureEl.querySelector('#collapseOne')
+ const collapseTwo = fixtureEl.querySelector('#collapseTwo')
+ const nestedCollapseOne = fixtureEl.querySelector('#nestedCollapseOne')
+
+ function handlerCollapseOne() {
+ expect(collapseOne).toHaveClass('show')
+ expect(collapseTwo).not.toHaveClass('show')
+ expect(nestedCollapseOne).not.toHaveClass('show')
+
+ nestedCollapseOne.addEventListener('shown.bs.collapse', handlerNestedCollapseOne)
+ nestedTrigger.click()
+ collapseOne.removeEventListener('shown.bs.collapse', handlerCollapseOne)
+ }
- const trigger1 = fixtureEl.querySelector('#trigger1')
- const trigger2 = fixtureEl.querySelector('#trigger2')
- const trigger3 = fixtureEl.querySelector('#trigger3')
- const target1 = fixtureEl.querySelector('#test1')
- const target2 = fixtureEl.querySelector('#test2')
+ function handlerNestedCollapseOne() {
+ expect(collapseOne).toHaveClass('show')
+ expect(collapseTwo).not.toHaveClass('show')
+ expect(nestedCollapseOne).toHaveClass('show')
- const target2Shown = () => {
- expect(trigger1).not.toHaveClass('collapsed')
- expect(trigger1.getAttribute('aria-expanded')).toEqual('true')
+ collapseTwo.addEventListener('shown.bs.collapse', () => {
+ expect(collapseOne).not.toHaveClass('show')
+ expect(collapseTwo).toHaveClass('show')
+ expect(nestedCollapseOne).toHaveClass('show')
+ resolve()
+ })
- expect(trigger2).not.toHaveClass('collapsed')
- expect(trigger2.getAttribute('aria-expanded')).toEqual('true')
+ triggerTwo.click()
+ nestedCollapseOne.removeEventListener('shown.bs.collapse', handlerNestedCollapseOne)
+ }
- expect(trigger3).not.toHaveClass('collapsed')
- expect(trigger3.getAttribute('aria-expanded')).toEqual('true')
+ collapseOne.addEventListener('shown.bs.collapse', handlerCollapseOne)
+ trigger.click()
+ })
+ })
- target2.addEventListener('hidden.bs.collapse', () => {
+ it('should add "collapsed" class and set aria-expanded to triggers only when all the targeted collapse are hidden', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a id="trigger1" role="button" data-bs-toggle="collapse" href="#test1"></a>',
+ '<a id="trigger2" role="button" data-bs-toggle="collapse" href="#test2"></a>',
+ '<a id="trigger3" role="button" data-bs-toggle="collapse" href=".multi"></a>',
+ '<div id="test1" class="multi"></div>',
+ '<div id="test2" class="multi"></div>'
+ ].join('')
+
+ const trigger1 = fixtureEl.querySelector('#trigger1')
+ const trigger2 = fixtureEl.querySelector('#trigger2')
+ const trigger3 = fixtureEl.querySelector('#trigger3')
+ const target1 = fixtureEl.querySelector('#test1')
+ const target2 = fixtureEl.querySelector('#test2')
+
+ const target2Shown = () => {
expect(trigger1).not.toHaveClass('collapsed')
expect(trigger1.getAttribute('aria-expanded')).toEqual('true')
- expect(trigger2).toHaveClass('collapsed')
- expect(trigger2.getAttribute('aria-expanded')).toEqual('false')
+ expect(trigger2).not.toHaveClass('collapsed')
+ expect(trigger2.getAttribute('aria-expanded')).toEqual('true')
expect(trigger3).not.toHaveClass('collapsed')
expect(trigger3.getAttribute('aria-expanded')).toEqual('true')
- target1.addEventListener('hidden.bs.collapse', () => {
- expect(trigger1).toHaveClass('collapsed')
- expect(trigger1.getAttribute('aria-expanded')).toEqual('false')
+ target2.addEventListener('hidden.bs.collapse', () => {
+ expect(trigger1).not.toHaveClass('collapsed')
+ expect(trigger1.getAttribute('aria-expanded')).toEqual('true')
expect(trigger2).toHaveClass('collapsed')
expect(trigger2.getAttribute('aria-expanded')).toEqual('false')
- expect(trigger3).toHaveClass('collapsed')
- expect(trigger3.getAttribute('aria-expanded')).toEqual('false')
- done()
- })
+ expect(trigger3).not.toHaveClass('collapsed')
+ expect(trigger3.getAttribute('aria-expanded')).toEqual('true')
- trigger1.click()
- })
+ target1.addEventListener('hidden.bs.collapse', () => {
+ expect(trigger1).toHaveClass('collapsed')
+ expect(trigger1.getAttribute('aria-expanded')).toEqual('false')
- trigger2.click()
- }
+ expect(trigger2).toHaveClass('collapsed')
+ expect(trigger2.getAttribute('aria-expanded')).toEqual('false')
+
+ expect(trigger3).toHaveClass('collapsed')
+ expect(trigger3.getAttribute('aria-expanded')).toEqual('false')
+ resolve()
+ })
+
+ trigger1.click()
+ })
- target2.addEventListener('shown.bs.collapse', target2Shown)
- trigger3.click()
+ trigger2.click()
+ }
+
+ target2.addEventListener('shown.bs.collapse', target2Shown)
+ trigger3.click()
+ })
})
})
diff --git a/js/tests/unit/dom/event-handler.spec.js b/js/tests/unit/dom/event-handler.spec.js
index 601af7409e..e5887ce708 100644
--- a/js/tests/unit/dom/event-handler.spec.js
+++ b/js/tests/unit/dom/event-handler.spec.js
@@ -1,5 +1,6 @@
import EventHandler from '../../../src/dom/event-handler'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import { clearFixture, getFixture } from '../../helpers/fixture'
+import { noop } from '../../../src/util'
describe('EventHandler', () => {
let fixtureEl
@@ -18,176 +19,190 @@ describe('EventHandler', () => {
const div = fixtureEl.querySelector('div')
- EventHandler.on(div, null, () => {})
- EventHandler.on(null, 'click', () => {})
+ EventHandler.on(div, null, noop)
+ EventHandler.on(null, 'click', noop)
expect().nothing()
})
- it('should add event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should add event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ const div = fixtureEl.querySelector('div')
- EventHandler.on(div, 'click', () => {
- expect().nothing()
- done()
- })
+ EventHandler.on(div, 'click', () => {
+ expect().nothing()
+ resolve()
+ })
- div.click()
+ div.click()
+ })
})
- it('should add namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should add namespaced event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ const div = fixtureEl.querySelector('div')
- EventHandler.on(div, 'bs.namespace', () => {
- expect().nothing()
- done()
- })
+ EventHandler.on(div, 'bs.namespace', () => {
+ expect().nothing()
+ resolve()
+ })
- EventHandler.trigger(div, 'bs.namespace')
+ EventHandler.trigger(div, 'bs.namespace')
+ })
})
- it('should add native namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
+ it('should add native namespaced event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- EventHandler.on(div, 'click.namespace', () => {
- expect().nothing()
- done()
- })
+ const div = fixtureEl.querySelector('div')
- EventHandler.trigger(div, 'click')
- })
+ EventHandler.on(div, 'click.namespace', () => {
+ expect().nothing()
+ resolve()
+ })
- it('should handle event delegation', done => {
- EventHandler.on(document, 'click', '.test', () => {
- expect().nothing()
- done()
+ EventHandler.trigger(div, 'click')
})
+ })
- fixtureEl.innerHTML = '<div class="test"></div>'
+ it('should handle event delegation', () => {
+ return new Promise(resolve => {
+ EventHandler.on(document, 'click', '.test', () => {
+ expect().nothing()
+ resolve()
+ })
- const div = fixtureEl.querySelector('div')
+ fixtureEl.innerHTML = '<div class="test"></div>'
- div.click()
- })
+ const div = fixtureEl.querySelector('div')
- it('should handle mouseenter/mouseleave like the native counterpart', done => {
- fixtureEl.innerHTML = [
- '<div class="outer">',
- '<div class="inner">',
- '<div class="nested">',
- '<div class="deep"></div>',
- '</div>',
- '</div>',
- '<div class="sibling"></div>',
- '</div>'
- ].join('')
-
- const outer = fixtureEl.querySelector('.outer')
- const inner = fixtureEl.querySelector('.inner')
- const nested = fixtureEl.querySelector('.nested')
- const deep = fixtureEl.querySelector('.deep')
- const sibling = fixtureEl.querySelector('.sibling')
-
- const enterSpy = jasmine.createSpy('mouseenter')
- const leaveSpy = jasmine.createSpy('mouseleave')
- const delegateEnterSpy = jasmine.createSpy('mouseenter')
- const delegateLeaveSpy = jasmine.createSpy('mouseleave')
-
- EventHandler.on(inner, 'mouseenter', enterSpy)
- EventHandler.on(inner, 'mouseleave', leaveSpy)
- EventHandler.on(outer, 'mouseenter', '.inner', delegateEnterSpy)
- EventHandler.on(outer, 'mouseleave', '.inner', delegateLeaveSpy)
-
- EventHandler.on(sibling, 'mouseenter', () => {
- 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()
+ div.click()
})
+ })
- const moveMouse = (from, to) => {
- from.dispatchEvent(new MouseEvent('mouseout', {
- bubbles: true,
- relatedTarget: to
- }))
-
- to.dispatchEvent(new MouseEvent('mouseover', {
- bubbles: true,
- relatedTarget: from
- }))
- }
+ it('should handle mouseenter/mouseleave like the native counterpart', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="outer">',
+ '<div class="inner">',
+ '<div class="nested">',
+ '<div class="deep"></div>',
+ '</div>',
+ '</div>',
+ '<div class="sibling"></div>',
+ '</div>'
+ ].join('')
+
+ const outer = fixtureEl.querySelector('.outer')
+ const inner = fixtureEl.querySelector('.inner')
+ const nested = fixtureEl.querySelector('.nested')
+ const deep = fixtureEl.querySelector('.deep')
+ const sibling = fixtureEl.querySelector('.sibling')
+
+ const enterSpy = jasmine.createSpy('mouseenter')
+ const leaveSpy = jasmine.createSpy('mouseleave')
+ const delegateEnterSpy = jasmine.createSpy('mouseenter')
+ const delegateLeaveSpy = jasmine.createSpy('mouseleave')
+
+ EventHandler.on(inner, 'mouseenter', enterSpy)
+ EventHandler.on(inner, 'mouseleave', leaveSpy)
+ EventHandler.on(outer, 'mouseenter', '.inner', delegateEnterSpy)
+ EventHandler.on(outer, 'mouseleave', '.inner', delegateLeaveSpy)
+
+ EventHandler.on(sibling, 'mouseenter', () => {
+ expect(enterSpy.calls.count()).toEqual(2)
+ expect(leaveSpy.calls.count()).toEqual(2)
+ expect(delegateEnterSpy.calls.count()).toEqual(2)
+ expect(delegateLeaveSpy.calls.count()).toEqual(2)
+ resolve()
+ })
+
+ const moveMouse = (from, to) => {
+ from.dispatchEvent(new MouseEvent('mouseout', {
+ bubbles: true,
+ relatedTarget: to
+ }))
+
+ to.dispatchEvent(new MouseEvent('mouseover', {
+ bubbles: true,
+ relatedTarget: from
+ }))
+ }
- // from outer to deep and back to outer (nested)
- moveMouse(outer, inner)
- moveMouse(inner, nested)
- moveMouse(nested, deep)
- moveMouse(deep, nested)
- moveMouse(nested, inner)
- moveMouse(inner, outer)
-
- setTimeout(() => {
- 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)
+ // from outer to deep and back to outer (nested)
moveMouse(outer, inner)
- moveMouse(inner, sibling)
- }, 20)
+ moveMouse(inner, nested)
+ moveMouse(nested, deep)
+ moveMouse(deep, nested)
+ moveMouse(nested, inner)
+ moveMouse(inner, outer)
+
+ setTimeout(() => {
+ 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)
+ moveMouse(inner, sibling)
+ }, 20)
+ })
})
})
describe('one', () => {
- it('should call listener just once', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- let called = 0
- const div = fixtureEl.querySelector('div')
- const obj = {
- oneListener() {
- called++
+ it('should call listener just once', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ let called = 0
+ const div = fixtureEl.querySelector('div')
+ const obj = {
+ oneListener() {
+ called++
+ }
}
- }
- EventHandler.one(div, 'bootstrap', obj.oneListener)
+ EventHandler.one(div, 'bootstrap', obj.oneListener)
- EventHandler.trigger(div, 'bootstrap')
- EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should call delegated listener just once', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should call delegated listener just once', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- let called = 0
- const div = fixtureEl.querySelector('div')
- const obj = {
- oneListener() {
- called++
+ let called = 0
+ const div = fixtureEl.querySelector('div')
+ const obj = {
+ oneListener() {
+ called++
+ }
}
- }
- EventHandler.one(fixtureEl, 'bootstrap', 'div', obj.oneListener)
+ EventHandler.one(fixtureEl, 'bootstrap', 'div', obj.oneListener)
- EventHandler.trigger(div, 'bootstrap')
- EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
})
@@ -196,171 +211,185 @@ describe('EventHandler', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
- EventHandler.off(div, null, () => {})
- EventHandler.off(null, 'click', () => {})
+ EventHandler.off(div, null, noop)
+ EventHandler.off(null, 'click', noop)
expect().nothing()
})
- it('should remove a listener', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove a listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
- const handler = () => {
- called++
- }
+ let called = 0
+ const handler = () => {
+ called++
+ }
- EventHandler.on(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
+ EventHandler.on(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
- EventHandler.off(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
+ EventHandler.off(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should remove all the events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove all the events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.trigger(div, 'foobar')
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.trigger(div, 'foobar')
- EventHandler.off(div, 'foobar')
- EventHandler.trigger(div, 'foobar')
+ EventHandler.off(div, 'foobar')
+ EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ resolve()
+ }, 20)
+ })
})
- it('should remove all the namespaced listeners if namespace is passed', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove all the namespaced listeners if namespace is passed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'foobar.namespace', () => {
- called++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- called++
+ EventHandler.on(div, 'foobar.namespace', () => {
+ called++
+ })
+ EventHandler.on(div, 'foofoo.namespace', () => {
+ called++
+ })
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
+
+ EventHandler.off(div, '.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
+
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ resolve()
+ }, 20)
})
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
-
- EventHandler.off(div, '.namespace')
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
-
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
})
- it('should remove the namespaced listeners', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove the namespaced listeners', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let calledCallback1 = 0
- let calledCallback2 = 0
+ let calledCallback1 = 0
+ let calledCallback2 = 0
- EventHandler.on(div, 'foobar.namespace', () => {
- calledCallback1++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- calledCallback2++
- })
+ EventHandler.on(div, 'foobar.namespace', () => {
+ calledCallback1++
+ })
+ EventHandler.on(div, 'foofoo.namespace', () => {
+ calledCallback2++
+ })
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.off(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.off(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
- setTimeout(() => {
- expect(calledCallback1).toEqual(1)
- expect(calledCallback2).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(calledCallback1).toEqual(1)
+ expect(calledCallback2).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should remove the all the namespaced listeners for native events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove the all the namespaced listeners for native events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'click.namespace', () => {
- called++
- })
- EventHandler.on(div, 'click.namespace2', () => {
- called++
- })
+ EventHandler.on(div, 'click.namespace', () => {
+ called++
+ })
+ EventHandler.on(div, 'click.namespace2', () => {
+ called++
+ })
- EventHandler.trigger(div, 'click')
- EventHandler.off(div, 'click')
- EventHandler.trigger(div, 'click')
+ EventHandler.trigger(div, 'click')
+ EventHandler.off(div, 'click')
+ EventHandler.trigger(div, 'click')
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ resolve()
+ }, 20)
+ })
})
- it('should remove the specified namespaced listeners for native events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called1 = 0
- let called2 = 0
-
- EventHandler.on(div, 'click.namespace', () => {
- called1++
+ it('should remove the specified namespaced listeners for native events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called1 = 0
+ let called2 = 0
+
+ EventHandler.on(div, 'click.namespace', () => {
+ called1++
+ })
+ EventHandler.on(div, 'click.namespace2', () => {
+ called2++
+ })
+ EventHandler.trigger(div, 'click')
+
+ EventHandler.off(div, 'click.namespace')
+ EventHandler.trigger(div, 'click')
+
+ setTimeout(() => {
+ expect(called1).toEqual(1)
+ expect(called2).toEqual(2)
+ resolve()
+ }, 20)
})
- EventHandler.on(div, 'click.namespace2', () => {
- called2++
- })
- EventHandler.trigger(div, 'click')
-
- EventHandler.off(div, 'click.namespace')
- EventHandler.trigger(div, 'click')
-
- setTimeout(() => {
- expect(called1).toEqual(1)
- expect(called2).toEqual(2)
- done()
- }, 20)
})
- it('should remove a listener registered by .one', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should remove a listener registered by .one', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
- const handler = () => {
- throw new Error('called')
- }
+ const div = fixtureEl.querySelector('div')
+ const handler = () => {
+ throw new Error('called')
+ }
- EventHandler.one(div, 'foobar', handler)
- EventHandler.off(div, 'foobar', handler)
+ EventHandler.one(div, 'foobar', handler)
+ EventHandler.off(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect().nothing()
- done()
- }, 20)
+ EventHandler.trigger(div, 'foobar')
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 20)
+ })
})
it('should remove the correct delegated event listener', () => {
diff --git a/js/tests/unit/dom/manipulator.spec.js b/js/tests/unit/dom/manipulator.spec.js
index 963ee5989f..95af902ff5 100644
--- a/js/tests/unit/dom/manipulator.spec.js
+++ b/js/tests/unit/dom/manipulator.spec.js
@@ -1,5 +1,5 @@
import Manipulator from '../../../src/dom/manipulator'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import { clearFixture, getFixture } from '../../helpers/fixture'
describe('Manipulator', () => {
let fixtureEl
@@ -134,42 +134,44 @@ describe('Manipulator', () => {
})
})
- it('should not change offset when viewport is scrolled', done => {
- const top = 500
- const left = 1000
- const scrollY = 200
- const scrollX = 400
+ it('should not change offset when viewport is scrolled', () => {
+ return new Promise(resolve => {
+ const top = 500
+ const left = 1000
+ const scrollY = 200
+ const scrollX = 400
- fixtureEl.innerHTML = `<div style="position:absolute;top:${top}px;left:${left}px"></div>`
+ fixtureEl.innerHTML = `<div style="position:absolute;top:${top}px;left:${left}px"></div>`
- const div = fixtureEl.querySelector('div')
- const offset = Manipulator.offset(div)
+ const div = fixtureEl.querySelector('div')
+ const offset = Manipulator.offset(div)
- // append an element that forces scrollbars on the window so we can scroll
- const { defaultView: win, body } = fixtureEl.ownerDocument
- const forceScrollBars = document.createElement('div')
- forceScrollBars.style.cssText = 'position:absolute;top:5000px;left:5000px;width:1px;height:1px'
- body.append(forceScrollBars)
+ // append an element that forces scrollbars on the window so we can scroll
+ const { defaultView: win, body } = fixtureEl.ownerDocument
+ const forceScrollBars = document.createElement('div')
+ forceScrollBars.style.cssText = 'position:absolute;top:5000px;left:5000px;width:1px;height:1px'
+ body.append(forceScrollBars)
- const scrollHandler = () => {
- expect(window.pageYOffset).toEqual(scrollY)
- expect(window.pageXOffset).toEqual(scrollX)
+ const scrollHandler = () => {
+ expect(window.pageYOffset).toEqual(scrollY)
+ expect(window.pageXOffset).toEqual(scrollX)
- const newOffset = Manipulator.offset(div)
+ const newOffset = Manipulator.offset(div)
- expect(newOffset).toEqual({
- top: offset.top,
- left: offset.left
- })
+ expect(newOffset).toEqual({
+ top: offset.top,
+ left: offset.left
+ })
- win.removeEventListener('scroll', scrollHandler)
- forceScrollBars.remove()
- win.scrollTo(0, 0)
- done()
- }
+ win.removeEventListener('scroll', scrollHandler)
+ forceScrollBars.remove()
+ win.scrollTo(0, 0)
+ resolve()
+ }
- win.addEventListener('scroll', scrollHandler)
- win.scrollTo(scrollX, scrollY)
+ win.addEventListener('scroll', scrollHandler)
+ win.scrollTo(scrollX, scrollY)
+ })
})
})
diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js
index 6ee58fe71a..f24b59ed5c 100644
--- a/js/tests/unit/dropdown.spec.js
+++ b/js/tests/unit/dropdown.spec.js
@@ -57,36 +57,38 @@ describe('Dropdown', () => {
expect(dropdownByElement._element).toEqual(btnDropdown)
})
- it('should create offset modifier correctly when offset option is a function', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const getOffset = jasmine.createSpy('getOffset').and.returnValue([10, 20])
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- offset: getOffset,
- popperConfig: {
- onFirstUpdate: state => {
- expect(getOffset).toHaveBeenCalledWith({
- popper: state.rects.popper,
- reference: state.rects.reference,
- placement: state.placement
- }, btnDropdown)
- done()
+ it('should create offset modifier correctly when offset option is a function', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const getOffset = jasmine.createSpy('getOffset').and.returnValue([10, 20])
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown, {
+ offset: getOffset,
+ popperConfig: {
+ onFirstUpdate: state => {
+ expect(getOffset).toHaveBeenCalledWith({
+ popper: state.rects.popper,
+ reference: state.rects.reference,
+ placement: state.placement
+ }, btnDropdown)
+ resolve()
+ }
}
- }
- })
- const offset = dropdown._getOffset()
+ })
+ const offset = dropdown._getOffset()
- expect(typeof offset).toEqual('function')
+ expect(typeof offset).toEqual('function')
- dropdown.show()
+ dropdown.show()
+ })
})
it('should create offset modifier correctly when offset option is a string into data attribute', () => {
@@ -151,761 +153,817 @@ describe('Dropdown', () => {
})
describe('toggle', () => {
- it('should toggle a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ it('should toggle a dropdown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
+
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
+ dropdown.toggle()
})
-
- dropdown.toggle()
})
- it('should destroy old popper references on toggle', done => {
- fixtureEl.innerHTML = [
- '<div class="first dropdown">',
- ' <button class="firstBtn btn" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>',
- '<div class="second dropdown">',
- ' <button class="secondBtn btn" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should destroy old popper references on toggle', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="first dropdown">',
+ ' <button class="firstBtn btn" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>',
+ '<div class="second dropdown">',
+ ' <button class="secondBtn btn" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown1 = fixtureEl.querySelector('.firstBtn')
+ const btnDropdown2 = fixtureEl.querySelector('.secondBtn')
+ const firstDropdownEl = fixtureEl.querySelector('.first')
+ const secondDropdownEl = fixtureEl.querySelector('.second')
+ const dropdown1 = new Dropdown(btnDropdown1)
+
+ firstDropdownEl.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown1).toHaveClass('show')
+ spyOn(dropdown1._popper, 'destroy')
+ btnDropdown2.click()
+ })
- const btnDropdown1 = fixtureEl.querySelector('.firstBtn')
- const btnDropdown2 = fixtureEl.querySelector('.secondBtn')
- const firstDropdownEl = fixtureEl.querySelector('.first')
- const secondDropdownEl = fixtureEl.querySelector('.second')
- const dropdown1 = new Dropdown(btnDropdown1)
+ secondDropdownEl.addEventListener('shown.bs.dropdown', () => setTimeout(() => {
+ expect(dropdown1._popper.destroy).toHaveBeenCalled()
+ resolve()
+ }))
- firstDropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown1).toHaveClass('show')
- spyOn(dropdown1._popper, 'destroy')
- btnDropdown2.click()
+ dropdown1.toggle()
})
-
- secondDropdownEl.addEventListener('shown.bs.dropdown', () => setTimeout(() => {
- expect(dropdown1._popper.destroy).toHaveBeenCalled()
- done()
- }))
-
- dropdown1.toggle()
})
- it('should toggle a dropdown and add/remove event listener on mobile', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropdown and add/remove event listener on mobile', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const defaultValueOnTouchStart = document.documentElement.ontouchstart
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const defaultValueOnTouchStart = document.documentElement.ontouchstart
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- document.documentElement.ontouchstart = noop
- spyOn(EventHandler, 'on')
- spyOn(EventHandler, 'off')
+ document.documentElement.ontouchstart = noop
+ spyOn(EventHandler, 'on')
+ spyOn(EventHandler, 'off')
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- expect(EventHandler.on).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop)
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ expect(EventHandler.on).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop)
- dropdown.toggle()
- })
+ dropdown.toggle()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(btnDropdown).not.toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- expect(EventHandler.off).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop)
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(btnDropdown).not.toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
+ expect(EventHandler.off).toHaveBeenCalledWith(jasmine.any(Object), 'mouseover', noop)
- document.documentElement.ontouchstart = defaultValueOnTouchStart
- done()
- })
+ document.documentElement.ontouchstart = defaultValueOnTouchStart
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropdown at the right', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu dropdown-menu-end">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropdown at the right', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu dropdown-menu-end">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropup', done => {
- fixtureEl.innerHTML = [
- '<div class="dropup">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropup', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropup">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropupEl = fixtureEl.querySelector('.dropup')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropupEl = fixtureEl.querySelector('.dropup')
+ const dropdown = new Dropdown(btnDropdown)
- dropupEl.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ dropupEl.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropup at the right', done => {
- fixtureEl.innerHTML = [
- '<div class="dropup">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu dropdown-menu-end">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropup at the right', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropup">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu dropdown-menu-end">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropupEl = fixtureEl.querySelector('.dropup')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropupEl = fixtureEl.querySelector('.dropup')
+ const dropdown = new Dropdown(btnDropdown)
- dropupEl.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ dropupEl.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropend', done => {
- fixtureEl.innerHTML = [
- '<div class="dropend">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropend', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropend">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropendEl = fixtureEl.querySelector('.dropend')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropendEl = fixtureEl.querySelector('.dropend')
+ const dropdown = new Dropdown(btnDropdown)
- dropendEl.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ dropendEl.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropstart', done => {
- fixtureEl.innerHTML = [
- '<div class="dropstart">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropstart', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropstart">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropstartEl = fixtureEl.querySelector('.dropstart')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropstartEl = fixtureEl.querySelector('.dropstart')
+ const dropdown = new Dropdown(btnDropdown)
- dropstartEl.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ dropstartEl.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropdown with parent reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropdown with parent reference', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- reference: 'parent'
- })
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown, {
+ reference: 'parent'
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropdown with a dom node reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropdown with a dom node reference', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- reference: fixtureEl
- })
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown, {
+ reference: fixtureEl
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropdown with a jquery object reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should toggle a dropdown with a jquery object reference', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- reference: { 0: fixtureEl, jquery: 'jQuery' }
- })
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown, {
+ reference: { 0: fixtureEl, jquery: 'jQuery' }
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ })
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should toggle a dropdown with a valid virtual element reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle visually-hidden" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const virtualElement = {
- nodeType: 1,
- getBoundingClientRect() {
- return {
- width: 0,
- height: 0,
- top: 0,
- right: 0,
- bottom: 0,
- left: 0
+ it('should toggle a dropdown with a valid virtual element reference', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle visually-hidden" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const virtualElement = {
+ nodeType: 1,
+ getBoundingClientRect() {
+ return {
+ width: 0,
+ height: 0,
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ }
}
}
- }
- expect(() => new Dropdown(btnDropdown, {
- reference: {}
- })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.')
+ expect(() => new Dropdown(btnDropdown, {
+ reference: {}
+ })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.')
- expect(() => new Dropdown(btnDropdown, {
- reference: {
- getBoundingClientRect: 'not-a-function'
- }
- })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.')
-
- // use onFirstUpdate as Poppers internal update is executed async
- const dropdown = new Dropdown(btnDropdown, {
- reference: virtualElement,
- popperConfig: {
- onFirstUpdate() {
- expect(virtualElement.getBoundingClientRect).toHaveBeenCalled()
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
+ expect(() => new Dropdown(btnDropdown, {
+ reference: {
+ getBoundingClientRect: 'not-a-function'
}
- }
- })
+ })).toThrowError(TypeError, 'DROPDOWN: Option "reference" provided type "object" without a required "getBoundingClientRect" method.')
+
+ // use onFirstUpdate as Poppers internal update is executed async
+ const dropdown = new Dropdown(btnDropdown, {
+ reference: virtualElement,
+ popperConfig: {
+ onFirstUpdate() {
+ expect(virtualElement.getBoundingClientRect).toHaveBeenCalled()
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ }
+ }
+ })
- spyOn(virtualElement, 'getBoundingClientRect').and.callThrough()
+ spyOn(virtualElement, 'getBoundingClientRect').and.callThrough()
- dropdown.toggle()
+ dropdown.toggle()
+ })
})
- it('should not toggle a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not toggle a dropdown if the element is disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.toggle()
+ dropdown.toggle()
- setTimeout(() => {
- expect().nothing()
- done()
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ })
})
})
- it('should not toggle a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not toggle a dropdown if the element contains .disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.toggle()
+ dropdown.toggle()
- setTimeout(() => {
- expect().nothing()
- done()
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ })
})
})
- it('should not toggle a dropdown if the menu is shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not toggle a dropdown if the menu is shown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.toggle()
+ dropdown.toggle()
- setTimeout(() => {
- expect().nothing()
- done()
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ })
})
})
- it('should not toggle a dropdown if show event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not toggle a dropdown if show event is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('show.bs.dropdown', event => {
- event.preventDefault()
- })
+ btnDropdown.addEventListener('show.bs.dropdown', event => {
+ event.preventDefault()
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.toggle()
+ dropdown.toggle()
- setTimeout(() => {
- expect().nothing()
- done()
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ })
})
})
})
describe('show', () => {
- it('should show a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ it('should show a dropdown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
+
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
+ resolve()
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
- done()
+ dropdown.show()
})
-
- dropdown.show()
})
- it('should not show a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not show a dropdown if the element is disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.show()
+ dropdown.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ })
})
- it('should not show a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not show a dropdown if the element contains .disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.show()
+ dropdown.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ })
})
- it('should not show a dropdown if the menu is shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not show a dropdown if the menu is shown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.show()
+ dropdown.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ })
})
- it('should not show a dropdown if show event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not show a dropdown if show event is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('show.bs.dropdown', event => {
- event.preventDefault()
- })
+ btnDropdown.addEventListener('show.bs.dropdown', event => {
+ event.preventDefault()
+ })
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ throw new Error('should not throw shown.bs.dropdown event')
+ })
- dropdown.show()
+ dropdown.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ })
})
})
describe('hide', () => {
- it('should hide a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="true">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ it('should hide a dropdown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="true">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
+
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(dropdownMenu).not.toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
+ resolve()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownMenu).not.toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- done()
+ dropdown.hide()
})
-
- dropdown.hide()
})
- it('should hide a dropdown and destroy popper', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should hide a dropdown and destroy popper', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- spyOn(dropdown._popper, 'destroy')
- dropdown.hide()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ spyOn(dropdown._popper, 'destroy')
+ dropdown.hide()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdown._popper.destroy).toHaveBeenCalled()
- done()
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(dropdown._popper.destroy).toHaveBeenCalled()
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
- it('should not hide a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not hide a dropdown if the element is disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ throw new Error('should not throw hidden.bs.dropdown event')
+ })
- dropdown.hide()
+ dropdown.hide()
- setTimeout(() => {
- expect(dropdownMenu).toHaveClass('show')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(dropdownMenu).toHaveClass('show')
+ resolve()
+ }, 10)
+ })
})
- it('should not hide a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not hide a dropdown if the element contains .disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle disabled" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ throw new Error('should not throw hidden.bs.dropdown event')
+ })
- dropdown.hide()
+ dropdown.hide()
- setTimeout(() => {
- expect(dropdownMenu).toHaveClass('show')
- done()
- }, 10)
+ setTimeout(() => {
+ expect(dropdownMenu).toHaveClass('show')
+ resolve()
+ }, 10)
+ })
})
- it('should not hide a dropdown if the menu is not shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not hide a dropdown if the menu is not shown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ throw new Error('should not throw hidden.bs.dropdown event')
+ })
- dropdown.hide()
+ dropdown.hide()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 10)
+ })
})
- it('should not hide a dropdown if hide event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not hide a dropdown if hide event is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu show">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('hide.bs.dropdown', event => {
- event.preventDefault()
- })
+ btnDropdown.addEventListener('hide.bs.dropdown', event => {
+ event.preventDefault()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ throw new Error('should not throw hidden.bs.dropdown event')
+ })
- dropdown.hide()
+ dropdown.hide()
- setTimeout(() => {
- expect(dropdownMenu).toHaveClass('show')
- done()
+ setTimeout(() => {
+ expect(dropdownMenu).toHaveClass('show')
+ resolve()
+ })
})
})
- it('should remove event listener on touch-enabled device that was added in show method', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Dropdwon item</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should remove event listener on touch-enabled device that was added in show method', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Dropdwon item</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const defaultValueOnTouchStart = document.documentElement.ontouchstart
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
+ const defaultValueOnTouchStart = document.documentElement.ontouchstart
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdown = new Dropdown(btnDropdown)
- document.documentElement.ontouchstart = noop
- spyOn(EventHandler, 'off')
+ document.documentElement.ontouchstart = noop
+ spyOn(EventHandler, 'off')
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- dropdown.hide()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ dropdown.hide()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(btnDropdown).not.toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- expect(EventHandler.off).toHaveBeenCalled()
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(btnDropdown).not.toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
+ expect(EventHandler.off).toHaveBeenCalled()
- document.documentElement.ontouchstart = defaultValueOnTouchStart
- done()
- })
+ document.documentElement.ontouchstart = defaultValueOnTouchStart
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
})
@@ -1013,903 +1071,957 @@ describe('Dropdown', () => {
})
describe('data-api', () => {
- it('should show and hide a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- let showEventTriggered = false
- let hideEventTriggered = false
+ it('should show and hide a dropdown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ let showEventTriggered = false
+ let hideEventTriggered = false
+
+ btnDropdown.addEventListener('show.bs.dropdown', () => {
+ showEventTriggered = true
+ })
- btnDropdown.addEventListener('show.bs.dropdown', () => {
- showEventTriggered = true
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', event => setTimeout(() => {
+ expect(btnDropdown).toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
+ expect(showEventTriggered).toBeTrue()
+ expect(event.relatedTarget).toEqual(btnDropdown)
+ document.body.click()
+ }))
- btnDropdown.addEventListener('shown.bs.dropdown', event => setTimeout(() => {
- expect(btnDropdown).toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- expect(showEventTriggered).toBeTrue()
- expect(event.relatedTarget).toEqual(btnDropdown)
- document.body.click()
- }))
+ btnDropdown.addEventListener('hide.bs.dropdown', () => {
+ hideEventTriggered = true
+ })
- btnDropdown.addEventListener('hide.bs.dropdown', () => {
- hideEventTriggered = true
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', event => {
+ expect(btnDropdown).not.toHaveClass('show')
+ expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
+ expect(hideEventTriggered).toBeTrue()
+ expect(event.relatedTarget).toEqual(btnDropdown)
+ resolve()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', event => {
- expect(btnDropdown).not.toHaveClass('show')
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- expect(hideEventTriggered).toBeTrue()
- expect(event.relatedTarget).toEqual(btnDropdown)
- done()
+ btnDropdown.click()
})
-
- btnDropdown.click()
})
- it('should not use "static" Popper in navbar', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar navbar-expand-md navbar-light bg-light">',
- ' <div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- ' </div>',
- '</nav>'
- ].join('')
+ it('should not use "static" Popper in navbar', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<nav class="navbar navbar-expand-md navbar-light bg-light">',
+ ' <div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ ' </div>',
+ '</nav>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(dropdown._popper).not.toBeNull()
- expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(dropdown._popper).not.toBeNull()
+ expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
- it('should not collapse the dropdown when clicking a select option nested in the dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <select>',
- ' <option selected>Open this select menu</option>',
- ' <option value="1">One</option>',
- ' </select>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not collapse the dropdown when clicking a select option nested in the dropdown', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <select>',
+ ' <option selected>Open this select menu</option>',
+ ' <option value="1">One</option>',
+ ' </select>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- const hideSpy = spyOn(dropdown, '_completeHide')
+ const hideSpy = spyOn(dropdown, '_completeHide')
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- const clickEvent = new MouseEvent('click', {
- bubbles: true
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ const clickEvent = new MouseEvent('click', {
+ bubbles: true
+ })
+
+ dropdownMenu.querySelector('option').dispatchEvent(clickEvent)
})
- dropdownMenu.querySelector('option').dispatchEvent(clickEvent)
- })
+ dropdownMenu.addEventListener('click', event => {
+ expect(event.target.tagName).toMatch(/select|option/i)
- dropdownMenu.addEventListener('click', event => {
- expect(event.target.tagName).toMatch(/select|option/i)
+ Dropdown.clearMenus(event)
- Dropdown.clearMenus(event)
+ setTimeout(() => {
+ expect(hideSpy).not.toHaveBeenCalled()
+ resolve()
+ }, 10)
+ })
- setTimeout(() => {
- expect(hideSpy).not.toHaveBeenCalled()
- done()
- }, 10)
+ dropdown.show()
})
-
- dropdown.show()
})
- it('should manage bs attribute `data-bs-popper`="static" when dropdown is in navbar', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar navbar-expand-md navbar-light bg-light">',
- ' <div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- ' </div>',
- '</nav>'
- ].join('')
+ it('should manage bs attribute `data-bs-popper`="static" when dropdown is in navbar', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<nav class="navbar navbar-expand-md navbar-light bg-light">',
+ ' <div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ ' </div>',
+ '</nav>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
- dropdown.hide()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+ dropdown.hide()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownMenu.getAttribute('data-bs-popper')).toBeNull()
- done()
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(dropdownMenu.getAttribute('data-bs-popper')).toBeNull()
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
- it('should not use Popper if display set to static', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not use Popper if display set to static', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- // Popper adds this attribute when we use it
- expect(dropdownMenu.getAttribute('data-popper-placement')).toBeNull()
- done()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ // Popper adds this attribute when we use it
+ expect(dropdownMenu.getAttribute('data-popper-placement')).toBeNull()
+ resolve()
+ })
- btnDropdown.click()
+ btnDropdown.click()
+ })
})
- it('should manage bs attribute `data-bs-popper`="static" when display set to static', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should manage bs attribute `data-bs-popper`="static" when display set to static', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
+ const dropdown = new Dropdown(btnDropdown)
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
- dropdown.hide()
- })
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(dropdownMenu.getAttribute('data-bs-popper')).toEqual('static')
+ dropdown.hide()
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownMenu.getAttribute('data-bs-popper')).toBeNull()
- done()
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(dropdownMenu.getAttribute('data-bs-popper')).toBeNull()
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
- it('should remove "show" class if tabbing outside of menu', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should remove "show" class if tabbing outside of menu', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- btnDropdown.addEventListener('shown.bs.dropdown', () => {
- expect(btnDropdown).toHaveClass('show')
+ btnDropdown.addEventListener('shown.bs.dropdown', () => {
+ expect(btnDropdown).toHaveClass('show')
- const keyup = createEvent('keyup')
+ const keyup = createEvent('keyup')
- keyup.key = 'Tab'
- document.dispatchEvent(keyup)
- })
+ keyup.key = 'Tab'
+ document.dispatchEvent(keyup)
+ })
- btnDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect(btnDropdown).not.toHaveClass('show')
- done()
- })
+ btnDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect(btnDropdown).not.toHaveClass('show')
+ resolve()
+ })
- btnDropdown.click()
+ btnDropdown.click()
+ })
})
- it('should remove "show" class if body is clicked, with multiple dropdowns', done => {
- fixtureEl.innerHTML = [
- '<div class="nav">',
- ' <div class="dropdown" id="testmenu">',
- ' <a class="dropdown-toggle" data-bs-toggle="dropdown" href="#testmenu">Test menu</a>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- ' </div>',
- '</div>',
- '<div class="btn-group">',
- ' <button class="btn">Actions</button>',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"></button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Action 1</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should remove "show" class if body is clicked, with multiple dropdowns', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="nav">',
+ ' <div class="dropdown" id="testmenu">',
+ ' <a class="dropdown-toggle" data-bs-toggle="dropdown" href="#testmenu">Test menu</a>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
+ ' </div>',
+ ' </div>',
+ '</div>',
+ '<div class="btn-group">',
+ ' <button class="btn">Actions</button>',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"></button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Action 1</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]')
+ const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]')
- expect(triggerDropdownList).toHaveSize(2)
+ expect(triggerDropdownList).toHaveSize(2)
- const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList
+ const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList
- triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => {
- expect(triggerDropdownFirst).toHaveClass('show')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
- document.body.click()
- })
+ triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => {
+ 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')).toHaveSize(0)
- triggerDropdownLast.click()
- })
+ triggerDropdownFirst.addEventListener('hidden.bs.dropdown', () => {
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
+ triggerDropdownLast.click()
+ })
- triggerDropdownLast.addEventListener('shown.bs.dropdown', () => {
- expect(triggerDropdownLast).toHaveClass('show')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
- document.body.click()
- })
+ triggerDropdownLast.addEventListener('shown.bs.dropdown', () => {
+ 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')).toHaveSize(0)
- done()
- })
+ triggerDropdownLast.addEventListener('hidden.bs.dropdown', () => {
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
+ resolve()
+ })
- triggerDropdownFirst.click()
+ triggerDropdownFirst.click()
+ })
})
- it('should remove "show" class if body if tabbing outside of menu, with multiple dropdowns', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <a class="dropdown-toggle" data-bs-toggle="dropdown" href="#testmenu">Test menu</a>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- '</div>',
- '<div class="btn-group">',
- ' <button class="btn">Actions</button>',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"></button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Action 1</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should remove "show" class if body if tabbing outside of menu, with multiple dropdowns', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <a class="dropdown-toggle" data-bs-toggle="dropdown" href="#testmenu">Test menu</a>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
+ ' </div>',
+ '</div>',
+ '<div class="btn-group">',
+ ' <button class="btn">Actions</button>',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"></button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Action 1</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]')
+ const triggerDropdownList = fixtureEl.querySelectorAll('[data-bs-toggle="dropdown"]')
- expect(triggerDropdownList).toHaveSize(2)
+ expect(triggerDropdownList).toHaveSize(2)
- const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList
+ const [triggerDropdownFirst, triggerDropdownLast] = triggerDropdownList
- triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => {
- expect(triggerDropdownFirst).toHaveClass('show')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
+ triggerDropdownFirst.addEventListener('shown.bs.dropdown', () => {
+ expect(triggerDropdownFirst).toHaveClass('show')
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
- const keyup = createEvent('keyup')
- keyup.key = 'Tab'
+ const keyup = createEvent('keyup')
+ keyup.key = 'Tab'
- document.dispatchEvent(keyup)
- })
+ document.dispatchEvent(keyup)
+ })
- triggerDropdownFirst.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
- triggerDropdownLast.click()
- })
+ triggerDropdownFirst.addEventListener('hidden.bs.dropdown', () => {
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
+ triggerDropdownLast.click()
+ })
- triggerDropdownLast.addEventListener('shown.bs.dropdown', () => {
- expect(triggerDropdownLast).toHaveClass('show')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
+ triggerDropdownLast.addEventListener('shown.bs.dropdown', () => {
+ expect(triggerDropdownLast).toHaveClass('show')
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(1)
- const keyup = createEvent('keyup')
- keyup.key = 'Tab'
+ const keyup = createEvent('keyup')
+ keyup.key = 'Tab'
- document.dispatchEvent(keyup)
- })
+ document.dispatchEvent(keyup)
+ })
- triggerDropdownLast.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
- done()
- })
+ triggerDropdownLast.addEventListener('hidden.bs.dropdown', () => {
+ expect(fixtureEl.querySelectorAll('.dropdown-menu.show')).toHaveSize(0)
+ resolve()
+ })
- triggerDropdownFirst.click()
+ triggerDropdownFirst.click()
+ })
})
- it('should fire hide and hidden event without a clickEvent if event type is not click', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should fire hide and hidden event without a clickEvent if event type is not click', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- triggerDropdown.addEventListener('hide.bs.dropdown', event => {
- expect(event.clickEvent).toBeUndefined()
- })
+ triggerDropdown.addEventListener('hide.bs.dropdown', event => {
+ expect(event.clickEvent).toBeUndefined()
+ })
- triggerDropdown.addEventListener('hidden.bs.dropdown', event => {
- expect(event.clickEvent).toBeUndefined()
- done()
- })
+ triggerDropdown.addEventListener('hidden.bs.dropdown', event => {
+ expect(event.clickEvent).toBeUndefined()
+ resolve()
+ })
- triggerDropdown.addEventListener('shown.bs.dropdown', () => {
- const keydown = createEvent('keydown')
+ triggerDropdown.addEventListener('shown.bs.dropdown', () => {
+ const keydown = createEvent('keydown')
- keydown.key = 'Escape'
- triggerDropdown.dispatchEvent(keydown)
- })
+ keydown.key = 'Escape'
+ triggerDropdown.dispatchEvent(keydown)
+ })
- triggerDropdown.click()
+ triggerDropdown.click()
+ })
})
- it('should bubble up the events to the parent elements', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#subMenu">Sub menu</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should bubble up the events to the parent elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#subMenu">Sub menu</a>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdownParent = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(triggerDropdown)
+ const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const dropdownParent = fixtureEl.querySelector('.dropdown')
+ const dropdown = new Dropdown(triggerDropdown)
- const showFunction = jasmine.createSpy('showFunction')
- dropdownParent.addEventListener('show.bs.dropdown', showFunction)
+ const showFunction = jasmine.createSpy('showFunction')
+ dropdownParent.addEventListener('show.bs.dropdown', showFunction)
- const shownFunction = jasmine.createSpy('shownFunction')
- dropdownParent.addEventListener('shown.bs.dropdown', () => {
- shownFunction()
- dropdown.hide()
- })
+ const shownFunction = jasmine.createSpy('shownFunction')
+ dropdownParent.addEventListener('shown.bs.dropdown', () => {
+ shownFunction()
+ dropdown.hide()
+ })
- const hideFunction = jasmine.createSpy('hideFunction')
- dropdownParent.addEventListener('hide.bs.dropdown', hideFunction)
+ const hideFunction = jasmine.createSpy('hideFunction')
+ dropdownParent.addEventListener('hide.bs.dropdown', hideFunction)
- dropdownParent.addEventListener('hidden.bs.dropdown', () => {
- expect(showFunction).toHaveBeenCalled()
- expect(shownFunction).toHaveBeenCalled()
- expect(hideFunction).toHaveBeenCalled()
- done()
- })
+ dropdownParent.addEventListener('hidden.bs.dropdown', () => {
+ expect(showFunction).toHaveBeenCalled()
+ expect(shownFunction).toHaveBeenCalled()
+ expect(hideFunction).toHaveBeenCalled()
+ resolve()
+ })
- dropdown.show()
+ dropdown.show()
+ })
})
- it('should ignore keyboard events within <input>s and <textarea>s', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' <input type="text">',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should ignore keyboard events within <input>s and <textarea>s', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
+ ' <input type="text">',
+ ' <textarea></textarea>',
+ ' </div>',
+ '</div>'
+ ].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')
- done()
- })
+ expect(document.activeElement).toEqual(textarea, 'textarea still focused')
+ resolve()
+ })
- triggerDropdown.click()
+ triggerDropdown.click()
+ })
})
- it('should skip disabled element when using keyboard navigation', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item disabled" href="#sub1">Submenu 1</a>',
- ' <button class="dropdown-item" type="button" disabled>Disabled button</button>',
- ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should skip disabled element when using keyboard navigation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item disabled" href="#sub1">Submenu 1</a>',
+ ' <button class="dropdown-item" type="button" disabled>Disabled button</button>',
+ ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<style>',
- ' .d-none {',
- ' display: none;',
- ' }',
- '</style>',
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <button class="dropdown-item d-none" type="button">Hidden button by class</button>',
- ' <a class="dropdown-item" href="#sub1" style="display: none">Hidden link</a>',
- ' <a class="dropdown-item" href="#sub1" style="visibility: hidden">Hidden link</a>',
- ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should skip hidden element when using keyboard navigation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<style>',
+ ' .d-none {',
+ ' display: none;',
+ ' }',
+ '</style>',
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <button class="dropdown-item d-none" type="button">Hidden button by class</button>',
+ ' <a class="dropdown-item" href="#sub1" style="display: none">Hidden link</a>',
+ ' <a class="dropdown-item" href="#sub1" style="visibility: hidden">Hidden link</a>',
+ ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a id="item1" class="dropdown-item" href="#">A link</a>',
- ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should focus next/previous element when using keyboard navigation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a id="item1" class="dropdown-item" href="#">A link</a>',
+ ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a id="item1" class="dropdown-item" href="#">A link</a>',
- ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a id="item1" class="dropdown-item" href="#">A link</a>',
+ ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a id="item1" class="dropdown-item" href="#">A link</a>',
- ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a id="item1" class="dropdown-item" href="#">A link</a>',
+ ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <input type="text">',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not close the dropdown if the user clicks on a text field within dropdown-menu', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <input type="text">',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not close the dropdown if the user clicks on a textarea within dropdown-menu', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <textarea></textarea>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' </div>',
- '</div>',
- '<input type="text">'
- ].join('')
+ 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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' </div>',
+ '</div>',
+ '<input type="text">'
+ ].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')
- triggerDropdown.addEventListener('hidden.bs.dropdown', () => {
- expect().nothing()
- done()
- })
+ triggerDropdown.addEventListener('hidden.bs.dropdown', () => {
+ expect().nothing()
+ resolve()
+ })
- triggerDropdown.addEventListener('shown.bs.dropdown', () => {
- input.dispatchEvent(createEvent('click', {
- bubbles: true
- }))
- })
+ triggerDropdown.addEventListener('shown.bs.dropdown', () => {
+ input.dispatchEvent(createEvent('click', {
+ bubbles: true
+ }))
+ })
- triggerDropdown.click()
- })
+ triggerDropdown.click()
+ })
+ })
+
+ it('should ignore keyboard events for <input>s and <textarea>s within dropdown-menu, except for escape key', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
+ ' <input type="text">',
+ ' <textarea></textarea>',
+ ' </div>',
+ '</div>'
+ ].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`)
+ }
- it('should ignore keyboard events for <input>s and <textarea>s within dropdown-menu, except for escape key', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' <input type="text">',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
+ const keydownEscape = createEvent('keydown')
+ keydownEscape.key = 'Escape'
- 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'
+ 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 = [
- '<div class="tabs">',
- ' <div class="dropdown">',
- ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' <a class="dropdown-item" href="#">Something else here</a>',
- ' <div class="divider"></div>',
- ' <a class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not open dropdown if escape key was pressed on the toggle', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="tabs">',
+ ' <div class="dropdown">',
+ ' <button disabled class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Secondary link</a>',
+ ' <a class="dropdown-item" href="#">Something else here</a>',
+ ' <div class="divider"></div>',
+ ' <a class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
- const dropdown = new Dropdown(triggerDropdown)
- const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]')
+ 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')
+ spyOn(dropdown, 'toggle')
- // Key escape
- button.focus()
- // Key escape
- const keydownEscape = createEvent('keydown')
- keydownEscape.key = 'Escape'
- button.dispatchEvent(keydownEscape)
+ // Key escape
+ button.focus()
+ // Key escape
+ const keydownEscape = createEvent('keydown')
+ keydownEscape.key = 'Escape'
+ button.dispatchEvent(keydownEscape)
- setTimeout(() => {
- expect(dropdown.toggle).not.toHaveBeenCalled()
- expect(triggerDropdown).not.toHaveClass('show')
- done()
- }, 20)
- })
-
- it('should propagate escape key events if dropdown is closed', done => {
- fixtureEl.innerHTML = [
- '<div class="parent">',
- ' <div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Some Item</a>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- 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 = [
+ '<div class="parent">',
+ ' <div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Some Item</a>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Some Item</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should close dropdown using `escape` button, and return focus to its trigger', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Some Item</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="inside">Dropdown toggle</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Dropdown item</a>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="inside">Dropdown toggle</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Dropdown item</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="outside">Dropdown toggle</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Dropdown item</a>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="outside">Dropdown toggle</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Dropdown item</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="false">Dropdown toggle</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Dropdown item</a>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" data-bs-auto-close="false">Dropdown toggle</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#">Dropdown item</a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item disabled" href="#sub1">Submenu 1</a>',
- ' <button class="dropdown-item" type="button" disabled>Disabled button</button>',
- ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should open dropdown when pressing keydown or keyup', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item disabled" href="#sub1">Submenu 1</a>',
+ ' <button class="dropdown-item" type="button" disabled>Disabled button</button>',
+ ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
+ ' </div>',
+ '</div>'
+ ].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 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 handleArrowDown = () => {
+ expect(triggerDropdown).toHaveClass('show')
+ expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true')
+ setTimeout(() => {
+ dropdown.hide()
+ keydown.key = 'ArrowUp'
+ triggerDropdown.dispatchEvent(keyup)
+ }, 20)
}
- })
- triggerDropdown.dispatchEvent(keydown)
+ const handleArrowUp = () => {
+ expect(triggerDropdown).toHaveClass('show')
+ expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true')
+ resolve()
+ }
+
+ 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 = [
- '<div class="container">',
- ' <div class="dropdown">',
- ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"><span id="childElement">Dropdown</span></button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#subMenu">Sub menu</a>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should open the dropdown when clicking the child element inside `data-bs-toggle="dropdown"`', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="container">',
+ ' <div class="dropdown">',
+ ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown"><span id="childElement">Dropdown</span></button>',
+ ' <div class="dropdown-menu">',
+ ' <a class="dropdown-item" href="#subMenu">Sub menu</a>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].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 16781a3518..7da39d6303 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 = [
- '<div class="alert">',
- ' <button type="button" data-bs-dismiss="alert">x</button>',
- '</div>'
- ].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 = [
+ '<div class="alert">',
+ ' <button type="button" data-bs-dismiss="alert">x</button>',
+ '</div>'
+ ].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 84a95c86ad..bf796411b5 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should call ScrollBarHelper to handle scrollBar on body', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
+
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should show a modal', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should show a modal without backdrop', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal-dialog"></div>'
+ modalEl.setAttribute('id', id)
+ modalEl.classList.add('modal')
+ modalEl.innerHTML = '<div class="modal-dialog"></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should not fire shown event when show is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal fade"><div class="modal-dialog"></div></div>'
+ it('should be shown after the first call to show() has been prevented while fading is enabled ', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal fade"><div class="modal-dialog"></div></div>'
- it('should set is transitioning if fade class is present', done => {
- fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog"></div></div>'
+ 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 = [
- '<div class="modal fade">',
- ' <div class="modal-dialog">',
- ' <div class="modal-header">',
- ' <button type="button" data-bs-dismiss="modal"></button>',
- ' </div>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="modal fade">',
+ ' <div class="modal-dialog">',
+ ' <div class="modal-header">',
+ ' <button type="button" data-bs-dismiss="modal"></button>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<button type="button" data-bs-dismiss="modal" data-bs-target="#modal1"></button>',
- '<div id="modal1" class="modal fade">',
- ' <div class="modal-dialog"></div>',
- '</div>'
- ].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 = [
+ '<button type="button" data-bs-dismiss="modal" data-bs-target="#modal1"></button>',
+ '<div id="modal1" class="modal fade">',
+ ' <div class="modal-dialog"></div>',
+ '</div>'
+ ].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 = [
- '<div class="modal fade">',
- ' <div class="modal-dialog"></div>',
- '</div>'
- ].join('')
+ it('should set .modal\'s scroll top to 0', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="modal fade">',
+ ' <div class="modal-dialog"></div>',
+ '</div>'
+ ].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 = [
- '<div class="modal fade">',
- ' <div class="modal-dialog">',
- ' <div class="modal-body"></div>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="modal fade">',
+ ' <div class="modal-dialog">',
+ ' <div class="modal-body"></div>',
+ ' </div>',
+ '</div>'
+ ].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 = '<div class="modal fade"><div class="modal-dialog"></div></div>'
+ it('should not trap focus if focus equal to false', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should add listener when escape touch is pressed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should do nothing when the pressed key is not escape', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should adjust dialog on resize', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = [
- '<div class="modal">',
- ' <div class="modal-dialog">',
- ' <div class="modal-content"></div>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not close modal when clicking on modal-content', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="modal">',
+ ' <div class="modal-dialog">',
+ ' <div class="modal-content"></div>',
+ ' </div>',
+ '</div>'
+ ].join('')
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- const shownCallback = () => {
- setTimeout(() => {
- expect(modal._isShown).toEqual(true)
- done()
- }, 10)
- }
-
- modalEl.addEventListener('shown.bs.modal', () => {
- fixtureEl.querySelector('.modal-dialog').click()
- fixtureEl.querySelector('.modal-content').click()
- shownCallback()
- })
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+
+ 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should not close modal when escape key is pressed with keyboard = false', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog" style="transition-duration: 20ms;"></div></div>'
+ it('should not overflow when clicking outside of modal-content if backdrop = static', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" style="transition-duration: 20ms;"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog" style="transition-duration: 50ms;"></div></div>'
+ it('should not queue multiple callbacks when clicking outside of modal-content and backdrop = static', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" style="transition-duration: 50ms;"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should trap focus', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should hide a modal', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should close modal when clicking outside of modal-content', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should not hide a modal if hide is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = '<div class="modal"><div class="modal-dialog"></div></div>'
+ it('should release focus trap', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
- 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 = [
- '<button type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"></button>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
- ].join('')
+ it('should toggle modal', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<button type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"></button>',
+ '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
+ ].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 = [
- '<button type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"></button>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
- ].join('')
+ it('should not recreate a new modal', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<button type="button" data-bs-toggle="modal" data-bs-target="#exampleModal"></button>',
+ '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
+ ].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 <a> or <area>', done => {
- fixtureEl.innerHTML = [
- '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
- ].join('')
+ it('should prevent default when the trigger is <a> or <area>', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
+ '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
+ ].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 = [
- '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
- ].join('')
+ it('should focus the trigger on hide', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
+ '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
+ ].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 <a> or <area>', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="modal">',
+ ' <div class="modal-dialog">',
+ ' <button type="button" data-bs-dismiss="modal"></button>',
+ ' </div>',
+ '</div>'
+ ].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 <a> or <area>', done => {
- fixtureEl.innerHTML = [
- '<div class="modal">',
- ' <div class="modal-dialog">',
- ' <button type="button" data-bs-dismiss="modal"></button>',
- ' </div>',
- '</div>'
- ].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 <a> or <area>', done => {
- fixtureEl.innerHTML = [
- '<div class="modal">',
- ' <div class="modal-dialog">',
- ' <a type="button" data-bs-dismiss="modal"></a>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should prevent default when a click occurred on data-bs-dismiss="modal" where tagName is <a> or <area>', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="modal">',
+ ' <div class="modal-dialog">',
+ ' <a type="button" data-bs-dismiss="modal"></a>',
+ ' </div>',
+ '</div>'
+ ].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 = [
+ '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal" style="display: none;"></a>',
+ '<div id="exampleModal" class="modal" style="display: none;"><div class="modal-dialog"></div></div>'
+ ].join('')
- it('should not focus the trigger if the modal is not visible', done => {
- fixtureEl.innerHTML = [
- '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal" style="display: none;"></a>',
- '<div id="exampleModal" class="modal" style="display: none;"><div class="modal-dialog"></div></div>'
- ].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 = [
+ '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
+ '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
+ ].join('')
- it('should not focus the trigger if the modal is not shown', done => {
- fixtureEl.innerHTML = [
- '<a data-bs-toggle="modal" href="#" data-bs-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog"></div></div>'
- ].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 = [
- '<button data-bs-toggle="modal" data-bs-target="#modal2"></button>',
- '<div id="modal1" class="modal fade"><div class="modal-dialog"></div></div>',
- '<div id="modal2" class="modal"><div class="modal-dialog"></div></div>'
- ].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 = [
+ '<button data-bs-toggle="modal" data-bs-target="#modal2"></button>',
+ '<div id="modal1" class="modal fade"><div class="modal-dialog"></div></div>',
+ '<div id="modal2" class="modal"><div class="modal-dialog"></div></div>'
+ ].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 = '<div class="modal"><div class="modal-dialog"></div></div>'
diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js
index 36ef45dceb..852ffa5560 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 = '<div class="offcanvas"></div>'
+ it('if scroll is enabled, should allow body to scroll while offcanvas is open', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('if scroll is disabled, should call ScrollBarHelper to handle scrollBar on body', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should hide a shown element if user click on backdrop', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should not trap focus if scroll is allowed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should call hide method if show class is present', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ 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 = '<div class="offcanvas"></div>'
+ it('should show a hidden element', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should not fire shown when show is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas show"></div>'
+ it('on window load, should make visible an offcanvas element, if its markup contains class "show"', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should trap focus', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ 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 = '<div class="offcanvas"></div>'
+ it('should hide a shown element', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should not fire hidden when hide is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = '<div class="offcanvas"></div>'
+ it('should release focus trap', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- 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 = [
- '<input type="checkbox" data-bs-toggle="offcanvas" data-bs-target="#offcanvasdiv1" />',
- '<div id="offcanvasdiv1" class="offcanvas"></div>'
- ].join('')
+ it('should not prevent event for input', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<input type="checkbox" data-bs-toggle="offcanvas" data-bs-target="#offcanvasdiv1" />',
+ '<div id="offcanvasdiv1" class="offcanvas"></div>'
+ ].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 = [
- '<button id="btn2" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2"></button>',
- '<div id="offcanvas1" class="offcanvas"></div>',
- '<div id="offcanvas2" class="offcanvas"></div>'
- ].join('')
-
- 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 = [
+ '<button id="btn2" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2"></button>',
+ '<div id="offcanvas1" class="offcanvas"></div>',
+ '<div id="offcanvas2" class="offcanvas"></div>'
+ ].join('')
+
+ 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 = [
+ '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>',
+ '<div id="offcanvas" class="offcanvas"></div>'
+ ].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 = [
+ '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>',
+ '<div id="offcanvas" class="offcanvas"></div>'
+ ].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 = [
- '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>',
- '<div id="offcanvas" class="offcanvas"></div>'
- ].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 = [
- '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas"></button>',
- '<div id="offcanvas" class="offcanvas"></div>'
- ].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 a04bd21c60..7bbd52b1db 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 = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap">BS twitter</a>'
+ it('should show a popover', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap">BS twitter</a>'
- 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 = '<a href="#">BS twitter</a>'
+ it('should set title and content from functions', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#">BS twitter</a>'
- 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 = '<a href="#">Nice link</a>'
+ it('should show a popover with just content without having header', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#">Nice link</a>'
- 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 = '<a href="#">Nice link</a>'
+ it('should show a popover with just title without having body', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#">Nice link</a>'
- 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 = '<a href="#" data-bs-content="" title="Title which does not require content">Nice link</a>'
+ it('should show a popover with just title without having body using data-attribute to get config', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" data-bs-content="" title="Title which does not require content">Nice link</a>'
- 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 = '<a href="#" data-bs-content="" title="">Nice link</a>'
+ it('should NOT show a popover without `title` and `content`', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" data-bs-content="" title="">Nice link</a>'
- 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 = '<a href="#">BS twitter</a>'
-
- 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 = '<a href="#">BS twitter</a>'
+
+ 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 = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap" data-bs-custom-class="custom-class">BS twitter</a>'
+ it('should show a popover with provided custom class', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap" data-bs-custom-class="custom-class">BS twitter</a>'
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
+ 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 = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap">BS twitter</a>'
+ it('should hide a popover', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap">BS twitter</a>'
- 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 5c044e697a..291654d9be 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 = [
- '<div id="root" class="active" style="display: block">',
- ' <div class="topbar">',
- ' <div class="topbar-inner">',
- ' <div class="container" id="ss-target">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
- ' <li class="nav-item"><a href="#detail">Detail</a></li>',
- ' </ul>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
- ' <div style="height: 200px;">',
- ' <h4 id="masthead">Overview</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' <div style="height: 200px;">',
- ' <h4 id="detail">Detail</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div id="root" class="active" style="display: block">',
+ ' <div class="topbar">',
+ ' <div class="topbar-inner">',
+ ' <div class="container" id="ss-target">',
+ ' <ul class="nav">',
+ ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
+ ' <li class="nav-item"><a href="#detail">Detail</a></li>',
+ ' </ul>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
+ ' <div style="height: 200px;">',
+ ' <h4 id="masthead">Overview</h4>',
+ ' <p style="height: 200px;"></p>',
+ ' </div>',
+ ' <div style="height: 200px;">',
+ ' <h4 id="detail">Detail</h4>',
+ ' <p style="height: 200px;"></p>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div id="root" class="active" style="display: block">',
- ' <div class="topbar">',
- ' <div class="topbar-inner">',
- ' <div class="container" id="ss-target">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
- ' <li class="nav-item"><a href="#detail">Detail</a></li>',
- ' </ul>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
- ' <div style="height: 200px;">',
- ' <h4 id="masthead">Overview</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' <div style="height: 200px;">',
- ' <h4 id="detail">Detail</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div id="root" class="active" style="display: block">',
+ ' <div class="topbar">',
+ ' <div class="topbar-inner">',
+ ' <div class="container" id="ss-target">',
+ ' <ul class="nav">',
+ ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
+ ' <li class="nav-item"><a href="#detail">Detail</a></li>',
+ ' </ul>',
+ ' </div>',
+ ' </div>',
+ ' </div>',
+ ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
+ ' <div style="height: 200px;">',
+ ' <h4 id="masthead">Overview</h4>',
+ ' <p style="height: 200px;"></p>',
+ ' </div>',
+ ' <div style="height: 200px;">',
+ ' <h4 id="detail">Detail</h4>',
+ ' <p style="height: 200px;"></p>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="one" style="height: 500px;"></div>',
- ' <div id="two" style="height: 300px;"></div>',
- ' <div id="three" style="height: 10px;"></div>',
- '</div>'
- ].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 = [
+ '<div id="header" style="height: 500px;"></div>',
+ '<nav id="navigation" class="navbar">',
+ ' <ul class="navbar-nav">',
+ ' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>',
+ ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
+ ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
+ ' </ul>',
+ '</nav>',
+ '<div id="content" style="height: 200px; overflow-y: auto;">',
+ ' <div id="one" style="height: 500px;"></div>',
+ ' <div id="two" style="height: 300px;"></div>',
+ ' <div id="three" style="height: 10px;"></div>',
+ '</div>'
+ ].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 = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].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 = [
+ '<nav class="navbar">',
+ ' <ul class="nav">',
+ ' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
+ ' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
+ ' </ul>',
+ '</nav>',
+ '<div class="content" style="overflow: auto; height: 50px">',
+ ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
+ ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
+ '</div>'
+ ].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 = [
- '<nav class="navbar">',
- ' <nav class="nav">',
- ' <a class="nav-link" id="a-1" href="#div-1">div 1</a>',
- ' <a class="nav-link" id="a-2" href="#div-2">div 2</a>',
- ' </nav>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].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 = [
+ '<nav class="navbar">',
+ ' <nav class="nav">',
+ ' <a class="nav-link" id="a-1" href="#div-1">div 1</a>',
+ ' <a class="nav-link" id="a-2" href="#div-2">div 2</a>',
+ ' </nav>',
+ '</nav>',
+ '<div class="content" style="overflow: auto; height: 50px">',
+ ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
+ ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
+ '</div>'
+ ].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 = [
- '<nav class="navbar">',
- ' <div class="list-group">',
- ' <a class="list-group-item" id="a-1" href="#div-1">div 1</a>',
- ' <a class="list-group-item" id="a-2" href="#div-2">div 2</a>',
- ' </div>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].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 = [
+ '<nav class="navbar">',
+ ' <div class="list-group">',
+ ' <a class="list-group-item" id="a-1" href="#div-1">div 1</a>',
+ ' <a class="list-group-item" id="a-2" href="#div-2">div 2</a>',
+ ' </div>',
+ '</nav>',
+ '<div class="content" style="overflow: auto; height: 50px">',
+ ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
+ ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
+ '</div>'
+ ].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 = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
- ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="spacer" style="height: 100px;"></div>',
- ' <div id="one" style="height: 100px;"></div>',
- ' <div id="two" style="height: 100px;"></div>',
- ' <div id="three" style="height: 100px;"></div>',
- ' <div id="spacer" style="height: 100px;"></div>',
- '</div>'
- ].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 = [
+ '<div id="header" style="height: 500px;"></div>',
+ '<nav id="navigation" class="navbar">',
+ ' <ul class="navbar-nav">',
+ ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
+ ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
+ ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
+ ' </ul>',
+ '</nav>',
+ '<div id="content" style="height: 200px; overflow-y: auto;">',
+ ' <div id="spacer" style="height: 100px;"></div>',
+ ' <div id="one" style="height: 100px;"></div>',
+ ' <div id="two" style="height: 100px;"></div>',
+ ' <div id="three" style="height: 100px;"></div>',
+ ' <div id="spacer" style="height: 100px;"></div>',
+ '</div>'
+ ].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 = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
- ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="one" style="height: 100px;"></div>',
- ' <div id="two" style="height: 100px;"></div>',
- ' <div id="three" style="height: 100px;"></div>',
- ' <div id="spacer" style="height: 100px;"></div>',
- '</div>'
- ].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 = [
+ '<div id="header" style="height: 500px;"></div>',
+ '<nav id="navigation" class="navbar">',
+ ' <ul class="navbar-nav">',
+ ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
+ ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
+ ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
+ ' </ul>',
+ '</nav>',
+ '<div id="content" style="height: 200px; overflow-y: auto;">',
+ ' <div id="one" style="height: 100px;"></div>',
+ ' <div id="two" style="height: 100px;"></div>',
+ ' <div id="three" style="height: 100px;"></div>',
+ ' <div id="spacer" style="height: 100px;"></div>',
+ '</div>'
+ ].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 = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>',
- ' <li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>',
- ' <li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>',
- ' <li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>',
- ' <li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="position: relative; overflow: auto; height: 100px">',
- ' <div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>',
- ' <div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>',
- ' <div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>',
- ' <div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>',
- '</div>'
- ].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 = [
+ '<nav class="navbar">',
+ ' <ul class="nav">',
+ ' <li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>',
+ ' <li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>',
+ ' <li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>',
+ ' <li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>',
+ ' <li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>',
+ ' </ul>',
+ '</nav>',
+ '<div class="content" style="position: relative; overflow: auto; height: 100px">',
+ ' <div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>',
+ ' <div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>',
+ ' <div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>',
+ ' <div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>',
+ ' <div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>',
+ '</div>'
+ ].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 bafa085526..43adee53b2 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 = [
- '<ul class="nav" role="tablist">',
- ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
- ' <li><button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button></li>',
- '</ul>',
- '<ul>',
- ' <li id="home" role="tabpanel"></li>',
- ' <li id="profile" role="tabpanel"></li>',
- '</ul>'
- ].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 = [
+ '<ul class="nav" role="tablist">',
+ ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
+ ' <li><button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button></li>',
+ '</ul>',
+ '<ul>',
+ ' <li id="home" role="tabpanel"></li>',
+ ' <li id="profile" role="tabpanel"></li>',
+ '</ul>'
+ ].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 = [
- '<ul class="nav" role="tablist">',
- ' <li><a href="#home" role="tab">Home</a></li>',
- ' <li><a id="triggerProfile" href="#profile" role="tab">Profile</a></li>',
- '</ul>',
- '<ul>',
- ' <li id="home" role="tabpanel"></li>',
- ' <li id="profile" role="tabpanel"></li>',
- '</ul>'
- ].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 = [
+ '<ul class="nav" role="tablist">',
+ ' <li><a href="#home" role="tab">Home</a></li>',
+ ' <li><a id="triggerProfile" href="#profile" role="tab">Profile</a></li>',
+ '</ul>',
+ '<ul>',
+ ' <li id="home" role="tabpanel"></li>',
+ ' <li id="profile" role="tabpanel"></li>',
+ '</ul>'
+ ].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 = [
- '<ol class="nav nav-pills">',
- ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
- ' <li><button type="button" id="triggerProfile" href="#profile" role="tab">Profile</button></li>',
- '</ol>',
- '<ol>',
- ' <li id="home" role="tabpanel"></li>',
- ' <li id="profile" role="tabpanel"></li>',
- '</ol>'
- ].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 = [
+ '<ol class="nav nav-pills">',
+ ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
+ ' <li><button type="button" id="triggerProfile" href="#profile" role="tab">Profile</button></li>',
+ '</ol>',
+ '<ol>',
+ ' <li id="home" role="tabpanel"></li>',
+ ' <li id="profile" role="tabpanel"></li>',
+ '</ol>'
+ ].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 = [
- '<nav class="nav">',
- ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
- ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>',
- '</nav>',
- '<div>',
- ' <div id="home" role="tabpanel"></div>',
- ' <div id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
- const tab = new Tab(profileTriggerEl)
+ it('should activate element by tab id in nav list', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<nav class="nav">',
+ ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
+ ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>',
+ '</nav>',
+ '<div>',
+ ' <div id="home" role="tabpanel"></div>',
+ ' <div id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].join('')
+
+ const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
+ const tab = new Tab(profileTriggerEl)
+
+ profileTriggerEl.addEventListener('shown.bs.tab', () => {
+ expect(fixtureEl.querySelector('#profile')).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 = [
- '<div class="list-group" role="tablist">',
- ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
- ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>',
- '</div>',
- '<div>',
- ' <div id="home" role="tabpanel"></div>',
- ' <div id="profile" role="tabpanel"></div>',
- '</div>'
- ].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 = [
+ '<div class="list-group" role="tablist">',
+ ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
+ ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>',
+ '</div>',
+ '<div>',
+ ' <div id="home" role="tabpanel"></div>',
+ ' <div id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = '<div class="nav"></div>'
+ it('should not fire shown when show is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div class="nav"></div>'
- 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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
- ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
+ ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav" role="tablist">',
- ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
- ' <li><button type="button" data-bs-target="#profile">Profile</button></li>',
- '</ul>'
- ].join('')
+ it('should fire hide and hidden events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<ul class="nav" role="tablist">',
+ ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
+ ' <li><button type="button" data-bs-target="#profile">Profile</button></li>',
+ '</ul>'
+ ].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 = [
- '<ul class="nav" role="tablist">',
- ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
- ' <li><button type="button" data-bs-target="#profile" role="tab">Profile</button></li>',
- '</ul>'
- ].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 = [
+ '<ul class="nav" role="tablist">',
+ ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
+ ' <li><button type="button" data-bs-target="#profile" role="tab">Profile</button></li>',
+ '</ul>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation">',
- ' <a class="nav-link nav-tab" href="#profile" role="tab" data-bs-toggle="tab">',
- ' <button class="btn-close" aria-label="Close"></button>',
- ' </a>',
- ' </li>',
- ' <li class="nav-item" role="presentation">',
- ' <a id="secondNav" class="nav-link nav-tab" href="#buzz" role="tab" data-bs-toggle="tab">',
- ' <button class="btn-close" aria-label="Close"></button>',
- ' </a>',
- ' </li>',
- ' <li class="nav-item" role="presentation">',
- ' <a class="nav-link nav-tab" href="#references" role="tab" data-bs-toggle="tab">',
- ' <button id="btnClose" class="btn-close" aria-label="Close"></button>',
- ' </a>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane fade show active" id="profile">test 1</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="buzz">test 2</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="references">test 3</div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation">',
+ ' <a class="nav-link nav-tab" href="#profile" role="tab" data-bs-toggle="tab">',
+ ' <button class="btn-close" aria-label="Close"></button>',
+ ' </a>',
+ ' </li>',
+ ' <li class="nav-item" role="presentation">',
+ ' <a id="secondNav" class="nav-link nav-tab" href="#buzz" role="tab" data-bs-toggle="tab">',
+ ' <button class="btn-close" aria-label="Close"></button>',
+ ' </a>',
+ ' </li>',
+ ' <li class="nav-item" role="presentation">',
+ ' <a class="nav-link nav-tab" href="#references" role="tab" data-bs-toggle="tab">',
+ ' <button id="btnClose" class="btn-close" aria-label="Close"></button>',
+ ' </a>',
+ ' </li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div role="tabpanel" class="tab-pane fade show active" id="profile">test 1</div>',
+ ' <div role="tabpanel" class="tab-pane fade" id="buzz">test 2</div>',
+ ' <div role="tabpanel" class="tab-pane fade" id="references">test 3</div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
- ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-toggle="tab" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const secondTabTrigger = fixtureEl.querySelector('#triggerProfile')
+ it('should create dynamically a tab', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
+ ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-toggle="tab" data-bs-target="#profile" class="nav-link" role="tab">Profile</button></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = [
- '<nav class="nav nav-tabs" role="tablist">',
- ' <button type="button" id="tab1" data-bs-target="#x-tab1" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</button>',
- ' <button type="button" data-bs-target="#x-tab2" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</button>',
- ' <button type="button" data-bs-target="#x-tab3" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</button>',
- '</nav>',
- '<div class="tab-content">',
- ' <div class="tab-pane" id="x-tab1" role="tabpanel">',
- ' <nav class="nav nav-tabs" role="tablist">',
- ' <button type="button" data-bs-target="#nested-tab1" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</button>',
- ' <button type="button" id="tabNested2" data-bs-target="#nested-tab2" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</button>',
- ' </nav>',
- ' <div class="tab-content">',
- ' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>',
- ' <div class="tab-pane" id="nested-tab2" role="tabpanel">Nested Tab2 Content</div>',
- ' </div>',
- ' </div>',
- ' <div class="tab-pane active" id="x-tab2" role="tabpanel">Tab2 Content</div>',
- ' <div class="tab-pane" id="x-tab3" role="tabpanel">Tab3 Content</div>',
- '</div>'
- ].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 = [
+ '<nav class="nav nav-tabs" role="tablist">',
+ ' <button type="button" id="tab1" data-bs-target="#x-tab1" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</button>',
+ ' <button type="button" data-bs-target="#x-tab2" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</button>',
+ ' <button type="button" data-bs-target="#x-tab3" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</button>',
+ '</nav>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane" id="x-tab1" role="tabpanel">',
+ ' <nav class="nav nav-tabs" role="tablist">',
+ ' <button type="button" data-bs-target="#nested-tab1" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</button>',
+ ' <button type="button" id="tabNested2" data-bs-target="#nested-tab2" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</button>',
+ ' </nav>',
+ ' <div class="tab-content">',
+ ' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>',
+ ' <div class="tab-pane" id="nested-tab2" role="tabpanel">Nested Tab2 Content</div>',
+ ' </div>',
+ ' </div>',
+ ' <div class="tab-pane active" id="x-tab2" role="tabpanel">Tab2 Content</div>',
+ ' <div class="tab-pane" id="x-tab3" role="tabpanel">Tab3 Content</div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><button type="button" id="tab-home" data-bs-target="#home" class="nav-link" data-bs-toggle="tab" role="tab">Home</button></li>',
- ' <li class="nav-item" role="presentation"><button type="button" id="tab-profile" data-bs-target="#profile" class="nav-link" data-bs-toggle="tab" role="tab">Profile</button></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane fade" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane fade" id="profile" role="tabpanel"></div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><button type="button" id="tab-home" data-bs-target="#home" class="nav-link" data-bs-toggle="tab" role="tab">Home</button></li>',
+ ' <li class="nav-item" role="presentation"><button type="button" id="tab-profile" data-bs-target="#profile" class="nav-link" data-bs-toggle="tab" role="tab">Profile</button></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane fade" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane fade" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation">',
- ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-toggle="tab">Home</button>',
- ' </li>',
- ' <li class="nav-item" role="presentation">',
- ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane" id="home">test 1</div>',
- ' <div role="tabpanel" class="tab-pane" id="profile">test 2</div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation">',
+ ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-toggle="tab">Home</button>',
+ ' </li>',
+ ' <li class="nav-item" role="presentation">',
+ ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
+ ' </li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div role="tabpanel" class="tab-pane" id="home">test 1</div>',
+ ' <div role="tabpanel" class="tab-pane" id="profile">test 2</div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation">',
- ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-toggle="tab">Home</button>',
- ' </li>',
- ' <li class="nav-item" role="presentation">',
- ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane fade" id="home">test 1</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="profile">test 2</div>',
- '</div>'
- ].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 = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation">',
+ ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-toggle="tab">Home</button>',
+ ' </li>',
+ ' <li class="nav-item" role="presentation">',
+ ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
+ ' </li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div role="tabpanel" class="tab-pane fade" id="home">test 1</div>',
+ ' <div role="tabpanel" class="tab-pane fade" id="profile">test 2</div>',
+ '</div>'
+ ].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 <a> or <area>', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav" role="tablist">',
- ' <li><a type="button" href="#test" class="active" role="tab" data-bs-toggle="tab">Home</a></li>',
- ' <li><a type="button" href="#test2" role="tab" data-bs-toggle="tab">Home</a></li>',
- '</ul>'
- ].join('')
+ it('should prevent default when the trigger is <a> or <area>', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<ul class="nav" role="tablist">',
+ ' <li><a type="button" href="#test" class="active" role="tab" data-bs-toggle="tab">Home</a></li>',
+ ' <li><a type="button" href="#test2" role="tab" data-bs-toggle="tab">Home</a></li>',
+ '</ul>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
- ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" disabled role="tab">Profile</button></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
+ it('should not fire shown when tab has disabled attribute', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
+ ' <li class="nav-item" role="presentation"><button type="button" data-bs-target="#profile" class="nav-link" disabled role="tab">Profile</button></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item" role="presentation"><a href="#home" class="nav-link active" role="tab" aria-selected="true">Home</a></li>',
- ' <li class="nav-item" role="presentation"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
+ it('should not fire shown when tab has disabled class', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<ul class="nav nav-tabs" role="tablist">',
+ ' <li class="nav-item" role="presentation"><a href="#home" class="nav-link active" role="tab" aria-selected="true">Home</a></li>',
+ ' <li class="nav-item" role="presentation"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>',
+ '</ul>',
+ '<div class="tab-content">',
+ ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
+ ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
+ '</div>'
+ ].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 c4ea43808c..9134a8410d 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 = [
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
+ it('should allow to config in js', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="1" data-bs-autohide="false" data-bs-animation="false">',
- ' <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>',
- '</div>'
- ].join('')
+ it('should close toast when close element with data-bs-dismiss attribute is set', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast" data-bs-delay="1" data-bs-autohide="false" data-bs-animation="false">',
+ ' <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="1">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].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 = [
- '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
+ it('should auto hide', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast" data-bs-delay="1">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not add fade class', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<button id="outside-focusable">outside focusable</button>',
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' <button>with a button</button>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should clear timeout if toast is interacted with mouse', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<button id="outside-focusable">outside focusable</button>',
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' <button>with a button</button>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should clear timeout if toast is interacted with keyboard', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<button id="outside-focusable">outside focusable</button>',
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' <button>with a button</button>',
+ ' </div>',
+ '</div>'
+ ].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 = [
+ '<button id="outside-focusable">outside focusable</button>',
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' <button>with a button</button>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<button id="outside-focusable">outside focusable</button>',
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' <button>with a button</button>',
- ' </div>',
- '</div>'
- ].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 = [
+ '<button id="outside-focusable">outside focusable</button>',
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' <button>with a button</button>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<button id="outside-focusable">outside focusable</button>',
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' <button>with a button</button>',
- ' </div>',
- '</div>'
- ].join('')
+ it('should not auto hide if mouse pointer leaves but focus remains inside', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<button id="outside-focusable">outside focusable</button>',
+ '<div class="toast">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' <button>with a button</button>',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="1" data-bs-autohide="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
+ it('should allow to hide toast manually', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast" data-bs-delay="1" data-bs-autohide="false">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].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 = [
+ '<div class="toast" data-bs-delay="1" data-bs-animation="false">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 = [
- '<div class="toast" data-bs-delay="0" data-bs-autohide="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
+ it('should allow to destroy toast and hide it before that', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="toast" data-bs-delay="0" data-bs-autohide="false">',
+ ' <div class="toast-body">',
+ ' a simple toast',
+ ' </div>',
+ '</div>'
+ ].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 3feacf7b44..4a9a6d3bb0 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 = '<div></div>'
+ it('should enable selector delegation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
- containerEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
+ 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 = '<a href="#" rel="tooltip" title="Offset from function">'
+ it('should create offset modifier when offset is passed as a function', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Offset from function">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should enable a tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should disable tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should do nothing if disabled', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should call toggle and show the tooltip when trigger is "click"', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should hide a tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should destroy a tooltip after it is shown and hidden', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should destroy a tooltip and remove it from the dom', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = [
- '<a href="#" rel="tooltip" title="Another tooltip">',
- ' <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100">',
- ' <rect width="100%" fill="#563d7c"/>',
- ' <circle cx="50" cy="50" r="30" fill="#fff"/>',
- ' </svg>',
- '</a>'
- ].join('')
+ it('should show a tooltip when hovering a child element', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a href="#" rel="tooltip" title="Another tooltip">',
+ ' <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100">',
+ ' <rect width="100%" fill="#563d7c"/>',
+ ' <circle cx="50" cy="50" r="30" fill="#fff"/>',
+ ' </svg>',
+ '</a>'
+ ].join('')
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
+ 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip on mobile', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip relative to placement option', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should not error when trying to show a tooltip that has been removed from the dom', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with a dom element container', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with a jquery element container', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with a selector in container', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with placement as a function', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip without the animation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
-
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show tooltip if leave event hasn\'t occurred before delay expires', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should not show tooltip if leave event occurs before delay expires', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = [
- '<a href="#" rel="tooltip" title="Another tooltip">',
- '<b>Trigger</b>',
- 'the tooltip',
- '</a>'
- ].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 = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-placement="top" style="position:fixed;left:50%;top:50%;">Trigger</a>'
+ it('should not hide tooltip if leave event occurs and interaction remains inside trigger', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a href="#" rel="tooltip" title="Another tooltip">',
+ '<b>Trigger</b>',
+ 'the tooltip',
+ '</a>'
+ ].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 = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-placement="top" style="position:fixed;left:50%;top:50%;">Trigger</a>'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
-
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class">'
+ it('should show a tooltip with custom class provided in data attributes', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with custom class provided as a string in config', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should show a tooltip with custom class provided as a function in config', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
+ it('should remove `title` attribute if exists', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should hide a tooltip', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should hide a tooltip on mobile', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should hide a tooltip without animation', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should not hide a tooltip if hide event is prevented', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">'
+ it('should call popper update', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
+ it('should add the aria-label attribute for referencing original title', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
- 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 = '<a href="#" rel="tooltip" aria-label="Different label" title="Another tooltip"></a>'
+ it('should not add the aria-label attribute if the attribute already exists', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" aria-label="Different label" title="Another tooltip"></a>'
- 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 = '<a href="#" rel="tooltip" title="Another tooltip">text content</a>'
+ it('should not add the aria-label attribute if the element has text content', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">text content</a>'
- 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 f9903c8327..73384fc90b 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 = '<div id="wrapper"></div>'
+ it('should not error if the backdrop no longer has a parent', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div id="wrapper"></div>'
- 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 = '<div id="wrapper"></div>'
- 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 = '<div id="wrapper"></div>'
+
+ 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 52a7573971..55f6a23a7e 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 = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="inside">inside</a>',
- '</div>'
- ].join('')
+ it('should force focus inside focus trap if it can', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a href="#" id="outside">outside</a>',
+ '<div id="focustrap" tabindex="-1">',
+ ' <a href="#" id="inside">inside</a>',
+ '</div>'
+ ].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 = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="first">first</a>',
- ' <a href="#" id="inside">inside</a>',
- ' <a href="#" id="last">last</a>',
- '</div>'
- ].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 = [
+ '<a href="#" id="outside">outside</a>',
+ '<div id="focustrap" tabindex="-1">',
+ ' <a href="#" id="first">first</a>',
+ ' <a href="#" id="inside">inside</a>',
+ ' <a href="#" id="last">last</a>',
+ '</div>'
+ ].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 = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="first">first</a>',
- ' <a href="#" id="inside">inside</a>',
- ' <a href="#" id="last">last</a>',
- '</div>'
- ].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 = [
+ '<a href="#" id="outside">outside</a>',
+ '<div id="focustrap" tabindex="-1">',
+ ' <a href="#" id="first">first</a>',
+ ' <a href="#" id="inside">inside</a>',
+ ' <a href="#" id="last">last</a>',
+ '</div>'
+ ].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 = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1"></div>'
- ].join('')
+ it('should force focus on itself if there is no focusable content', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<a href="#" id="outside">outside</a>',
+ '<div id="focustrap" tabindex="-1"></div>'
+ ].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 9d8c5ed986..0d60ca9894 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 = '<div></div>'
+ it('should trigger transitionend event', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- 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 = [
- '<div class="outer">',
- ' <div class="nested"></div>',
- '</div>'
- ].join('')
+ it('should ignore transitionend events from nested elements', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="outer">',
+ ' <div class="nested"></div>',
+ '</div>'
+ ].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 fc3a6f4e87..6fcf5718bb 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 = [
'<div style="height: 110vh; width: 100%">',
' <div class="fixed-top" id="fixed1" style="padding-right: 0px; width: 100vw"></div>',
@@ -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 = [
'<div style="height: 110vh; width: 100%">',
' <div class="fixed" id="fixed" style="width: 100vw;"></div>',
@@ -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 = [
'<div style="height: 110vh">',
' <div class="sticky-top" style="margin-right: 10px; padding-right: 20px; width: 100vw; height: 10px"></div>',
@@ -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 93131b8fdd..054aab6958 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')
+ })
})
})