diff options
Diffstat (limited to 'js/src/carousel')
| -rw-r--r-- | js/src/carousel/carousel.js | 637 | ||||
| -rw-r--r-- | js/src/carousel/carousel.spec.js | 1201 |
2 files changed, 0 insertions, 1838 deletions
diff --git a/js/src/carousel/carousel.js b/js/src/carousel/carousel.js deleted file mode 100644 index 723bf57c6..000000000 --- a/js/src/carousel/carousel.js +++ /dev/null @@ -1,637 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.3.1): carousel.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * -------------------------------------------------------------------------- - */ - -import { - getjQuery, - TRANSITION_END, - emulateTransitionEnd, - getElementFromSelector, - getTransitionDurationFromElement, - isVisible, - makeArray, - reflow, - triggerTransitionEnd, - typeCheckConfig -} from '../util/index' -import Data from '../dom/data' -import EventHandler from '../dom/event-handler' -import Manipulator from '../dom/manipulator' -import SelectorEngine from '../dom/selector-engine' - -/** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - -const NAME = 'carousel' -const VERSION = '4.3.1' -const DATA_KEY = 'bs.carousel' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key -const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key -const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch -const SWIPE_THRESHOLD = 40 - -const Default = { - interval: 5000, - keyboard: true, - slide: false, - pause: 'hover', - wrap: true, - touch: true -} - -const DefaultType = { - interval: '(number|boolean)', - keyboard: 'boolean', - slide: '(boolean|string)', - pause: '(string|boolean)', - wrap: 'boolean', - touch: 'boolean' -} - -const Direction = { - NEXT: 'next', - PREV: 'prev', - LEFT: 'left', - RIGHT: 'right' -} - -const Event = { - SLIDE: `slide${EVENT_KEY}`, - SLID: `slid${EVENT_KEY}`, - KEYDOWN: `keydown${EVENT_KEY}`, - MOUSEENTER: `mouseenter${EVENT_KEY}`, - MOUSELEAVE: `mouseleave${EVENT_KEY}`, - TOUCHSTART: `touchstart${EVENT_KEY}`, - TOUCHMOVE: `touchmove${EVENT_KEY}`, - TOUCHEND: `touchend${EVENT_KEY}`, - POINTERDOWN: `pointerdown${EVENT_KEY}`, - POINTERUP: `pointerup${EVENT_KEY}`, - DRAG_START: `dragstart${EVENT_KEY}`, - LOAD_DATA_API: `load${EVENT_KEY}${DATA_API_KEY}`, - CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}` -} - -const ClassName = { - CAROUSEL: 'carousel', - ACTIVE: 'active', - SLIDE: 'slide', - RIGHT: 'carousel-item-right', - LEFT: 'carousel-item-left', - NEXT: 'carousel-item-next', - PREV: 'carousel-item-prev', - ITEM: 'carousel-item', - POINTER_EVENT: 'pointer-event' -} - -const Selector = { - ACTIVE: '.active', - ACTIVE_ITEM: '.active.carousel-item', - ITEM: '.carousel-item', - ITEM_IMG: '.carousel-item img', - NEXT_PREV: '.carousel-item-next, .carousel-item-prev', - INDICATORS: '.carousel-indicators', - DATA_SLIDE: '[data-slide], [data-slide-to]', - DATA_RIDE: '[data-ride="carousel"]' -} - -const PointerType = { - TOUCH: 'touch', - PEN: 'pen' -} - -/** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ -class Carousel { - constructor(element, config) { - this._items = null - this._interval = null - this._activeElement = null - this._isPaused = false - this._isSliding = false - this.touchTimeout = null - this.touchStartX = 0 - this.touchDeltaX = 0 - - this._config = this._getConfig(config) - this._element = element - this._indicatorsElement = SelectorEngine.findOne(Selector.INDICATORS, this._element) - this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 - this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) - - this._addEventListeners() - Data.setData(element, DATA_KEY, this) - } - - // Getters - - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - // Public - - next() { - if (!this._isSliding) { - this._slide(Direction.NEXT) - } - } - - nextWhenVisible() { - // Don't call next when the page isn't visible - // or the carousel or its parent isn't visible - if (!document.hidden && isVisible(this._element)) { - this.next() - } - } - - prev() { - if (!this._isSliding) { - this._slide(Direction.PREV) - } - } - - pause(event) { - if (!event) { - this._isPaused = true - } - - if (SelectorEngine.findOne(Selector.NEXT_PREV, this._element)) { - triggerTransitionEnd(this._element) - this.cycle(true) - } - - clearInterval(this._interval) - this._interval = null - } - - cycle(event) { - if (!event) { - this._isPaused = false - } - - if (this._interval) { - clearInterval(this._interval) - this._interval = null - } - - if (this._config && this._config.interval && !this._isPaused) { - this._interval = setInterval( - (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), - this._config.interval - ) - } - } - - to(index) { - this._activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element) - const activeIndex = this._getItemIndex(this._activeElement) - - if (index > this._items.length - 1 || index < 0) { - return - } - - if (this._isSliding) { - EventHandler.one(this._element, Event.SLID, () => this.to(index)) - return - } - - if (activeIndex === index) { - this.pause() - this.cycle() - return - } - - const direction = index > activeIndex ? - Direction.NEXT : - Direction.PREV - - this._slide(direction, this._items[index]) - } - - dispose() { - EventHandler.off(this._element, EVENT_KEY) - Data.removeData(this._element, DATA_KEY) - - this._items = null - this._config = null - this._element = null - this._interval = null - this._isPaused = null - this._isSliding = null - this._activeElement = null - this._indicatorsElement = null - } - - // Private - - _getConfig(config) { - config = { - ...Default, - ...config - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - - _handleSwipe() { - const absDeltax = Math.abs(this.touchDeltaX) - - if (absDeltax <= SWIPE_THRESHOLD) { - return - } - - const direction = absDeltax / this.touchDeltaX - - this.touchDeltaX = 0 - - // swipe left - if (direction > 0) { - this.prev() - } - - // swipe right - if (direction < 0) { - this.next() - } - } - - _addEventListeners() { - if (this._config.keyboard) { - EventHandler - .on(this._element, Event.KEYDOWN, event => this._keydown(event)) - } - - if (this._config.pause === 'hover') { - EventHandler - .on(this._element, Event.MOUSEENTER, event => this.pause(event)) - EventHandler - .on(this._element, Event.MOUSELEAVE, event => this.cycle(event)) - } - - if (this._config.touch && this._touchSupported) { - this._addTouchEventListeners() - } - } - - _addTouchEventListeners() { - const start = event => { - if (this._pointerEvent && PointerType[event.pointerType.toUpperCase()]) { - this.touchStartX = event.clientX - } else if (!this._pointerEvent) { - this.touchStartX = event.touches[0].clientX - } - } - - const move = event => { - // ensure swiping with one touch and not pinching - if (event.touches && event.touches.length > 1) { - this.touchDeltaX = 0 - } else { - this.touchDeltaX = event.touches[0].clientX - this.touchStartX - } - } - - const end = event => { - if (this._pointerEvent && PointerType[event.pointerType.toUpperCase()]) { - this.touchDeltaX = event.clientX - this.touchStartX - } - - this._handleSwipe() - if (this._config.pause === 'hover') { - // If it's a touch-enabled device, mouseenter/leave are fired as - // part of the mouse compatibility events on first tap - the carousel - // would stop cycling until user tapped out of it; - // here, we listen for touchend, explicitly pause the carousel - // (as if it's the second time we tap on it, mouseenter compat event - // is NOT fired) and after a timeout (to allow for mouse compatibility - // events to fire) we explicitly restart cycling - - this.pause() - if (this.touchTimeout) { - clearTimeout(this.touchTimeout) - } - - this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) - } - } - - makeArray(SelectorEngine.find(Selector.ITEM_IMG, this._element)).forEach(itemImg => { - EventHandler.on(itemImg, Event.DRAG_START, e => e.preventDefault()) - }) - - if (this._pointerEvent) { - EventHandler.on(this._element, Event.POINTERDOWN, event => start(event)) - EventHandler.on(this._element, Event.POINTERUP, event => end(event)) - - this._element.classList.add(ClassName.POINTER_EVENT) - } else { - EventHandler.on(this._element, Event.TOUCHSTART, event => start(event)) - EventHandler.on(this._element, Event.TOUCHMOVE, event => move(event)) - EventHandler.on(this._element, Event.TOUCHEND, event => end(event)) - } - } - - _keydown(event) { - if (/input|textarea/i.test(event.target.tagName)) { - return - } - - switch (event.which) { - case ARROW_LEFT_KEYCODE: - event.preventDefault() - this.prev() - break - case ARROW_RIGHT_KEYCODE: - event.preventDefault() - this.next() - break - default: - } - } - - _getItemIndex(element) { - this._items = element && element.parentNode ? - makeArray(SelectorEngine.find(Selector.ITEM, element.parentNode)) : - [] - - return this._items.indexOf(element) - } - - _getItemByDirection(direction, activeElement) { - const isNextDirection = direction === Direction.NEXT - const isPrevDirection = direction === Direction.PREV - const activeIndex = this._getItemIndex(activeElement) - const lastItemIndex = this._items.length - 1 - const isGoingToWrap = (isPrevDirection && activeIndex === 0) || - (isNextDirection && activeIndex === lastItemIndex) - - if (isGoingToWrap && !this._config.wrap) { - return activeElement - } - - const delta = direction === Direction.PREV ? -1 : 1 - const itemIndex = (activeIndex + delta) % this._items.length - - return itemIndex === -1 ? - this._items[this._items.length - 1] : - this._items[itemIndex] - } - - _triggerSlideEvent(relatedTarget, eventDirectionName) { - const targetIndex = this._getItemIndex(relatedTarget) - const fromIndex = this._getItemIndex(SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element)) - - return EventHandler.trigger(this._element, Event.SLIDE, { - relatedTarget, - direction: eventDirectionName, - from: fromIndex, - to: targetIndex - }) - } - - _setActiveIndicatorElement(element) { - if (this._indicatorsElement) { - const indicators = SelectorEngine.find(Selector.ACTIVE, this._indicatorsElement) - for (let i = 0; i < indicators.length; i++) { - indicators[i].classList.remove(ClassName.ACTIVE) - } - - const nextIndicator = this._indicatorsElement.children[ - this._getItemIndex(element) - ] - - if (nextIndicator) { - nextIndicator.classList.add(ClassName.ACTIVE) - } - } - } - - _slide(direction, element) { - const activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element) - const activeElementIndex = this._getItemIndex(activeElement) - const nextElement = element || (activeElement && - this._getItemByDirection(direction, activeElement)) - - const nextElementIndex = this._getItemIndex(nextElement) - const isCycling = Boolean(this._interval) - - let directionalClassName - let orderClassName - let eventDirectionName - - if (direction === Direction.NEXT) { - directionalClassName = ClassName.LEFT - orderClassName = ClassName.NEXT - eventDirectionName = Direction.LEFT - } else { - directionalClassName = ClassName.RIGHT - orderClassName = ClassName.PREV - eventDirectionName = Direction.RIGHT - } - - if (nextElement && nextElement.classList.contains(ClassName.ACTIVE)) { - this._isSliding = false - return - } - - const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) - if (slideEvent.defaultPrevented) { - return - } - - if (!activeElement || !nextElement) { - // Some weirdness is happening, so we bail - return - } - - this._isSliding = true - - if (isCycling) { - this.pause() - } - - this._setActiveIndicatorElement(nextElement) - - if (this._element.classList.contains(ClassName.SLIDE)) { - nextElement.classList.add(orderClassName) - - reflow(nextElement) - - activeElement.classList.add(directionalClassName) - nextElement.classList.add(directionalClassName) - - const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10) - if (nextElementInterval) { - this._config.defaultInterval = this._config.defaultInterval || this._config.interval - this._config.interval = nextElementInterval - } else { - this._config.interval = this._config.defaultInterval || this._config.interval - } - - const transitionDuration = getTransitionDurationFromElement(activeElement) - - EventHandler - .one(activeElement, TRANSITION_END, () => { - nextElement.classList.remove(directionalClassName) - nextElement.classList.remove(orderClassName) - nextElement.classList.add(ClassName.ACTIVE) - - activeElement.classList.remove(ClassName.ACTIVE) - activeElement.classList.remove(orderClassName) - activeElement.classList.remove(directionalClassName) - - this._isSliding = false - - setTimeout(() => { - EventHandler.trigger(this._element, Event.SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) - }, 0) - }) - - emulateTransitionEnd(activeElement, transitionDuration) - } else { - activeElement.classList.remove(ClassName.ACTIVE) - nextElement.classList.add(ClassName.ACTIVE) - - this._isSliding = false - EventHandler.trigger(this._element, Event.SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) - } - - if (isCycling) { - this.cycle() - } - } - - // Static - - static carouselInterface(element, config) { - let data = Data.getData(element, DATA_KEY) - let _config = { - ...Default, - ...Manipulator.getDataAttributes(element) - } - - if (typeof config === 'object') { - _config = { - ..._config, - ...config - } - } - - const action = typeof config === 'string' ? config : _config.slide - - if (!data) { - data = new Carousel(element, _config) - } - - if (typeof config === 'number') { - data.to(config) - } else if (typeof action === 'string') { - if (typeof data[action] === 'undefined') { - throw new TypeError(`No method named "${action}"`) - } - - data[action]() - } else if (_config.interval && _config.ride) { - data.pause() - data.cycle() - } - } - - static jQueryInterface(config) { - return this.each(function () { - Carousel.carouselInterface(this, config) - }) - } - - static dataApiClickHandler(event) { - const target = getElementFromSelector(this) - - if (!target || !target.classList.contains(ClassName.CAROUSEL)) { - return - } - - const config = { - ...Manipulator.getDataAttributes(target), - ...Manipulator.getDataAttributes(this) - } - const slideIndex = this.getAttribute('data-slide-to') - - if (slideIndex) { - config.interval = false - } - - Carousel.carouselInterface(target, config) - - if (slideIndex) { - Data.getData(target, DATA_KEY).to(slideIndex) - } - - event.preventDefault() - } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } -} - -/** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - -EventHandler - .on(document, Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel.dataApiClickHandler) - -EventHandler.on(window, Event.LOAD_DATA_API, () => { - const carousels = makeArray(SelectorEngine.find(Selector.DATA_RIDE)) - for (let i = 0, len = carousels.length; i < len; i++) { - Carousel.carouselInterface(carousels[i], Data.getData(carousels[i], DATA_KEY)) - } -}) - -const $ = getjQuery() - -/** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - * add .carousel to jQuery only if jQuery is present - */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Carousel.jQueryInterface - $.fn[NAME].Constructor = Carousel - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Carousel.jQueryInterface - } -} - -export default Carousel diff --git a/js/src/carousel/carousel.spec.js b/js/src/carousel/carousel.spec.js deleted file mode 100644 index 4c13b6d22..000000000 --- a/js/src/carousel/carousel.spec.js +++ /dev/null @@ -1,1201 +0,0 @@ -import Carousel from './carousel' -import EventHandler from '../dom/event-handler' - -/** Test helpers */ -import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture' - -describe('Carousel', () => { - const { Simulator, PointerEvent, MSPointerEvent } = window - const originWinPointerEvent = PointerEvent || MSPointerEvent - const supportPointerEvent = Boolean(PointerEvent || MSPointerEvent) - - window.MSPointerEvent = null - const cssStyleCarousel = '.carousel.pointer-event { -ms-touch-action: none; 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() - }) - - const keyDown = createEvent('keydown') - keyDown.which = 39 - - 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.which = 37 - - 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.which = 40 - - carouselEl.dispatchEvent(keyDown) - }) - - it('should ignore keyboard events within <input>s and <textarea>s', () => { - fixtureEl.innerHTML = [ - '<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.which = 39 - 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() - - 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) - - 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() - 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 - 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() - }) - }) - - 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() - }) - - 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 => { - 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) - - 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') - - 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('') - - 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>', - ' <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() - }) - - 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() - }) - - 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>', - ' <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>' - ].join('') - - const next = fixtureEl.querySelector('#next') - - next.click() - - expect().nothing() - }) - }) -}) |
