carousel.spec.js 37.04 KiB
import Carousel from '../../src/carousel'
import EventHandler from '../../src/dom/event-handler'
/** Test helpers */
import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture'
describe('Carousel', () => {
  const { Simulator, PointerEvent } = window
  const originWinPointerEvent = PointerEvent
  const supportPointerEvent = Boolean(PointerEvent)
  const cssStyleCarousel = '.carousel.pointer-event { touch-action: none; }'
  const stylesCarousel = document.createElement('style')
  stylesCarousel.type = 'text/css'
  stylesCarousel.appendChild(document.createTextNode(cssStyleCarousel))
  const clearPointerEvents = () => {
    window.PointerEvent = null
  const restorePointerEvents = () => {
    window.PointerEvent = originWinPointerEvent
  let fixtureEl
  beforeAll(() => {
    fixtureEl = getFixture()
  afterEach(() => {
    clearFixture()
  describe('VERSION', () => {
    it('should return plugin version', () => {
      expect(Carousel.VERSION).toEqual(jasmine.any(String))
  describe('Default', () => {
    it('should return plugin default config', () => {
      expect(Carousel.Default).toEqual(jasmine.any(Object))
  describe('constructor', () => {
    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('')
      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()
        done()
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
}) 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('') 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) }) 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('') const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl, { keyboard: true }) spyOn(carousel, '_keydown').and.callThrough() carouselEl.addEventListener('keydown', event => { expect(carousel._keydown).toHaveBeenCalled() expect(event.defaultPrevented).toEqual(false) done() }) const keydown = createEvent('keydown') keydown.key = 'ArrowDown' carouselEl.dispatchEvent(keydown) }) it('should ignore keyboard events within <input>s and <textarea>s', () => { fixtureEl.innerHTML = [
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
'<div id="myCarousel" class="carousel slide">', ' <div class="carousel-inner">', ' <div class="carousel-item active">', ' <input type="text" />', ' <textarea></textarea>', ' </div>', ' <div class="carousel-item"></div>', ' <div class="carousel-item">item 3</div>', ' </div>', '</div>' ].join('') const carouselEl = fixtureEl.querySelector('#myCarousel') const input = fixtureEl.querySelector('input') const textarea = fixtureEl.querySelector('textarea') const carousel = new Carousel(carouselEl, { keyboard: true }) const spyKeydown = spyOn(carousel, '_keydown').and.callThrough() const spyPrev = spyOn(carousel, 'prev') const spyNext = spyOn(carousel, 'next') const keydown = createEvent('keydown', { bubbles: true, cancelable: true }) keydown.key = 'ArrowRight' Object.defineProperty(keydown, 'target', { value: input, writable: true, configurable: true }) input.dispatchEvent(keydown) expect(spyKeydown).toHaveBeenCalled() expect(spyPrev).not.toHaveBeenCalled() expect(spyNext).not.toHaveBeenCalled() spyKeydown.calls.reset() spyPrev.calls.reset() spyNext.calls.reset() Object.defineProperty(keydown, 'target', { value: textarea }) textarea.dispatchEvent(keydown) expect(spyKeydown).toHaveBeenCalled() expect(spyPrev).not.toHaveBeenCalled() expect(spyNext).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', e => { const activeId = getActiveId()
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
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(e.from + 1).toEqual(3) done() } }) 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('') 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') }) carousel.prev() setTimeout(() => { expect(firstElement.classList.contains('active')).toEqual(true) done() }, 10) }) it('should not add touch event listeners if touch = false', () => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') spyOn(Carousel.prototype, '_addTouchEventListeners') const carousel = new Carousel(carouselEl, { touch: false }) expect(carousel._addTouchEventListeners).not.toHaveBeenCalled() }) it('should not add touch event listeners if touch supported = false', () => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl)
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
EventHandler.off(carouselEl, '.bs-carousel') carousel._touchSupported = false spyOn(carousel, '_addTouchEventListeners') carousel._addEventListeners() expect(carousel._addTouchEventListeners).not.toHaveBeenCalled() }) it('should add touch event listeners by default', () => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') spyOn(Carousel.prototype, '_addTouchEventListeners') document.documentElement.ontouchstart = () => {} const carousel = new Carousel(carouselEl) expect(carousel._addTouchEventListeners).toHaveBeenCalled() }) it('should allow swiperight and call prev with pointer events', done => { if (!supportPointerEvent) { expect().nothing() done() return } document.documentElement.ontouchstart = () => {} document.head.appendChild(stylesCarousel) Simulator.setType('pointer') fixtureEl.innerHTML = [ '<div class="carousel" data-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, 'prev').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', () => { expect(item.classList.contains('active')).toEqual(true) expect(carousel.prev).toHaveBeenCalled() document.head.removeChild(stylesCarousel) delete document.documentElement.ontouchstart done() }) Simulator.gestures.swipe(carouselEl, { deltaX: 300, deltaY: 0 }) }) it('should allow swipeleft and call next with pointer events', done => { if (!supportPointerEvent) { expect().nothing()
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
done() return } document.documentElement.ontouchstart = () => {} document.head.appendChild(stylesCarousel) Simulator.setType('pointer') fixtureEl.innerHTML = [ '<div class="carousel" data-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, 'next').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', () => { expect(item.classList.contains('active')).toEqual(false) expect(carousel.next).toHaveBeenCalled() document.head.removeChild(stylesCarousel) delete document.documentElement.ontouchstart done() }) Simulator.gestures.swipe(carouselEl, { pos: [300, 10], deltaX: -300, deltaY: 0 }) }) it('should allow swiperight and call prev with touch events', done => { Simulator.setType('touch') clearPointerEvents() document.documentElement.ontouchstart = () => {} fixtureEl.innerHTML = [ '<div class="carousel" data-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, 'prev').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', () => { expect(item.classList.contains('active')).toEqual(true) expect(carousel.prev).toHaveBeenCalled() delete document.documentElement.ontouchstart
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
restorePointerEvents() done() }) Simulator.gestures.swipe(carouselEl, { deltaX: 300, deltaY: 0 }) }) it('should allow swipeleft and call next with touch events', done => { Simulator.setType('touch') clearPointerEvents() document.documentElement.ontouchstart = () => {} fixtureEl.innerHTML = [ '<div class="carousel" data-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, 'next').and.callThrough() carouselEl.addEventListener('slid.bs.carousel', () => { expect(item.classList.contains('active')).toEqual(false) expect(carousel.next).toHaveBeenCalled() delete document.documentElement.ontouchstart restorePointerEvents() done() }) Simulator.gestures.swipe(carouselEl, { pos: [300, 10], deltaX: -300, deltaY: 0 }) }) it('should not allow pinch with touch events', done => { Simulator.setType('touch') clearPointerEvents() document.documentElement.ontouchstart = () => {} fixtureEl.innerHTML = '<div class="carousel" data-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.touchDeltaX).toEqual(0) done() })
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
}) it('should call pause method on mouse over with pause equal to hover', done => { fixtureEl.innerHTML = '<div class="carousel"></div>' const carouselEl = fixtureEl.querySelector('.carousel') const carousel = new Carousel(carouselEl) spyOn(carousel, 'pause') const mouseOverEvent = createEvent('mouseover') carouselEl.dispatchEvent(mouseOverEvent) setTimeout(() => { expect(carousel.pause).toHaveBeenCalled() done() }, 10) }) it('should call cycle on mouse out with pause equal to hover', done => { fixtureEl.innerHTML = '<div class="carousel"></div>' const carouselEl = fixtureEl.querySelector('.carousel') const carousel = new Carousel(carouselEl) spyOn(carousel, 'cycle') const mouseOutEvent = createEvent('mouseout') carouselEl.dispatchEvent(mouseOutEvent) setTimeout(() => { expect(carousel.cycle).toHaveBeenCalled() done() }, 10) }) }) describe('next', () => { it('should not slide if the carousel is sliding', () => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) spyOn(carousel, '_slide') carousel._isSliding = true carousel.next() expect(carousel._slide).not.toHaveBeenCalled() }) it('should not fire slid when slide is prevented', done => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) let slidEvent = false const doneTest = () => { setTimeout(() => { expect(slidEvent).toEqual(false) done() }, 20) } carouselEl.addEventListener('slide.bs.carousel', e => { e.preventDefault() doneTest() })
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
carouselEl.addEventListener('slid.bs.carousel', () => { slidEvent = true }) 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('') const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl, {}) const onSlide = e => { expect(e.direction).toEqual('left') expect(e.relatedTarget.classList.contains('carousel-item')).toEqual(true) expect(e.from).toEqual(0) expect(e.to).toEqual(1) carouselEl.removeEventListener('slide.bs.carousel', onSlide) carouselEl.addEventListener('slide.bs.carousel', onSlide2) carousel.prev() } const onSlide2 = e => { expect(e.direction).toEqual('right') done() } 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('') const carouselEl = fixtureEl.querySelector('#myCarousel') const carousel = new Carousel(carouselEl, {}) const onSlid = e => { expect(e.direction).toEqual('left') expect(e.relatedTarget.classList.contains('carousel-item')).toEqual(true) expect(e.from).toEqual(0) expect(e.to).toEqual(1) carouselEl.removeEventListener('slid.bs.carousel', onSlid) carouselEl.addEventListener('slid.bs.carousel', onSlid2) carousel.prev() } const onSlid2 = e => {
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
expect(e.direction).toEqual('right') done() } carouselEl.addEventListener('slid.bs.carousel', onSlid) carousel.next() }) it('should get interval from data attribute in individual item', () => { 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-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, { interval: 1814 }) expect(carousel._config.interval).toEqual(1814) carousel.next() expect(carousel._config.interval).toEqual(7) }) it('should update indicators if present', done => { fixtureEl.innerHTML = [ '<div id="myCarousel" class="carousel slide">', ' <ol class="carousel-indicators">', ' <li data-target="#myCarousel" data-slide-to="0" class="active"></li>', ' <li id="secondIndicator" data-target="#myCarousel" data-slide-to="1"></li>', ' <li data-target="#myCarousel" data-slide-to="2"></li>', ' </ol>', ' <div class="carousel-inner">', ' <div class="carousel-item active">item 1</div>', ' <div class="carousel-item" data-interval="7">item 2</div>', ' <div class="carousel-item">item 3</div>', ' </div>', '</div>' ].join('') const carouselEl = fixtureEl.querySelector('#myCarousel') const secondIndicator = fixtureEl.querySelector('#secondIndicator') const carousel = new Carousel(carouselEl) carouselEl.addEventListener('slid.bs.carousel', () => { expect(secondIndicator.classList.contains('active')).toEqual(true) done() }) carousel.next() }) }) describe('nextWhenVisible', () => { it('should not call next when the page is not visible', () => { fixtureEl.innerHTML = [ '<div style="display: none;">', ' <div class="carousel" data-interval="false"></div>', '</div>' ].join('') const carouselEl = fixtureEl.querySelector('.carousel') const carousel = new Carousel(carouselEl)
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
spyOn(carousel, 'next') carousel.nextWhenVisible() expect(carousel.next).not.toHaveBeenCalled() }) }) describe('prev', () => { it('should not slide if the carousel is sliding', () => { fixtureEl.innerHTML = '<div></div>' const carouselEl = fixtureEl.querySelector('div') const carousel = new Carousel(carouselEl, {}) spyOn(carousel, '_slide') carousel._isSliding = true carousel.prev() expect(carousel._slide).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')
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
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) }) }) describe('cycle', () => { it('should set an interval', () => { 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.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('')
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
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() }) it('should clear interval if there is one', () => { 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) carousel._interval = setInterval(() => {}, 10) spyOn(window, 'setInterval').and.callThrough() spyOn(window, 'clearInterval').and.callThrough() carousel.cycle() expect(window.setInterval).toHaveBeenCalled() expect(window.clearInterval).toHaveBeenCalled() }) }) describe('to', () => { it('should go directement 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, {}) expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1')) carousel.to(2) carouselEl.addEventListener('slid.bs.carousel', () => { expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3')) done() }) }) 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>',
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
' <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, {}) expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3')) carousel.to(1) carouselEl.addEventListener('slid.bs.carousel', () => { expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) done() }) }) it('should do nothing if a wrong index is provided', () => { 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-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 spy = spyOn(carousel, '_slide') carousel.to(25) expect(spy).not.toHaveBeenCalled() spy.calls.reset() carousel.to(-5) expect(spy).not.toHaveBeenCalled() }) it('should call pause and cycle is the provided is the same compare to the current one', () => { 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-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, {}) spyOn(carousel, '_slide') spyOn(carousel, 'pause') spyOn(carousel, 'cycle') carousel.to(0) expect(carousel._slide).not.toHaveBeenCalled() expect(carousel.pause).toHaveBeenCalled() expect(carousel.cycle).toHaveBeenCalled() })
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
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-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, {}) spyOn(EventHandler, 'one').and.callThrough() spyOn(carousel, '_slide') carousel._isSliding = true carousel.to(1) expect(carousel._slide).not.toHaveBeenCalled() expect(EventHandler.one).toHaveBeenCalled() spyOn(carousel, 'to') EventHandler.trigger(carouselEl, 'slid.bs.carousel') setTimeout(() => { expect(carousel.to).toHaveBeenCalledWith(1) done() }) }) }) describe('dispose', () => { it('should destroy a carousel', () => { 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-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) spyOn(EventHandler, 'off').and.callThrough() carousel.dispose() expect(EventHandler.off).toHaveBeenCalled() }) }) describe('jQueryInterface', () => { it('should create a carousel', () => { fixtureEl.innerHTML = '<div></div>' const div = fixtureEl.querySelector('div') jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] jQueryMock.fn.carousel.call(jQueryMock) expect(Carousel.getInstance(div)).toBeDefined()
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
}) it('should not re create a carousel', () => { fixtureEl.innerHTML = '<div></div>' const div = fixtureEl.querySelector('div') const carousel = new Carousel(div) jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] jQueryMock.fn.carousel.call(jQueryMock) expect(Carousel.getInstance(div)).toEqual(carousel) }) it('should call to if the config is a number', () => { fixtureEl.innerHTML = '<div></div>' const div = fixtureEl.querySelector('div') const carousel = new Carousel(div) const slideTo = 2 spyOn(carousel, 'to') jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] jQueryMock.fn.carousel.call(jQueryMock, slideTo) expect(carousel.to).toHaveBeenCalledWith(slideTo) }) it('should throw error on undefined method', () => { fixtureEl.innerHTML = '<div></div>' const div = fixtureEl.querySelector('div') const action = 'undefinedMethod' jQueryMock.fn.carousel = Carousel.jQueryInterface jQueryMock.elements = [div] try { jQueryMock.fn.carousel.call(jQueryMock, action) } catch (error) { expect(error.message).toEqual(`No method named "${action}"`) } }) }) describe('data-api', () => { it('should init carousels with data-ride="carousel" on load', () => { fixtureEl.innerHTML = '<div data-ride="carousel"></div>' const carouselEl = fixtureEl.querySelector('div') const loadEvent = createEvent('load') window.dispatchEvent(loadEvent) expect(Carousel.getInstance(carouselEl)).toBeDefined() }) it('should create carousel and go to the next slide on click', 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>',
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
' <div class="carousel-control-prev" data-target="#myCarousel" role="button" data-slide="prev"></div>', ' <div id="next" class="carousel-control-next" data-target="#myCarousel" role="button" data-slide="next"></div>', '</div>' ].join('') const next = fixtureEl.querySelector('#next') const item2 = fixtureEl.querySelector('#item2') next.click() setTimeout(() => { expect(item2.classList.contains('active')).toEqual(true) done() }, 10) }) it('should create carousel and go to the next slide on click with data-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-target="#myCarousel" data-slide-to="1"></div>', '</div>' ].join('') const next = fixtureEl.querySelector('#next') const item2 = fixtureEl.querySelector('#item2') next.click() setTimeout(() => { expect(item2.classList.contains('active')).toEqual(true) done() }, 10) }) it('should do nothing if no selector on click on arrows', () => { 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" data-target="#myCarousel" role="button" data-slide="prev"></div>', ' <div id="next" class="carousel-control-next" role="button" data-slide="next"></div>', '</div>' ].join('') const next = fixtureEl.querySelector('#next') next.click() expect().nothing() }) it('should do nothing if no carousel class on click on arrows', () => { fixtureEl.innerHTML = [ '<div id="myCarousel" class="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 class="carousel-control-prev" data-target="#myCarousel" role="button" data-slide="prev"></div>', ' <div id="next" class="carousel-control-next" data-target="#myCarousel" role="button" data-slide="next"></div>', '</div>'
11911192119311941195119611971198119912001201
].join('') const next = fixtureEl.querySelector('#next') next.click() expect().nothing() }) }) })