diff options
author | Johann-S <johann.servoire@gmail.com> | 2019-03-27 13:58:00 +0300 |
---|---|---|
committer | Johann-S <johann.servoire@gmail.com> | 2019-07-23 15:23:50 +0300 |
commit | 62730d9afd4e208ab9b490a073ab6426463e41b6 (patch) | |
tree | d105f488d2cf5c9aef81efbc0e4ea8d2e690488b /js | |
parent | 747f0f4c7b01a3900c163bb9b11715fa2380faea (diff) |
rewrite carousel unit tests
Diffstat (limited to 'js')
-rw-r--r-- | js/index.esm.js | 2 | ||||
-rw-r--r-- | js/index.umd.js | 2 | ||||
-rw-r--r-- | js/src/carousel/carousel.js (renamed from js/src/carousel.js) | 18 | ||||
-rw-r--r-- | js/src/carousel/carousel.spec.js | 1197 | ||||
-rw-r--r-- | js/tests/karma.conf.js | 4 | ||||
-rw-r--r-- | js/tests/unit/carousel.js | 1370 |
6 files changed, 1209 insertions, 1384 deletions
diff --git a/js/index.esm.js b/js/index.esm.js index ca47d7405e..4f5058560d 100644 --- a/js/index.esm.js +++ b/js/index.esm.js @@ -7,7 +7,7 @@ import Alert from './src/alert/alert' import Button from './src/button/button' -import Carousel from './src/carousel' +import Carousel from './src/carousel/carousel' import Collapse from './src/collapse' import Dropdown from './src/dropdown' import Modal from './src/modal' diff --git a/js/index.umd.js b/js/index.umd.js index 2cb90696da..f3b81377e5 100644 --- a/js/index.umd.js +++ b/js/index.umd.js @@ -7,7 +7,7 @@ import Alert from './src/alert/alert' import Button from './src/button/button' -import Carousel from './src/carousel' +import Carousel from './src/carousel/carousel' import Collapse from './src/collapse' import Dropdown from './src/dropdown' import Modal from './src/modal' diff --git a/js/src/carousel.js b/js/src/carousel/carousel.js index 7cd790f85d..0e1bad14ac 100644 --- a/js/src/carousel.js +++ b/js/src/carousel/carousel.js @@ -16,11 +16,11 @@ import { 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' +} 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' /** * ------------------------------------------------------------------------ @@ -283,16 +283,12 @@ class Carousel { .on(this._element, Event.MOUSELEAVE, event => this.cycle(event)) } - if (this._config.touch) { + if (this._config.touch && this._touchSupported) { this._addTouchEventListeners() } } _addTouchEventListeners() { - if (!this._touchSupported) { - return - } - const start = event => { if (this._pointerEvent && PointerType[event.pointerType.toUpperCase()]) { this.touchStartX = event.clientX @@ -631,7 +627,7 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => { * ------------------------------------------------------------------------ * add .carousel to jQuery only if jQuery is present */ - +/* istanbul ignore if */ if (typeof $ !== 'undefined') { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Carousel._jQueryInterface diff --git a/js/src/carousel/carousel.spec.js b/js/src/carousel/carousel.spec.js new file mode 100644 index 0000000000..9f897110d5 --- /dev/null +++ b/js/src/carousel/carousel.spec.js @@ -0,0 +1,1197 @@ +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 class="carousel" data-interval="false"></div>' + + const carouselEl = fixtureEl.querySelector('div') + 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() + }) + }) +}) diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index b5b9fb3736..00bf5d8d35 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -74,7 +74,9 @@ const rollupPreprocessor = { } } -let files = [] +let files = [ + 'node_modules/hammer-simulator/index.js' +] const conf = { basePath: '../..', diff --git a/js/tests/unit/carousel.js b/js/tests/unit/carousel.js deleted file mode 100644 index f92d87c612..0000000000 --- a/js/tests/unit/carousel.js +++ /dev/null @@ -1,1370 +0,0 @@ -$(function () { - 'use strict' - - window.Carousel = typeof bootstrap === 'undefined' ? Carousel : bootstrap.Carousel - - var originWinPointerEvent = window.PointerEvent - window.MSPointerEvent = null - var supportPointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) - - function clearPointerEvents() { - window.PointerEvent = null - } - - function restorePointerEvents() { - window.PointerEvent = originWinPointerEvent - } - - var stylesCarousel = [ - '<style>', - ' .carousel.pointer-event { -ms-touch-action: none; touch-action: none; }', - '</style>' - ].join('') - - QUnit.module('carousel plugin') - - QUnit.test('should be defined on jQuery object', function (assert) { - assert.expect(1) - assert.ok($(document.body).carousel, 'carousel method is defined') - }) - - QUnit.module('carousel', { - beforeEach: function () { - // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode - $.fn.bootstrapCarousel = $.fn.carousel.noConflict() - }, - afterEach: function () { - $('.carousel').bootstrapCarousel('dispose') - $.fn.carousel = $.fn.bootstrapCarousel - delete $.fn.bootstrapCarousel - $('#qunit-fixture').html('') - } - }) - - QUnit.test('should provide no conflict', function (assert) { - assert.expect(1) - assert.strictEqual(typeof $.fn.carousel, 'undefined', 'carousel was set back to undefined (orig value)') - }) - - QUnit.test('should return the version', function (assert) { - assert.expect(1) - assert.strictEqual(typeof Carousel.VERSION, 'string') - }) - - QUnit.test('should return default parameters', function (assert) { - assert.expect(1) - - var defaultConfig = Carousel.Default - - assert.strictEqual(defaultConfig.touch, true) - }) - - QUnit.test('should throw explicit error on undefined method', function (assert) { - assert.expect(1) - var $el = $('<div/>') - $el.bootstrapCarousel() - try { - $el.bootstrapCarousel('noMethod') - } catch (error) { - assert.strictEqual(error.message, 'No method named "noMethod"') - } - }) - - QUnit.test('should return jquery collection containing the element', function (assert) { - assert.expect(2) - var $el = $('<div/>') - var $carousel = $el.bootstrapCarousel() - assert.ok($carousel instanceof $, 'returns jquery collection') - assert.strictEqual($carousel[0], $el[0], 'collection contains element') - }) - - QUnit.test('should type check config options', function (assert) { - assert.expect(2) - - var message - var expectedMessage = 'CAROUSEL: Option "interval" provided type "string" but expected type "(number|boolean)".' - var config = { - interval: 'fat sux' - } - - try { - $('<div/>').bootstrapCarousel(config) - } catch (error) { - message = error.message - } - - assert.ok(message === expectedMessage, 'correct error message') - - config = { - keyboard: document.createElement('div') - } - expectedMessage = 'CAROUSEL: Option "keyboard" provided type "element" but expected type "boolean".' - - try { - $('<div/>').bootstrapCarousel(config) - } catch (error) { - message = error.message - } - - assert.ok(message === expectedMessage, 'correct error message') - }) - - QUnit.test('should not fire slid when slide is prevented', function (assert) { - assert.expect(1) - var done = assert.async() - var $carousel = $('<div class="carousel"/>') - $carousel.appendTo('#qunit-fixture') - - $carousel[0].addEventListener('slide.bs.carousel', function (e) { - e.preventDefault() - assert.ok(true, 'slide event fired') - done() - }) - $carousel[0].addEventListener('slid.bs.carousel', function () { - assert.ok(false, 'slid event fired') - }) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should reset when slide is prevented', function (assert) { - assert.expect(6) - var carouselHTML = '<div id="carousel-example-generic" class="carousel slide">' + - '<ol class="carousel-indicators">' + - '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + - '</ol>' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item">' + - '<div class="carousel-caption"/>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + - '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + - '</div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - - var done = assert.async() - function onSlide(e) { - e.preventDefault() - setTimeout(function () { - assert.ok($carousel.find('.carousel-item:nth-child(1)').is('.active'), 'first item still active') - assert.ok($carousel.find('.carousel-indicators li:nth-child(1)').is('.active'), 'first indicator still active') - $carousel.bootstrapCarousel('next') - }, 0) - $carousel[0].removeEventListener('slide.bs.carousel', onSlide) - } - - $carousel[0].addEventListener('slide.bs.carousel', onSlide) - - function onSlid() { - setTimeout(function () { - assert.ok(!$carousel.find('.carousel-item:nth-child(1)').is('.active'), 'first item still active') - assert.ok(!$carousel.find('.carousel-indicators li:nth-child(1)').is('.active'), 'first indicator still active') - assert.ok($carousel.find('.carousel-item:nth-child(2)').is('.active'), 'second item active') - assert.ok($carousel.find('.carousel-indicators li:nth-child(2)').is('.active'), 'second indicator active') - done() - }, 0) - $carousel[0].removeEventListener('slid.bs.carousel', onSlid) - } - - $carousel[0].addEventListener('slid.bs.carousel', onSlid) - - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should fire slide event with direction', function (assert) { - assert.expect(4) - var carouselHTML = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - - var done = assert.async() - - function onSlide(e) { - assert.ok(e.direction, 'direction present on next') - assert.strictEqual(e.direction, 'left', 'direction is left on next') - - $carousel[0].addEventListener('slide.bs.carousel', onSlide2) - $carousel[0].removeEventListener('slide.bs.carousel', onSlide) - $carousel.bootstrapCarousel('prev') - } - - function onSlide2(e) { - assert.ok(e.direction, 'direction present on prev') - assert.strictEqual(e.direction, 'right', 'direction is right on prev') - done() - } - - $carousel[0].addEventListener('slide.bs.carousel', onSlide) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should fire slid event with direction', function (assert) { - assert.expect(4) - var carouselHTML = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - - var done = assert.async() - - function onSlid(e) { - assert.ok(e.direction, 'direction present on next') - assert.strictEqual(e.direction, 'left', 'direction is left on next') - - $carousel[0].addEventListener('slid.bs.carousel', onSlid2) - $carousel[0].removeEventListener('slid.bs.carousel', onSlid) - $carousel.bootstrapCarousel('prev') - } - - function onSlid2(e) { - assert.ok(e.direction, 'direction present on prev') - assert.strictEqual(e.direction, 'right', 'direction is right on prev') - $carousel[0].removeEventListener('slid.bs.carousel', onSlid2) - done() - } - - $carousel[0].addEventListener('slid.bs.carousel', onSlid) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should fire slide event with relatedTarget', function (assert) { - assert.expect(2) - var template = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - - var done = assert.async() - var $carousel = $(template) - $carousel.appendTo('#qunit-fixture') - - function onSlide(e) { - assert.ok(e.relatedTarget, 'relatedTarget present') - assert.ok($(e.relatedTarget).hasClass('carousel-item'), 'relatedTarget has class "item"') - $carousel[0].removeEventListener('slide.bs.carousel', onSlide) - done() - } - - $carousel[0].addEventListener('slide.bs.carousel', onSlide) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should fire slid event with relatedTarget', function (assert) { - assert.expect(2) - var template = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - - var done = assert.async() - var $carousel = $(template) - $carousel.appendTo('#qunit-fixture') - - $carousel[0].addEventListener('slid.bs.carousel', function (e) { - assert.ok(e.relatedTarget, 'relatedTarget present') - assert.ok($(e.relatedTarget).hasClass('carousel-item'), 'relatedTarget has class "item"') - done() - }) - - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should fire slid and slide events with from and to', function (assert) { - assert.expect(4) - var template = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - - var done = assert.async() - var $carousel = $(template) - - $carousel[0].addEventListener('slid.bs.carousel', function (e) { - assert.ok(typeof e.from !== 'undefined', 'from present') - assert.ok(typeof e.to !== 'undefined', 'to present') - done() - }) - - $carousel[0].addEventListener('slide.bs.carousel', function (e) { - assert.ok(typeof e.from !== 'undefined', 'from present') - assert.ok(typeof e.to !== 'undefined', 'to present') - }) - - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should set interval from data attribute', function (assert) { - assert.expect(4) - var templateHTML = '<div id="myCarousel" class="carousel slide">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - var $carousel = $(templateHTML) - $carousel.attr('data-interval', 1814) - - $carousel.appendTo('body') - $('[data-slide]').first()[0].dispatchEvent(new Event('click')) - assert.strictEqual(Carousel._getInstance($carousel[0])._config.interval, 1814) - $carousel.remove() - - $carousel.appendTo('body').attr('data-modal', 'foobar') - $('[data-slide]').first()[0].dispatchEvent(new Event('click')) - assert.strictEqual(Carousel._getInstance($carousel[0])._config.interval, 1814, 'even if there is an data-modal attribute set') - $carousel.remove() - - $carousel.appendTo('body') - $('[data-slide]').first()[0].dispatchEvent(new Event('click')) - $carousel.attr('data-interval', 1860) - - $('[data-slide]').first()[0].dispatchEvent(new Event('click')) - assert.strictEqual(Carousel._getInstance($carousel[0])._config.interval, 1814, 'attributes should be read only on initialization') - $carousel.bootstrapCarousel('dispose') - $carousel.remove() - - $carousel.attr('data-interval', false) - $carousel.appendTo('body') - $carousel.bootstrapCarousel(1) - assert.strictEqual(Carousel._getInstance($carousel[0])._config.interval, false, 'data attribute has higher priority than default options') - $carousel.remove() - }) - - QUnit.test('should set interval from data attribute on individual carousel-item', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel slide" data-interval="1814">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active" data-interval="2814">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>First Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item" data-interval="3814">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Second Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '<div class="carousel-item">' + - '<img alt="">' + - '<div class="carousel-caption">' + - '<h4>Third Thumbnail label</h4>' + - '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + - 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + - 'ultricies vehicula ut id elit.</p>' + - '</div>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - - var $carousel = $(templateHTML).appendTo('#qunit-fixture') - $carousel.bootstrapCarousel(1) - var carousel = Carousel._getInstance($carousel[0]) - assert.strictEqual(carousel._config.interval, 3814) - carousel.dispose() - $carousel.remove() - - $carousel = $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel(2) - carousel = Carousel._getInstance($carousel[0]) - - assert.strictEqual(carousel._config.interval, 1814, 'reverts to default interval if no data-interval is set') - $carousel.remove() - }) - - QUnit.test('should skip over non-items when using item indices', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="1814">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '<script type="text/x-metamorph" id="thingy"/>' + - '<div class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div class="carousel-item">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - - $template.bootstrapCarousel(1) - - assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active') - }) - - QUnit.test('should skip over non-items when using next/prev methods', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="1814">' + - '<div class="carousel-inner">' + - '<div class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '<script type="text/x-metamorph" id="thingy"/>' + - '<div class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div class="carousel-item">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - - $template.bootstrapCarousel('next') - - assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active') - }) - - QUnit.test('should go to previous item if left arrow key is pressed', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div id="second" class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '<div id="third" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active') - - var keyDown = new Event('keydown') - keyDown.which = 37 - $template[0].dispatchEvent(keyDown) - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - }) - - QUnit.test('should go to next item if right arrow key is pressed', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '<div id="second" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div id="third" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - - var keyDown = new Event('keydown') - keyDown.which = 39 - $template[0].dispatchEvent(keyDown) - - assert.strictEqual($template.find('.carousel-item')[1], $template.find('.active')[0], 'second item active') - }) - - QUnit.test('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - var done = assert.async() - - function handlerKeydown(event) { - assert.strictEqual(event.defaultPrevented, false) - $template[0].removeEventListener('keydown', handlerKeydown) - } - - $template[0].addEventListener('keydown', handlerKeydown) - - // arrow down - var keyDown = new Event('keydown') - keyDown.which = 40 - $template[0].dispatchEvent(keyDown) - - function handlerKeydown2(event) { - assert.strictEqual(event.defaultPrevented, false) - $template[0].addEventListener('keydown', handlerKeydown2) - done() - } - - $template[0].addEventListener('keydown', handlerKeydown2) - - // arrow up - var keyDown2 = new Event('keydown') - keyDown2.which = 38 - $template[0].dispatchEvent(keyDown2) - }) - - QUnit.test('should support disabling the keyboard navigation', function (assert) { - assert.expect(3) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false" data-keyboard="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item active">' + - '<img alt="">' + - '</div>' + - '<div id="second" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div id="third" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - - $template.trigger($.Event('keydown', { - which: 39 - })) - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after right arrow press') - - $template.trigger($.Event('keydown', { - which: 37 - })) - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after left arrow press') - }) - - QUnit.test('should ignore keyboard events within <input>s and <textarea>s', function (assert) { - assert.expect(7) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item active">' + - '<img alt="">' + - '<input type="text" id="in-put">' + - '<textarea id="text-area"></textarea>' + - '</div>' + - '<div id="second" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '<div id="third" class="carousel-item">' + - '<img alt="">' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - var $input = $template.find('#in-put') - var $textarea = $template.find('#text-area') - - assert.strictEqual($input.length, 1, 'found <input>') - assert.strictEqual($textarea.length, 1, 'found <textarea>') - - $template.bootstrapCarousel() - - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item active') - - $input.trigger($.Event('keydown', { - which: 39 - })) - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after right arrow press in <input>') - - $input.trigger($.Event('keydown', { - which: 37 - })) - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after left arrow press in <input>') - - $textarea.trigger($.Event('keydown', { - which: 39 - })) - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after right arrow press in <textarea>') - - $textarea.trigger($.Event('keydown', { - which: 37 - })) - assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after left arrow press in <textarea>') - }) - - QUnit.test('should wrap around from end to start when wrap option is true', function (assert) { - assert.expect(3) - var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="true">' + - '<ol class="carousel-indicators">' + - '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + - '</ol>' + - '<div class="carousel-inner">' + - '<div class="carousel-item active" id="one">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="two">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="three">' + - '<div class="carousel-caption"/>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + - '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + - '</div>' - var $carousel = $(carouselHTML) - var done = assert.async() - var getActiveId = function () { - return $carousel.find('.carousel-item.active').attr('id') - } - - $carousel[0].addEventListener('slid.bs.carousel', function () { - var activeId = getActiveId() - if (activeId === 'two') { - assert.strictEqual(activeId, 'two', 'carousel slid from 1st to 2nd slide') - $carousel.bootstrapCarousel('next') - return - } - - if (activeId === 'three') { - assert.strictEqual(activeId, 'three', 'carousel slid from 2nd to 3rd slide') - $carousel.bootstrapCarousel('next') - return - } - - if (activeId === 'one') { - assert.strictEqual(activeId, 'one', 'carousel wrapped around and slid from 3rd to 1st slide') - done() - } - }) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should wrap around from start to end when wrap option is true', function (assert) { - assert.expect(1) - var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="true">' + - '<ol class="carousel-indicators">' + - '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + - '</ol>' + - '<div class="carousel-inner">' + - '<div class="carousel-item active" id="one">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="two">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="three">' + - '<div class="carousel-caption"/>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + - '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + - '</div>' - var $carousel = $(carouselHTML) - - var done = assert.async() - - $carousel[0].addEventListener('slid.bs.carousel', function () { - assert.strictEqual($carousel.find('.carousel-item.active').attr('id'), 'three', 'carousel wrapped around and slid from 1st to 3rd slide') - done() - }) - $carousel.bootstrapCarousel('prev') - }) - - QUnit.test('should stay at the end when the next method is called and wrap is false', function (assert) { - assert.expect(3) - var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="false">' + - '<ol class="carousel-indicators">' + - '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + - '</ol>' + - '<div class="carousel-inner">' + - '<div class="carousel-item active" id="one">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="two">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="three">' + - '<div class="carousel-caption"/>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + - '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + - '</div>' - var $carousel = $(carouselHTML).appendTo('#qunit-fixture') - var getActiveId = function () { - return $carousel.find('.carousel-item.active').attr('id') - } - - var done = assert.async() - $carousel[0].addEventListener('slid.bs.carousel', function () { - var activeId = getActiveId() - if (activeId === 'two') { - assert.strictEqual(activeId, 'two', 'carousel slid from 1st to 2nd slide') - $carousel.bootstrapCarousel('next') - return - } - - if (activeId === 'three') { - assert.strictEqual(activeId, 'three', 'carousel slid from 2nd to 3rd slide') - $carousel.bootstrapCarousel('next') - assert.strictEqual(getActiveId(), 'three', 'carousel did not wrap around and stayed on 3rd slide') - done() - } - }) - $carousel.bootstrapCarousel('next') - }) - - QUnit.test('should stay at the start when the prev method is called and wrap is false', function (assert) { - assert.expect(1) - var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="false">' + - '<ol class="carousel-indicators">' + - '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + - '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + - '</ol>' + - '<div class="carousel-inner">' + - '<div class="carousel-item active" id="one">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="two">' + - '<div class="carousel-caption"/>' + - '</div>' + - '<div class="carousel-item" id="three">' + - '<div class="carousel-caption"/>' + - '</div>' + - '</div>' + - '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + - '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + - '</div>' - var $carousel = $(carouselHTML) - - $carousel[0].addEventListener('slid.bs.carousel', function () { - assert.ok(false, 'carousel slid when it should not have slid') - }) - $carousel.bootstrapCarousel('prev') - assert.strictEqual($carousel.find('.carousel-item.active').attr('id'), 'one', 'carousel did not wrap around and stayed on 1st slide') - }) - - QUnit.test('should not prevent keydown for inputs and textareas', function (assert) { - assert.expect(2) - var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + - '<div class="carousel-inner">' + - '<div id="first" class="carousel-item">' + - '<input type="text" id="inputText" />' + - '</div>' + - '<div id="second" class="carousel-item active">' + - '<textarea id="txtArea"></textarea>' + - '</div>' + - '</div>' + - '</div>' - var $template = $(templateHTML) - var done = assert.async() - $template.appendTo('#qunit-fixture') - var $inputText = $template.find('#inputText') - var $textArea = $template.find('#txtArea') - $template.bootstrapCarousel() - - var eventKeyDown = $.Event('keydown', { - which: 65 - }) // 65 for "a" - $inputText.on('keydown', function (event) { - assert.strictEqual(event.isDefaultPrevented(), false) - }) - $inputText.trigger(eventKeyDown) - - $textArea.on('keydown', function (event) { - assert.strictEqual(event.isDefaultPrevented(), false) - done() - }) - $textArea.trigger(eventKeyDown) - }) - - QUnit.test('should not go to the next item when the carousel is not visible', function (assert) { - assert.expect(2) - var done = assert.async() - var html = '<div id="myCarousel" class="carousel slide" data-interval="50" style="display: none;">' + - ' <div class="carousel-inner">' + - ' <div id="firstItem" class="carousel-item active">' + - ' <img alt="">' + - ' </div>' + - ' <div class="carousel-item">' + - ' <img alt="">' + - ' </div>' + - ' <div class="carousel-item">' + - ' <img alt="">' + - ' </div>' + - ' <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - ' <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - '</div>' - var $html = $(html) - $html - .appendTo('#qunit-fixture') - .bootstrapCarousel() - - var $firstItem = $('#firstItem') - setTimeout(function () { - assert.ok($firstItem.hasClass('active')) - $html - .bootstrapCarousel('dispose') - .attr('style', 'visibility: hidden;') - .bootstrapCarousel() - - setTimeout(function () { - assert.ok($firstItem.hasClass('active')) - done() - }, 80) - }, 80) - }) - - QUnit.test('should not go to the next item when the parent of the carousel is not visible', function (assert) { - assert.expect(2) - var done = assert.async() - var html = '<div id="parent" style="display: none;">' + - ' <div id="myCarousel" class="carousel slide" data-interval="50" style="display: none;">' + - ' <div class="carousel-inner">' + - ' <div id="firstItem" class="carousel-item active">' + - ' <img alt="">' + - ' </div>' + - ' <div class="carousel-item">' + - ' <img alt="">' + - ' </div>' + - ' <div class="carousel-item">' + - ' <img alt="">' + - ' </div>' + - ' <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + - ' <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + - ' </div>' + - '</div>' - var $html = $(html) - $html.appendTo('#qunit-fixture') - var $parent = $html.find('#parent') - var $carousel = $html.find('#myCarousel') - $carousel.bootstrapCarousel() - var $firstItem = $('#firstItem') - - setTimeout(function () { - assert.ok($firstItem.hasClass('active')) - $carousel.bootstrapCarousel('dispose') - $parent.attr('style', 'visibility: hidden;') - $carousel.bootstrapCarousel() - - setTimeout(function () { - assert.ok($firstItem.hasClass('active')) - done() - }, 80) - }, 80) - }) - - QUnit.test('should allow swiperight and call prev with pointer events', function (assert) { - if (!supportPointerEvent) { - assert.expect(0) - return - } - - document.documentElement.ontouchstart = $.noop - Simulator.setType('pointer') - assert.expect(3) - var $styles = $(stylesCarousel).appendTo('head') - var done = assert.async() - - var carouselHTML = - '<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>' - - var $carousel = $(carouselHTML).appendTo('#qunit-fixture') - var $item = $('#item') - $carousel.bootstrapCarousel() - var carousel = Carousel._getInstance($carousel[0]) - var spy = sinon.spy(carousel, 'prev') - - $carousel.one('slid.bs.carousel', function () { - assert.ok(true, 'slid event fired') - assert.ok($item.hasClass('active')) - assert.ok(spy.called) - $styles.remove() - delete document.documentElement.ontouchstart - done() - }) - - Simulator.gestures.swipe($carousel[0], { - deltaX: 300, - deltaY: 0 - }) - }) - - QUnit.test('should allow swiperight and call prev with touch events', function (assert) { - Simulator.setType('touch') - clearPointerEvents() - - assert.expect(3) - var done = assert.async() - document.documentElement.ontouchstart = $.noop - - var carouselHTML = - '<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>' - - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - var $item = $('#item') - $carousel.bootstrapCarousel() - var carousel = Carousel._getInstance($carousel[0]) - var spy = sinon.spy(carousel, 'prev') - - $carousel.one('slid.bs.carousel', function () { - assert.ok(true, 'slid event fired') - assert.ok($item.hasClass('active')) - assert.ok(spy.called) - delete document.documentElement.ontouchstart - restorePointerEvents() - done() - }) - - Simulator.gestures.swipe($carousel[0], { - deltaX: 300, - deltaY: 0 - }) - }) - - QUnit.test('should allow swipeleft and call next with pointer events', function (assert) { - if (!supportPointerEvent) { - assert.expect(0) - return - } - - document.documentElement.ontouchstart = $.noop - assert.expect(4) - Simulator.setType('pointer') - - var $styles = $(stylesCarousel).appendTo('head') - var done = assert.async() - - var carouselHTML = - '<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>' - - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - var $item = $('#item') - $carousel.bootstrapCarousel() - var carousel = Carousel._getInstance($carousel[0]) - var spy = sinon.spy(carousel, 'next') - - $carousel.one('slid.bs.carousel', function () { - assert.ok(true, 'slid event fired') - assert.ok(!$item.hasClass('active')) - assert.ok(spy.called) - assert.strictEqual(carousel.touchDeltaX, 0) - $styles.remove() - delete document.documentElement.ontouchstart - done() - }) - - Simulator.gestures.swipe($carousel[0], { - pos: [300, 10], - deltaX: -300, - deltaY: 0 - }) - }) - - QUnit.test('should allow swipeleft and call next with touch events', function (assert) { - assert.expect(4) - clearPointerEvents() - Simulator.setType('touch') - document.documentElement.ontouchstart = $.noop - - var done = assert.async() - - var carouselHTML = - '<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>' - - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - var $item = $('#item') - $carousel.bootstrapCarousel() - var carousel = Carousel._getInstance($carousel[0]) - var spy = sinon.spy(carousel, 'next') - - $carousel.one('slid.bs.carousel', function () { - assert.ok(true, 'slid event fired') - assert.ok(!$item.hasClass('active')) - assert.ok(spy.called) - assert.strictEqual(carousel.touchDeltaX, 0) - restorePointerEvents() - delete document.documentElement.ontouchstart - done() - }) - - Simulator.gestures.swipe($carousel[0], { - pos: [300, 10], - deltaX: -300, - deltaY: 0 - }) - }) - - QUnit.test('should not allow pinch with touch events', function (assert) { - assert.expect(0) - clearPointerEvents() - - Simulator.setType('touch') - var done = assert.async() - document.documentElement.ontouchstart = $.noop - - var carouselHTML = '<div class="carousel" data-interval="false"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - Simulator.gestures.swipe($carousel[0], { - pos: [300, 10], - deltaX: -300, - deltaY: 0, - touches: 2 - }, function () { - restorePointerEvents() - delete document.documentElement.ontouchstart - done() - }) - }) - - QUnit.test('should not call _slide if the carousel is sliding', function (assert) { - assert.expect(1) - - var carouselHTML = '<div class="carousel" data-interval="false"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - var carousel = Carousel._getInstance($carousel[0]) - - var spy = sinon.spy(carousel, '_slide') - - carousel._isSliding = true - - carousel.next() - - assert.strictEqual(spy.called, false) - }) - - QUnit.test('should call next when the page is visible', function (assert) { - assert.expect(1) - - var carouselHTML = '<div class="carousel" data-interval="false"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - var carousel = Carousel._getInstance($carousel[0]) - - var spy = sinon.spy(carousel, 'next') - var sandbox = sinon.createSandbox() - - sandbox.replaceGetter(document, 'hidden', function () { - return false - }) - sandbox.stub($carousel, 'is').returns(true) - sandbox.stub($carousel, 'css').returns('block') - - carousel.nextWhenVisible() - - assert.strictEqual(spy.called, true) - sandbox.restore() - }) - - QUnit.test('should not cycle when there is no attribute data-ride', function (assert) { - assert.expect(1) - - var spy = sinon.spy(Carousel.prototype, 'cycle') - - var carouselHTML = '<div class="carousel"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - assert.strictEqual(spy.called, false) - spy.restore() - }) - - QUnit.test('should cycle when there is data-ride attribute', function (assert) { - assert.expect(1) - - var spy = sinon.spy(Carousel.prototype, 'cycle') - - var carouselHTML = '<div class="carousel" data-ride="carousel"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - assert.strictEqual(spy.called, true) - spy.restore() - }) - - QUnit.test('should init carousels with data-ride on load event', function (assert) { - assert.expect(1) - - var done = assert.async() - var spy = sinon.spy(Carousel, '_carouselInterface') - - var carouselHTML = '<div class="carousel" data-ride="carousel"></div>' - var $carousel = $(carouselHTML) - $carousel.appendTo('#qunit-fixture') - - window.dispatchEvent(new Event('load')) - - setTimeout(function () { - assert.strictEqual(spy.called, true) - spy.restore() - done() - }, 5) - }) - - QUnit.test('should not add touch event listeners when touch option set to false', function (assert) { - assert.expect(1) - - var spy = sinon.spy(Carousel.prototype, '_addTouchEventListeners') - var $carousel = $('<div class="carousel" data-ride="carousel" data-touch="false"></div>') - - $carousel.appendTo('#qunit-fixture') - $carousel.bootstrapCarousel() - - assert.strictEqual(spy.called, false) - spy.restore() - }) -}) |