diff options
Diffstat (limited to 'js/tests/unit/carousel.spec.js')
| -rw-r--r-- | js/tests/unit/carousel.spec.js | 1474 |
1 files changed, 755 insertions, 719 deletions
diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index a138f3ad5..2960eb5ce 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -1,8 +1,10 @@ -import Carousel from '../../src/carousel' -import EventHandler from '../../src/dom/event-handler' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' -import { isRTL, noop } from '../../src/util/index' -import Swipe from '../../src/util/swipe' +import Carousel from '../../src/carousel.js' +import EventHandler from '../../src/dom/event-handler.js' +import { isRTL, noop } from '../../src/util/index.js' +import Swipe from '../../src/util/swipe.js' +import { + clearFixture, createEvent, getFixture, jQueryMock +} from '../helpers/fixture.js' describe('Carousel', () => { const { Simulator, PointerEvent } = window @@ -63,94 +65,148 @@ 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 start cycling if `ride`===`carousel`', () => { + fixtureEl.innerHTML = '<div id="myCarousel" class="carousel slide" data-bs-ride="carousel"></div>' - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, { - keyboard: true - }) + const carousel = new Carousel('#myCarousel') + expect(carousel._interval).not.toBeNull() + }) - spyOn(carousel, '_keydown').and.callThrough() + it('should not start cycling if `ride`!==`carousel`', () => { + fixtureEl.innerHTML = '<div id="myCarousel" class="carousel slide" data-bs-ride="true"></div>' - carouselEl.addEventListener('slid.bs.carousel', () => { - expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) - expect(carousel._keydown).toHaveBeenCalled() - done() - }) + const carousel = new Carousel('#myCarousel') + expect(carousel._interval).toBeNull() + }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowRight' + 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 + }) + + const spy = spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) + expect(spy).toHaveBeenCalled() + resolve() + }) - 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 => { + it('should ignore keyboard events if data-bs-keyboard=false', () => { fixtureEl.innerHTML = [ - '<div id="myCarousel" class="carousel slide">', + '<div id="myCarousel" class="carousel slide" data-bs-keyboard="false">', ' <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 class="carousel-item active">item 1</div>', + ' <div id="item2" class="carousel-item">item 2</div>', ' </div>', '</div>' ].join('') + const spy = spyOn(EventHandler, 'trigger').and.callThrough() 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('#item1')) - expect(carousel._keydown).toHaveBeenCalled() - done() - }) - - const keydown = createEvent('keydown') - keydown.key = 'ArrowLeft' - - carouselEl.dispatchEvent(keydown) + // eslint-disable-next-line no-new + new Carousel('#myCarousel') + expect(spy).not.toHaveBeenCalledWith(carouselEl, 'keydown.bs.carousel', jasmine.any(Function)) }) - it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', done => { + it('should ignore mouse events if data-bs-pause=false', () => { fixtureEl.innerHTML = [ - '<div id="myCarousel" class="carousel slide">', + '<div id="myCarousel" class="carousel slide" data-bs-pause="false">', ' <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 id="item2" class="carousel-item">item 2</div>', ' </div>', '</div>' ].join('') + const spy = spyOn(EventHandler, 'trigger').and.callThrough() const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, { - keyboard: true - }) + // eslint-disable-next-line no-new + new Carousel('#myCarousel') + expect(spy).not.toHaveBeenCalledWith(carouselEl, 'hover.bs.carousel', jasmine.any(Function)) + }) + + 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 spy = spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1')) + expect(spy).toHaveBeenCalled() + resolve() + }) - spyOn(carousel, '_keydown').and.callThrough() + const keydown = createEvent('keydown') + keydown.key = 'ArrowLeft' - carouselEl.addEventListener('keydown', event => { - expect(carousel._keydown).toHaveBeenCalled() - expect(event.defaultPrevented).toEqual(false) - done() + carouselEl.dispatchEvent(keydown) }) + }) + + 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 spy = spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('keydown', event => { + expect(spy).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', () => { @@ -208,7 +264,7 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - spyOn(carousel, '_triggerSlideEvent') + const spy = spyOn(EventHandler, 'trigger') carousel._isSliding = true @@ -219,75 +275,77 @@ describe('Carousel', () => { carouselEl.dispatchEvent(keydown) } - expect(carousel._triggerSlideEvent).not.toHaveBeenCalled() + expect(spy).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 = () => { - return 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, reject) => { + 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', () => { + reject(new Error('carousel slid when it should not have slid')) + }) - carousel.prev() + carousel.prev() - setTimeout(() => { - expect(firstElement.classList.contains('active')).toEqual(true) - done() - }, 10) + setTimeout(() => { + expect(firstElement).toHaveClass('active') + resolve() + }, 10) + }) }) it('should not add touch event listeners if touch = false', () => { @@ -295,13 +353,13 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') - spyOn(Carousel.prototype, '_addTouchEventListeners') + const spy = spyOn(Carousel.prototype, '_addTouchEventListeners') const carousel = new Carousel(carouselEl, { touch: false }) - expect(carousel._addTouchEventListeners).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() expect(carousel._swipeHelper).toBeNull() }) @@ -314,11 +372,11 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) EventHandler.off(carouselEl, Carousel.EVENT_KEY) - spyOn(carousel, '_addTouchEventListeners') + const spy = spyOn(carousel, '_addTouchEventListeners') carousel._addEventListeners() - expect(carousel._addTouchEventListeners).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() expect(carousel._swipeHelper).toBeNull() }) @@ -337,274 +395,292 @@ 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.classList.contains('active')).toEqual(true) - 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">', + ' <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) + + const spy = spyOn(carousel, '_slide').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', event => { + expect(item).toHaveClass('active') + expect(spy).toHaveBeenCalledWith('prev') + 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.classList.contains('active')).toEqual(false) - 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">', + ' <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) + + const spy = spyOn(carousel, '_slide').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', event => { + expect(item).not.toHaveClass('active') + expect(spy).toHaveBeenCalledWith('next') + 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.classList.contains('active')).toEqual(true) - 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">', + ' <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) + + const spy = spyOn(carousel, '_slide').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', event => { + expect(item).toHaveClass('active') + expect(spy).toHaveBeenCalledWith('prev') + 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.classList.contains('active')).toEqual(false) - 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">', + ' <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) + + const spy = spyOn(carousel, '_slide').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', event => { + expect(item).not.toHaveClass('active') + expect(spy).toHaveBeenCalledWith('next') + 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('') - - const carouselEl = fixtureEl.querySelector('.carousel') - const carousel = new Carousel(carouselEl) - carousel._isSliding = true - - spyOn(carousel, '_triggerSlideEvent') + 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">', + ' <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 + + const spy = spyOn(EventHandler, 'trigger') + + Simulator.gestures.swipe(carouselEl, { + deltaX: 300, + deltaY: 0 + }) + + Simulator.gestures.swipe(carouselEl, { + pos: [300, 10], + deltaX: -300, + deltaY: 0 + }) - Simulator.gestures.swipe(carouselEl, { - deltaX: 300, - deltaY: 0 - }) - - Simulator.gestures.swipe(carouselEl, { - pos: [300, 10], - deltaX: -300, - deltaY: 0 + setTimeout(() => { + expect(spy).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"></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') + const spy = 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(spy).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 `maybeEnableCycle` on mouse out with pause equal to hover', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '<div class="carousel" data-bs-ride="true"></div>' - const carouselEl = fixtureEl.querySelector('.carousel') - const carousel = new Carousel(carouselEl) + const carouselEl = fixtureEl.querySelector('.carousel') + const carousel = new Carousel(carouselEl) - spyOn(carousel, 'cycle') + const spyEnable = spyOn(carousel, '_maybeEnableCycle').and.callThrough() + const spyCycle = 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(spyEnable).toHaveBeenCalled() + expect(spyCycle).toHaveBeenCalled() + resolve() + }, 10) + }) }) }) @@ -615,108 +691,114 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - spyOn(carousel, '_triggerSlideEvent') + const spy = spyOn(EventHandler, 'trigger') carousel._isSliding = true carousel.next() - expect(carousel._triggerSlideEvent).not.toHaveBeenCalled() + expect(spy).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).toEqual(false) - 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.classList.contains('carousel-item')).toEqual(true) - 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.classList.contains('carousel-item')).toEqual(true) - 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', () => { @@ -739,36 +821,60 @@ describe('Carousel', () => { expect(carousel._activeElement).toEqual(secondItemEl) }) - it('should update indicators if present', done => { + it('should continue cycling if it was already', () => { 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 class="carousel-item">item 2</div>', ' </div>', '</div>' ].join('') const carouselEl = fixtureEl.querySelector('#myCarousel') - const firstIndicator = fixtureEl.querySelector('#firstIndicator') - const secondIndicator = fixtureEl.querySelector('#secondIndicator') const carousel = new Carousel(carouselEl) + const spy = spyOn(carousel, 'cycle') - carouselEl.addEventListener('slid.bs.carousel', () => { - expect(firstIndicator.classList.contains('active')).toEqual(false) - expect(firstIndicator.hasAttribute('aria-current')).toEqual(false) - expect(secondIndicator.classList.contains('active')).toEqual(true) - expect(secondIndicator.getAttribute('aria-current')).toEqual('true') - done() - }) + carousel.next() + expect(spy).not.toHaveBeenCalled() + carousel.cycle() carousel.next() + expect(spy).toHaveBeenCalledTimes(1) + }) + + 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() + }) }) it('should call next()/prev() instance methods when clicking the respective direction buttons', () => { @@ -791,12 +897,14 @@ describe('Carousel', () => { const carousel = new Carousel(carouselEl) const nextSpy = spyOn(carousel, 'next') const prevSpy = spyOn(carousel, 'prev') + const spyEnable = spyOn(carousel, '_maybeEnableCycle') nextBtnEl.click() prevBtnEl.click() expect(nextSpy).toHaveBeenCalled() expect(prevSpy).toHaveBeenCalled() + expect(spyEnable).toHaveBeenCalled() }) }) @@ -804,18 +912,18 @@ describe('Carousel', () => { it('should not call next when the page is not visible', () => { fixtureEl.innerHTML = [ '<div style="display: none;">', - ' <div class="carousel" data-bs-interval="false"></div>', + ' <div class="carousel"></div>', '</div>' ].join('') const carouselEl = fixtureEl.querySelector('.carousel') const carousel = new Carousel(carouselEl) - spyOn(carousel, 'next') + const spy = spyOn(carousel, 'next') carousel.nextWhenVisible() - expect(carousel.next).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) }) @@ -826,91 +934,42 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - spyOn(carousel, '_triggerSlideEvent') + const spy = spyOn(EventHandler, 'trigger') carousel._isSliding = true carousel.prev() - expect(carousel._triggerSlideEvent).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) }) describe('pause', () => { - it('should call cycle if the carousel have carousel-item-next and carousel-item-prev class', () => { - fixtureEl.innerHTML = [ - '<div id="myCarousel" class="carousel slide">', - ' <div class="carousel-inner">', - ' <div class="carousel-item active">item 1</div>', - ' <div class="carousel-item carousel-item-next">item 2</div>', - ' <div class="carousel-item">item 3</div>', - ' </div>', - ' <div class="carousel-control-prev"></div>', - ' <div class="carousel-control-next"></div>', - '</div>' - ].join('') - - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl) - - spyOn(carousel, 'cycle') - spyOn(window, 'clearInterval') - - carousel.pause() - - expect(carousel.cycle).toHaveBeenCalledWith(true) - expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(true) - }) - - it('should not call cycle if nothing is in transition', () => { - 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 class="carousel-control-prev"></div>', - ' <div class="carousel-control-next"></div>', - '</div>' - ].join('') - - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl) - - spyOn(carousel, 'cycle') - spyOn(window, 'clearInterval') - - carousel.pause() - - expect(carousel.cycle).not.toHaveBeenCalled() - expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(true) - }) - - it('should not set is paused at true if an event is passed', () => { - 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 class="carousel-control-prev"></div>', - ' <div class="carousel-control-next"></div>', - '</div>' - ].join('') - - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl) - const event = createEvent('mouseenter') - - spyOn(window, 'clearInterval') - - carousel.pause(event) - - expect(window.clearInterval).toHaveBeenCalled() - expect(carousel._isPaused).toEqual(false) + it('should trigger transitionend if the carousel have carousel-item-next or carousel-item-prev class, cause 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 carousel-item-next">item 2</div>', + ' <div class="carousel-item">item 3</div>', + ' </div>', + ' <div class="carousel-control-prev"></div>', + ' <div class="carousel-control-next"></div>', + '</div>' + ].join('') + + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl) + const spy = spyOn(carousel, '_clearInterval') + + carouselEl.addEventListener('transitionend', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) + + carousel._slide('next') + carousel.pause() + }) }) }) @@ -931,35 +990,11 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl) - spyOn(window, 'setInterval').and.callThrough() + const spy = spyOn(window, 'setInterval').and.callThrough() carousel.cycle() - expect(window.setInterval).toHaveBeenCalled() - }) - - it('should not set interval if the carousel is paused', () => { - 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 class="carousel-control-prev"></div>', - ' <div class="carousel-control-next"></div>', - '</div>' - ].join('') - - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl) - - spyOn(window, 'setInterval').and.callThrough() - - carousel._isPaused = true - carousel.cycle(true) - - expect(window.setInterval).not.toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) it('should clear interval if there is one', () => { @@ -980,13 +1015,13 @@ describe('Carousel', () => { carousel._interval = setInterval(noop, 10) - spyOn(window, 'setInterval').and.callThrough() - spyOn(window, 'clearInterval').and.callThrough() + const spySet = spyOn(window, 'setInterval').and.callThrough() + const spyClear = spyOn(window, 'clearInterval').and.callThrough() carousel.cycle() - expect(window.setInterval).toHaveBeenCalled() - expect(window.clearInterval).toHaveBeenCalled() + expect(spySet).toHaveBeenCalled() + expect(spyClear).toHaveBeenCalled() }) it('should get interval from data attribute on the active item element', () => { @@ -1020,51 +1055,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('') - - const carouselEl = fixtureEl.querySelector('#myCarousel') - const carousel = new Carousel(carouselEl, {}) + 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, {}) - 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() + }) }) }) @@ -1095,7 +1134,7 @@ describe('Carousel', () => { expect(spy).not.toHaveBeenCalled() }) - it('should call pause and cycle is the provided is the same compare to the current one', () => { + it('should not continue if the provided is the same compare to the current one', () => { fixtureEl.innerHTML = [ '<div id="myCarousel" class="carousel slide">', ' <div class="carousel-inner">', @@ -1109,50 +1148,49 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl, {}) - spyOn(carousel, '_slide') - spyOn(carousel, 'pause') - spyOn(carousel, 'cycle') + const spy = spyOn(carousel, '_slide') carousel.to(0) - expect(carousel._slide).not.toHaveBeenCalled() - expect(carousel.pause).toHaveBeenCalled() - expect(carousel.cycle).toHaveBeenCalled() + expect(spy).not.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') + const spyOne = spyOn(EventHandler, 'one').and.callThrough() + const spySlide = 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(spySlide).not.toHaveBeenCalled() + expect(spyOne).toHaveBeenCalled() - spyOn(carousel, 'to') + const spyTo = spyOn(carousel, 'to') - EventHandler.trigger(carouselEl, 'slid.bs.carousel') + EventHandler.trigger(carouselEl, 'slid.bs.carousel') - setTimeout(() => { - expect(carousel.to).toHaveBeenCalledWith(1) - done() + setTimeout(() => { + expect(spyTo).toHaveBeenCalledWith(1) + resolve() + }) }) }) }) + describe('rtl function', () => { it('"_directionToOrder" and "_orderToDirection" must return the right results', () => { fixtureEl.innerHTML = '<div></div>' @@ -1161,9 +1199,7 @@ describe('Carousel', () => { 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') @@ -1175,12 +1211,10 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - expect(isRTL()).toEqual(true, 'rtl has to be true') + expect(isRTL()).toBeTrue() expect(carousel._directionToOrder('left')).toEqual('prev') - expect(carousel._directionToOrder('prev')).toEqual('prev') expect(carousel._directionToOrder('right')).toEqual('next') - expect(carousel._directionToOrder('next')).toEqual('next') expect(carousel._orderToDirection('next')).toEqual('right') expect(carousel._orderToDirection('prev')).toEqual('left') @@ -1192,16 +1226,14 @@ describe('Carousel', () => { 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') + const spy = spyOn(carousel, '_orderToDirection').and.callThrough() - carousel._slide('right') - expect(spy).toHaveBeenCalledWith('right') - expect(spy2).toHaveBeenCalledWith('prev') + carousel._slide(carousel._directionToOrder('left')) + expect(spy).toHaveBeenCalledWith('next') + + carousel._slide(carousel._directionToOrder('right')) + expect(spy).toHaveBeenCalledWith('prev') }) it('"_slide" has to call "_directionToOrder" and "_orderToDirection" when rtl=true', () => { @@ -1210,16 +1242,13 @@ describe('Carousel', () => { const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) - const spy = spyOn(carousel, '_directionToOrder').and.callThrough() - const spy2 = spyOn(carousel, '_orderToDirection').and.callThrough() + const spy = spyOn(carousel, '_orderToDirection').and.callThrough() - carousel._slide('left') - expect(spy).toHaveBeenCalledWith('left') - expect(spy2).toHaveBeenCalledWith('prev') + carousel._slide(carousel._directionToOrder('left')) + expect(spy).toHaveBeenCalledWith('prev') - carousel._slide('right') - expect(spy).toHaveBeenCalledWith('right') - expect(spy2).toHaveBeenCalledWith('next') + carousel._slide(carousel._directionToOrder('right')) + expect(spy).toHaveBeenCalledWith('next') document.documentElement.dir = 'ltl' }) @@ -1292,7 +1321,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() }) }) @@ -1313,7 +1342,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() expect(Carousel.getOrCreateInstance(div)).toBeInstanceOf(Carousel) }) @@ -1322,7 +1351,7 @@ describe('Carousel', () => { const div = fixtureEl.querySelector('div') - expect(Carousel.getInstance(div)).toEqual(null) + expect(Carousel.getInstance(div)).toBeNull() const carousel = Carousel.getOrCreateInstance(div, { interval: 1 }) @@ -1385,14 +1414,14 @@ describe('Carousel', () => { const carousel = new Carousel(div) const slideTo = 2 - spyOn(carousel, 'to') + const spy = spyOn(carousel, 'to') jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] jQueryMock.fn.carousel.call(jQueryMock, slideTo) - expect(carousel.to).toHaveBeenCalledWith(slideTo) + expect(spy).toHaveBeenCalledWith(slideTo) }) it('should throw error on undefined method', () => { @@ -1418,79 +1447,86 @@ describe('Carousel', () => { const loadEvent = createEvent('load') window.dispatchEvent(loadEvent) - - expect(Carousel.getInstance(carouselEl)).not.toBeNull() + const carousel = Carousel.getInstance(carouselEl) + expect(carousel._interval).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"></div>', - '</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.classList.contains('active')).toEqual(true) - 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"></button>', - ' <a id="next" class="carousel-control-next" href="#myCarousel" role="button" data-bs-slide="next"></div>', - '</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.classList.contains('active')).toEqual(true) - 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" data-bs-ride="true">', + ' <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.classList.contains('active')).toEqual(true) - done() - }, 10) + setTimeout(() => { + expect(item2).toHaveClass('active') + expect(Carousel.getInstance('#myCarousel')._interval).not.toBeNull() + resolve() + }, 10) + }) }) it('should do nothing if no selector on click on arrows', () => { @@ -1521,8 +1557,8 @@ describe('Carousel', () => { ' <div id="item2" class="carousel-item">item 2</div>', ' <div class="carousel-item">item 3</div>', ' </div>', - ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></div>', - ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></div>', + ' <button class="carousel-control-prev" data-bs-target="#myCarousel" type="button" data-bs-slide="prev"></button>', + ' <button id="next" class="carousel-control-next" data-bs-target="#myCarousel" type="button" data-bs-slide="next"></button>', '</div>' ].join('') |
