aboutsummaryrefslogtreecommitdiff
path: root/js/tests/unit/carousel.spec.js
diff options
context:
space:
mode:
authorXhmikosR <[email protected]>2021-08-18 07:29:56 +0300
committerGitHub <[email protected]>2021-08-18 07:29:56 +0300
commit433a148c9e61aa942801fd8101dfa5c4045fdaed (patch)
treef41db59fd06019169df5ea0338213ec0e298f226 /js/tests/unit/carousel.spec.js
parentb97cfa163b5098db70e03b27c91fca5dde9c267e (diff)
parent18b3e1ac71f73d006756684a285c5a818e2d1454 (diff)
downloadbootstrap-global-focus-vars.tar.xz
bootstrap-global-focus-vars.zip
Merge branch 'main' into global-focus-varsglobal-focus-vars
Diffstat (limited to 'js/tests/unit/carousel.spec.js')
-rw-r--r--js/tests/unit/carousel.spec.js298
1 files changed, 263 insertions, 35 deletions
diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js
index 533e1ba7e..a933f1eda 100644
--- a/js/tests/unit/carousel.spec.js
+++ b/js/tests/unit/carousel.spec.js
@@ -2,7 +2,8 @@ import Carousel from '../../src/carousel'
import EventHandler from '../../src/dom/event-handler'
/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture'
+import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture'
+import * as util from '../../src/util'
describe('Carousel', () => {
const { Simulator, PointerEvent } = window
@@ -13,7 +14,7 @@ describe('Carousel', () => {
const stylesCarousel = document.createElement('style')
stylesCarousel.type = 'text/css'
- stylesCarousel.appendChild(document.createTextNode(cssStyleCarousel))
+ stylesCarousel.append(document.createTextNode(cssStyleCarousel))
const clearPointerEvents = () => {
window.PointerEvent = null
@@ -52,6 +53,17 @@ describe('Carousel', () => {
})
describe('constructor', () => {
+ it('should take care of element either passed as a CSS selector or DOM element', () => {
+ fixtureEl.innerHTML = '<div id="myCarousel" class="carousel slide"></div>'
+
+ const carouselEl = fixtureEl.querySelector('#myCarousel')
+ const carouselBySelector = new Carousel('#myCarousel')
+ const carouselByElement = new Carousel(carouselEl)
+
+ expect(carouselBySelector._element).toEqual(carouselEl)
+ 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">',
@@ -164,8 +176,7 @@ describe('Carousel', () => {
})
const spyKeydown = spyOn(carousel, '_keydown').and.callThrough()
- const spyPrev = spyOn(carousel, 'prev')
- const spyNext = spyOn(carousel, 'next')
+ const spySlide = spyOn(carousel, '_slide')
const keydown = createEvent('keydown', { bubbles: true, cancelable: true })
keydown.key = 'ArrowRight'
@@ -178,12 +189,10 @@ describe('Carousel', () => {
input.dispatchEvent(keydown)
expect(spyKeydown).toHaveBeenCalled()
- expect(spyPrev).not.toHaveBeenCalled()
- expect(spyNext).not.toHaveBeenCalled()
+ expect(spySlide).not.toHaveBeenCalled()
spyKeydown.calls.reset()
- spyPrev.calls.reset()
- spyNext.calls.reset()
+ spySlide.calls.reset()
Object.defineProperty(keydown, 'target', {
value: textarea
@@ -191,8 +200,27 @@ describe('Carousel', () => {
textarea.dispatchEvent(keydown)
expect(spyKeydown).toHaveBeenCalled()
- expect(spyPrev).not.toHaveBeenCalled()
- expect(spyNext).not.toHaveBeenCalled()
+ expect(spySlide).not.toHaveBeenCalled()
+ })
+
+ it('should not slide if arrow key is pressed and carousel is sliding', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+
+ spyOn(carousel, '_triggerSlideEvent')
+
+ carousel._isSliding = true;
+
+ ['ArrowLeft', 'ArrowRight'].forEach(key => {
+ const keydown = createEvent('keydown')
+ keydown.key = key
+
+ carouselEl.dispatchEvent(keydown)
+ })
+
+ expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
})
it('should wrap around from end to start when wrap option is true', done => {
@@ -309,7 +337,7 @@ describe('Carousel', () => {
expect(carousel._addTouchEventListeners).toHaveBeenCalled()
})
- it('should allow swiperight and call prev with pointer events', done => {
+ it('should allow swiperight and call _slide (prev) with pointer events', done => {
if (!supportPointerEvent) {
expect().nothing()
done()
@@ -317,7 +345,7 @@ describe('Carousel', () => {
}
document.documentElement.ontouchstart = () => {}
- document.head.appendChild(stylesCarousel)
+ document.head.append(stylesCarousel)
Simulator.setType('pointer')
fixtureEl.innerHTML = [
@@ -337,12 +365,13 @@ describe('Carousel', () => {
const item = fixtureEl.querySelector('#item')
const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'prev').and.callThrough()
+ spyOn(carousel, '_slide').and.callThrough()
- carouselEl.addEventListener('slid.bs.carousel', () => {
+ carouselEl.addEventListener('slid.bs.carousel', event => {
expect(item.classList.contains('active')).toEqual(true)
- expect(carousel.prev).toHaveBeenCalled()
- document.head.removeChild(stylesCarousel)
+ expect(carousel._slide).toHaveBeenCalledWith('right')
+ expect(event.direction).toEqual('right')
+ stylesCarousel.remove()
delete document.documentElement.ontouchstart
done()
})
@@ -361,7 +390,7 @@ describe('Carousel', () => {
}
document.documentElement.ontouchstart = () => {}
- document.head.appendChild(stylesCarousel)
+ document.head.append(stylesCarousel)
Simulator.setType('pointer')
fixtureEl.innerHTML = [
@@ -381,12 +410,13 @@ describe('Carousel', () => {
const item = fixtureEl.querySelector('#item')
const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'next').and.callThrough()
+ spyOn(carousel, '_slide').and.callThrough()
- carouselEl.addEventListener('slid.bs.carousel', () => {
+ carouselEl.addEventListener('slid.bs.carousel', event => {
expect(item.classList.contains('active')).toEqual(false)
- expect(carousel.next).toHaveBeenCalled()
- document.head.removeChild(stylesCarousel)
+ expect(carousel._slide).toHaveBeenCalledWith('left')
+ expect(event.direction).toEqual('left')
+ stylesCarousel.remove()
delete document.documentElement.ontouchstart
done()
})
@@ -398,7 +428,7 @@ describe('Carousel', () => {
})
})
- it('should allow swiperight and call prev with touch events', done => {
+ it('should allow swiperight and call _slide (prev) with touch events', done => {
Simulator.setType('touch')
clearPointerEvents()
document.documentElement.ontouchstart = () => {}
@@ -420,11 +450,12 @@ describe('Carousel', () => {
const item = fixtureEl.querySelector('#item')
const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'prev').and.callThrough()
+ spyOn(carousel, '_slide').and.callThrough()
- carouselEl.addEventListener('slid.bs.carousel', () => {
+ carouselEl.addEventListener('slid.bs.carousel', event => {
expect(item.classList.contains('active')).toEqual(true)
- expect(carousel.prev).toHaveBeenCalled()
+ expect(carousel._slide).toHaveBeenCalledWith('right')
+ expect(event.direction).toEqual('right')
delete document.documentElement.ontouchstart
restorePointerEvents()
done()
@@ -436,7 +467,7 @@ describe('Carousel', () => {
})
})
- it('should allow swipeleft and call next with touch events', done => {
+ it('should allow swipeleft and call _slide (next) with touch events', done => {
Simulator.setType('touch')
clearPointerEvents()
document.documentElement.ontouchstart = () => {}
@@ -458,11 +489,12 @@ describe('Carousel', () => {
const item = fixtureEl.querySelector('#item')
const carousel = new Carousel(carouselEl)
- spyOn(carousel, 'next').and.callThrough()
+ spyOn(carousel, '_slide').and.callThrough()
- carouselEl.addEventListener('slid.bs.carousel', () => {
+ carouselEl.addEventListener('slid.bs.carousel', event => {
expect(item.classList.contains('active')).toEqual(false)
- expect(carousel.next).toHaveBeenCalled()
+ expect(carousel._slide).toHaveBeenCalledWith('left')
+ expect(event.direction).toEqual('left')
delete document.documentElement.ontouchstart
restorePointerEvents()
done()
@@ -475,6 +507,49 @@ describe('Carousel', () => {
})
})
+ it('should not slide when swiping and carousel is sliding', done => {
+ Simulator.setType('touch')
+ clearPointerEvents()
+ document.documentElement.ontouchstart = () => {}
+
+ 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
+ })
+
+ 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()
@@ -540,12 +615,12 @@ describe('Carousel', () => {
const carouselEl = fixtureEl.querySelector('div')
const carousel = new Carousel(carouselEl, {})
- spyOn(carousel, '_slide')
+ spyOn(carousel, '_triggerSlideEvent')
carousel._isSliding = true
carousel.next()
- expect(carousel._slide).not.toHaveBeenCalled()
+ expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
})
it('should not fire slid when slide is prevented', done => {
@@ -695,6 +770,34 @@ describe('Carousel', () => {
carousel.next()
})
+
+ it('should call next()/prev() instance methods when clicking the respective direction buttons', () => {
+ fixtureEl.innerHTML = [
+ '<div id="carousel" 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>',
+ ' <button class="carousel-control-prev" type="button" data-bs-target="#carousel" data-bs-slide="prev"></button>',
+ ' <button class="carousel-control-next" type="button" data-bs-target="#carousel" data-bs-slide="next"></button>',
+ '</div>'
+ ].join('')
+
+ const carouselEl = fixtureEl.querySelector('#carousel')
+ const prevBtnEl = fixtureEl.querySelector('.carousel-control-prev')
+ const nextBtnEl = fixtureEl.querySelector('.carousel-control-next')
+
+ const carousel = new Carousel(carouselEl)
+ const nextSpy = spyOn(carousel, 'next')
+ const prevSpy = spyOn(carousel, 'prev')
+
+ nextBtnEl.click()
+ prevBtnEl.click()
+
+ expect(nextSpy).toHaveBeenCalled()
+ expect(prevSpy).toHaveBeenCalled()
+ })
})
describe('nextWhenVisible', () => {
@@ -723,12 +826,12 @@ describe('Carousel', () => {
const carouselEl = fixtureEl.querySelector('div')
const carousel = new Carousel(carouselEl, {})
- spyOn(carousel, '_slide')
+ spyOn(carousel, '_triggerSlideEvent')
carousel._isSliding = true
carousel.prev()
- expect(carousel._slide).not.toHaveBeenCalled()
+ expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
})
})
@@ -1050,6 +1153,77 @@ describe('Carousel', () => {
})
})
})
+ describe('rtl function', () => {
+ it('"_directionToOrder" and "_orderToDirection" must return the right results', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+
+ expect(carousel._directionToOrder('left')).toEqual('next')
+ expect(carousel._directionToOrder('prev')).toEqual('prev')
+ expect(carousel._directionToOrder('right')).toEqual('prev')
+ expect(carousel._directionToOrder('next')).toEqual('next')
+
+ expect(carousel._orderToDirection('next')).toEqual('left')
+ expect(carousel._orderToDirection('prev')).toEqual('right')
+ })
+
+ it('"_directionToOrder" and "_orderToDirection" must return the right results when rtl=true', () => {
+ document.documentElement.dir = 'rtl'
+ fixtureEl.innerHTML = '<div></div>'
+
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+ expect(util.isRTL()).toEqual(true, 'rtl has to be true')
+
+ expect(carousel._directionToOrder('left')).toEqual('prev')
+ expect(carousel._directionToOrder('prev')).toEqual('prev')
+ expect(carousel._directionToOrder('right')).toEqual('next')
+ expect(carousel._directionToOrder('next')).toEqual('next')
+
+ expect(carousel._orderToDirection('next')).toEqual('right')
+ expect(carousel._orderToDirection('prev')).toEqual('left')
+ document.documentElement.dir = 'ltl'
+ })
+
+ it('"_slide" has to call _directionToOrder and "_orderToDirection"', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+ const spy = spyOn(carousel, '_directionToOrder').and.callThrough()
+ const spy2 = spyOn(carousel, '_orderToDirection').and.callThrough()
+
+ carousel._slide('left')
+ expect(spy).toHaveBeenCalledWith('left')
+ expect(spy2).toHaveBeenCalledWith('next')
+
+ carousel._slide('right')
+ expect(spy).toHaveBeenCalledWith('right')
+ expect(spy2).toHaveBeenCalledWith('prev')
+ })
+
+ it('"_slide" has to call "_directionToOrder" and "_orderToDirection" when rtl=true', () => {
+ document.documentElement.dir = 'rtl'
+ fixtureEl.innerHTML = '<div></div>'
+
+ const carouselEl = fixtureEl.querySelector('div')
+ const carousel = new Carousel(carouselEl, {})
+ const spy = spyOn(carousel, '_directionToOrder').and.callThrough()
+ const spy2 = spyOn(carousel, '_orderToDirection').and.callThrough()
+
+ carousel._slide('left')
+ expect(spy).toHaveBeenCalledWith('left')
+ expect(spy2).toHaveBeenCalledWith('prev')
+
+ carousel._slide('right')
+ expect(spy).toHaveBeenCalledWith('right')
+ expect(spy2).toHaveBeenCalledWith('next')
+
+ document.documentElement.dir = 'ltl'
+ })
+ })
describe('dispose', () => {
it('should destroy a carousel', () => {
@@ -1119,6 +1293,60 @@ describe('Carousel', () => {
})
})
+ describe('getOrCreateInstance', () => {
+ it('should return carousel instance', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const carousel = new Carousel(div)
+
+ expect(Carousel.getOrCreateInstance(div)).toEqual(carousel)
+ expect(Carousel.getInstance(div)).toEqual(Carousel.getOrCreateInstance(div, {}))
+ expect(Carousel.getOrCreateInstance(div)).toBeInstanceOf(Carousel)
+ })
+
+ it('should return new instance when there is no carousel instance', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Carousel.getInstance(div)).toEqual(null)
+ expect(Carousel.getOrCreateInstance(div)).toBeInstanceOf(Carousel)
+ })
+
+ it('should return new instance when there is no carousel instance with given configuration', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Carousel.getInstance(div)).toEqual(null)
+ const carousel = Carousel.getOrCreateInstance(div, {
+ interval: 1
+ })
+ expect(carousel).toBeInstanceOf(Carousel)
+
+ expect(carousel._config.interval).toEqual(1)
+ })
+
+ it('should return the instance when exists without given configuration', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const carousel = new Carousel(div, {
+ interval: 1
+ })
+ expect(Carousel.getInstance(div)).toEqual(carousel)
+
+ const carousel2 = Carousel.getOrCreateInstance(div, {
+ interval: 2
+ })
+ expect(carousel).toBeInstanceOf(Carousel)
+ expect(carousel2).toEqual(carousel)
+
+ expect(carousel2._config.interval).toEqual(1)
+ })
+ })
+
describe('jQueryInterface', () => {
it('should create a carousel', () => {
fixtureEl.innerHTML = '<div></div>'
@@ -1130,7 +1358,7 @@ describe('Carousel', () => {
jQueryMock.fn.carousel.call(jQueryMock)
- expect(Carousel.getInstance(div)).toBeDefined()
+ expect(Carousel.getInstance(div)).not.toBeNull()
})
it('should not re create a carousel', () => {
@@ -1188,7 +1416,7 @@ describe('Carousel', () => {
window.dispatchEvent(loadEvent)
- expect(Carousel.getInstance(carouselEl)).toBeDefined()
+ expect(Carousel.getInstance(carouselEl)).not.toBeNull()
})
it('should create carousel and go to the next slide on click (with real button controls)', done => {