UNPKG

angular-ui-bootstrap

Version:

Native AngularJS (Angular) directives for Bootstrap

597 lines (502 loc) 18.7 kB
describe('carousel', function() { beforeEach(module('ui.bootstrap.carousel')); beforeEach(module('ngAnimateMock')); beforeEach(module('uib/template/carousel/carousel.html', 'uib/template/carousel/slide.html')); var $rootScope, $compile, $controller, $interval, $templateCache, $timeout, $animate; beforeEach(inject(function(_$rootScope_, _$compile_, _$controller_, _$interval_, _$templateCache_, _$timeout_, _$animate_) { $rootScope = _$rootScope_; $compile = _$compile_; $controller = _$controller_; $interval = _$interval_; $templateCache = _$templateCache_; $timeout = _$timeout_; $animate = _$animate_; })); describe('basics', function() { var elm, scope; beforeEach(function() { scope = $rootScope.$new(); scope.slides = [ {content: 'one', index: 0}, {content: 'two', index: 1}, {content: 'three', index: 2} ]; elm = $compile( '<div uib-carousel active="active" interval="interval" no-transition="true" no-pause="nopause">' + '<div uib-slide ng-repeat="slide in slides track by slide.index" index="slide.index">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); scope.interval = 5000; scope.nopause = undefined; scope.$apply(); }); function testSlideActive(slideIndex) { for (var i = 0; i < scope.slides.length; i++) { if (i === slideIndex) { expect(scope.active).toBe(scope.slides[i].index); } else { expect(scope.active).not.toBe(scope.slides[i].index); } } } it('should allow overriding of the carousel template', function() { $templateCache.put('foo/bar.html', '<div>foo</div>'); elm = $compile('<div uib-carousel template-url="foo/bar.html"></div>')(scope); $rootScope.$digest(); expect(elm.html()).toBe('<div>foo</div>'); }); it('should allow overriding of the slide template', function() { $templateCache.put('foo/bar.html', '<div class="slide">bar</div>'); elm = $compile( '<div uib-carousel interval="interval" no-transition="true" no-pause="nopause">' + '<div uib-slide template-url="foo/bar.html"></div>' + '</div>' )(scope); $rootScope.$digest(); var slide = elm.find('.slide'); expect(slide.html()).toBe('bar'); }); it('should be able to select a slide via model changes', function() { testSlideActive(0); scope.$apply('active=1'); testSlideActive(1); }); it('should create clickable prev nav button', function() { var navPrev = elm.find('a.left'); var navNext = elm.find('a.right'); expect(navPrev.length).toBe(1); expect(navNext.length).toBe(1); }); it('should display clickable slide indicators', function () { var indicators = elm.find('ol.carousel-indicators > li'); expect(indicators.length).toBe(3); }); it('should stop cycling slides forward when noWrap is truthy', function () { elm = $compile( '<div uib-carousel active="active" interval="interval" no-wrap="noWrap">' + '<div uib-slide ng-repeat="slide in slides track by slide.index" index="slide.index">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); scope.noWrap = true; scope.$apply(); var $scope = elm.isolateScope(); spyOn($scope, 'pause'); scope.active = $scope.slides.length - 1; scope.$apply(); testSlideActive($scope.slides.length - 1); $scope.next(); testSlideActive($scope.slides.length - 1); expect($scope.pause).toHaveBeenCalled(); }); it('should stop cycling slides backward when noWrap is truthy', function () { elm = $compile( '<div uib-carousel active="active" interval="interval" no-wrap="noWrap">' + '<div uib-slide ng-repeat="slide in slides track by slide.index" index="slide.index">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); scope.noWrap = true; scope.$apply(); var $scope = elm.isolateScope(); spyOn($scope, 'pause'); testSlideActive(0); $scope.prev(); testSlideActive(0); expect($scope.pause).toHaveBeenCalled(); }); it('should hide navigation when only one slide', function () { scope.slides = [{active:false,content:'one'}]; scope.$apply(); elm = $compile( '<div uib-carousel active="active" interval="interval" no-transition="true">' + '<div uib-slide ng-repeat="slide in slides" index="$index">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); var indicators = elm.find('ol.carousel-indicators > li'); expect(indicators.length).toBe(0); var navNext = elm.find('a.right'); expect(navNext.length).toBe(0); var navPrev = elm.find('a.left'); expect(navPrev.length).toBe(0); }); it('should disable prev button when slide index is 0 and noWrap is truthy', function() { scope.$apply(); var $scope = elm.isolateScope(); $scope.noWrap = function() {return true;}; $scope.isPrevDisabled(); scope.$apply(); var navPrev = elm.find('a.left'); expect(navPrev.hasClass('disabled')).toBe(true); }); it('should disable next button when last slide is active and noWrap is truthy', function() { scope.slides = [ {content: 'one', index: 0}, {content: 'two', index: 1} ]; scope.$apply(); var $scope = elm.isolateScope(); $scope.noWrap = function() {return true;}; $scope.next(); $scope.isNextDisabled(); scope.$apply(); var navNext = elm.find('a.right'); expect(navNext.hasClass('disabled')).toBe(true); }); it('should show navigation when there are 3 slides', function () { var indicators = elm.find('ol.carousel-indicators > li'); expect(indicators.length).not.toBe(0); var navNext = elm.find('a.right'); expect(navNext.length).not.toBe(0); var navPrev = elm.find('a.left'); expect(navPrev.length).not.toBe(0); }); it('should go to next when clicking next button', function() { var navNext = elm.find('a.right'); testSlideActive(0); navNext.click(); testSlideActive(1); navNext.click(); testSlideActive(2); navNext.click(); testSlideActive(0); }); it('should go to prev when clicking prev button', function() { var navPrev = elm.find('a.left'); testSlideActive(0); navPrev.click(); testSlideActive(2); navPrev.click(); testSlideActive(1); navPrev.click(); testSlideActive(0); }); it('should select a slide when clicking on slide indicators', function () { var indicators = elm.find('ol.carousel-indicators > li'); indicators.eq(1).click(); testSlideActive(1); }); it('shouldnt go forward if interval is NaN or negative or has no slides', function() { testSlideActive(0); var previousInterval = scope.interval; scope.$apply('interval = -1'); $interval.flush(previousInterval); testSlideActive(0); scope.$apply('interval = 1000'); $interval.flush(1000); testSlideActive(1); scope.$apply('interval = false'); $interval.flush(1000); testSlideActive(1); scope.$apply('interval = 1000'); $interval.flush(1000); testSlideActive(2); scope.$apply('slides = []'); $interval.flush(1000); testSlideActive(2); }); it('should bind the content to slides', function() { var contents = elm.find('div.item [ng-transclude]'); expect(contents.length).toBe(3); expect(contents.eq(0).text()).toBe('one'); expect(contents.eq(1).text()).toBe('two'); expect(contents.eq(2).text()).toBe('three'); scope.$apply(function() { scope.slides[0].content = 'what'; scope.slides[1].content = 'no'; scope.slides[2].content = 'maybe'; }); expect(contents.eq(0).text()).toBe('what'); expect(contents.eq(1).text()).toBe('no'); expect(contents.eq(2).text()).toBe('maybe'); }); it('should be playing by default and cycle through slides', function() { testSlideActive(0); $interval.flush(scope.interval); testSlideActive(1); $interval.flush(scope.interval); testSlideActive(2); $interval.flush(scope.interval); testSlideActive(0); }); it('should pause and play on mouseover', function() { testSlideActive(0); $interval.flush(scope.interval); testSlideActive(1); elm.trigger('mouseenter'); testSlideActive(1); $interval.flush(scope.interval); testSlideActive(1); elm.trigger('mouseleave'); $interval.flush(scope.interval); testSlideActive(2); }); it('should not pause on mouseover if noPause', function() { scope.$apply('nopause = true'); testSlideActive(0); elm.trigger('mouseenter'); $interval.flush(scope.interval); testSlideActive(1); elm.trigger('mouseleave'); $interval.flush(scope.interval); testSlideActive(2); }); it('should remove slide from dom and change active slide', function() { scope.$apply('active = 2'); testSlideActive(2); scope.$apply('slides.splice(2,1)'); $timeout.flush(0); expect(elm.find('div.item').length).toBe(2); testSlideActive(1); $interval.flush(scope.interval); testSlideActive(0); scope.$apply('slides.splice(1,1)'); $timeout.flush(0); expect(elm.find('div.item').length).toBe(1); testSlideActive(0); }); it('should change dom when you reassign ng-repeat slides array', function() { scope.slides = [ {content:'new1', index: 4}, {content:'new2', index: 5}, {content:'new3', index: 6} ]; scope.$apply(); var contents = elm.find('div.item [ng-transclude]'); expect(contents.length).toBe(3); expect(contents.eq(0).text()).toBe('new1'); expect(contents.eq(1).text()).toBe('new2'); expect(contents.eq(2).text()).toBe('new3'); }); it('should not change if next is clicked while transitioning', function() { var carouselScope = elm.children().scope(); var next = elm.find('a.right'); testSlideActive(0); carouselScope.$currentTransition = true; next.click(); testSlideActive(0); carouselScope.$currentTransition = null; next.click(); testSlideActive(1); }); it('should buffer the slides if transition is clicked and only transition to the last requested', function() { var carouselScope = elm.children().scope(); testSlideActive(0); carouselScope.$currentTransition = null; carouselScope.select(carouselScope.slides[1]); $animate.flush(); testSlideActive(1); carouselScope.$currentTransition = true; carouselScope.select(carouselScope.slides[2]); scope.$apply(); testSlideActive(1); carouselScope.select(carouselScope.slides[0]); scope.$apply(); testSlideActive(1); carouselScope.$currentTransition = null; $interval.flush(scope.interval); $animate.flush(); testSlideActive(2); $interval.flush(scope.interval); $animate.flush(); testSlideActive(0); }); it('issue 1414 - should not continue running timers after scope is destroyed', function() { testSlideActive(0); $interval.flush(scope.interval); testSlideActive(1); $interval.flush(scope.interval); testSlideActive(2); $interval.flush(scope.interval); testSlideActive(0); spyOn($interval, 'cancel').and.callThrough(); scope.$destroy(); expect($interval.cancel).toHaveBeenCalled(); }); it('issue 4390 - should reset the currentTransition if there are no slides', function() { var carouselScope = elm.children().scope(); var next = elm.find('a.right'); scope.slides = [ {content:'new1', index: 1}, {content:'new2', index: 2}, {content:'new3', index: 3} ]; scope.$apply(); testSlideActive(0); carouselScope.$currentTransition = true; scope.slides = []; scope.$apply(); expect(carouselScope.$currentTransition).toBe(null); }); }); describe('slide order', function() { var elm, scope; beforeEach(function() { scope = $rootScope.$new(); scope.slides = [ {content: 'one', id: 3}, {content: 'two', id: 1}, {content: 'three', id: 2} ]; elm = $compile( '<div uib-carousel active="active" interval="interval" no-transition="true" no-pause="nopause">' + '<div uib-slide ng-repeat="slide in slides | orderBy: \'id\' track by slide.id" index="slide.id">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); scope.$apply(); }); function testSlideActive(slideIndex) { for (var i = 0; i < scope.slides.length; i++) { if (i === slideIndex) { expect(scope.active).toBe(scope.slides[i].id); } else { expect(scope.active).not.toBe(scope.slides[i].id); } } } it('should change dom when the order of the slides changes', function() { scope.slides[0].id = 3; scope.slides[1].id = 2; scope.slides[2].id = 1; scope.$apply(); var contents = elm.find('div.item [ng-transclude]'); expect(contents.length).toBe(3); expect(contents.eq(0).text()).toBe('three'); expect(contents.eq(1).text()).toBe('two'); expect(contents.eq(2).text()).toBe('one'); }); it('should select next after order change', function() { testSlideActive(1); var next = elm.find('a.right'); next.click(); testSlideActive(2); }); it('should select prev after order change', function() { testSlideActive(1); var prev = elm.find('a.left'); prev.click(); testSlideActive(0); }); it('should add slide in the specified position', function() { testSlideActive(1); scope.slides[2].id = 4; scope.slides.push({content:'four', id: 5}); scope.$apply(); var contents = elm.find('div.item [ng-transclude]'); expect(contents.length).toBe(4); expect(contents.eq(0).text()).toBe('two'); expect(contents.eq(1).text()).toBe('one'); expect(contents.eq(2).text()).toBe('three'); expect(contents.eq(3).text()).toBe('four'); }); it('should remove slide after order change', function() { testSlideActive(1); scope.slides.splice(1, 1); scope.$apply(); var contents = elm.find('div.item [ng-transclude]'); expect(contents.length).toBe(2); expect(contents.eq(0).text()).toBe('three'); expect(contents.eq(1).text()).toBe('one'); }); }); describe('controller', function() { var scope, ctrl; //create an array of slides and add to the scope var slides = [ {'content': 1, index: 0}, {'content': 2, index: 1}, {'content': 3, index: 2}, {'content': 4, index: 3} ]; beforeEach(function() { scope = $rootScope.$new(); scope.noWrap = angular.noop; ctrl = $controller('UibCarouselController', {$scope: scope, $element: angular.element('<div></div>')}); for (var i = 0; i < slides.length; i++) { ctrl.addSlide(slides[i]); } }); it('should set first slide to active = true and the rest to false', function() { angular.forEach(ctrl.slides, function(slide, i) { if (i !== 0) { expect(slide.slide.active).not.toBe(true); } else { expect(slide.slide.active).toBe(true); } }); }); it('should add a new slide and not change the active slide', function() { var newSlide = {active: false, index: 4}; expect(ctrl.slides.length).toBe(4); ctrl.addSlide(newSlide); expect(ctrl.slides.length).toBe(5); expect(ctrl.slides[4].slide.active).toBe(false); expect(ctrl.slides[0].slide.active).toBe(true); }); it('should remove slide and change active slide if needed', function() { expect(ctrl.slides.length).toBe(4); ctrl.removeSlide(ctrl.slides[0].slide); $timeout.flush(0); expect(ctrl.slides.length).toBe(3); expect(scope.active).toBe(1); ctrl.select(ctrl.slides[2]); ctrl.removeSlide(ctrl.slides[2].slide); $timeout.flush(0); expect(ctrl.slides.length).toBe(2); expect(scope.active).toBe(2); ctrl.removeSlide(ctrl.slides[0].slide); $timeout.flush(0); expect(ctrl.slides.length).toBe(1); expect(scope.active).toBe(1); }); it('issue 1414 - should not continue running timers after scope is destroyed', function() { spyOn(scope, 'next'); scope.interval = 2000; scope.$digest(); $interval.flush(scope.interval); expect(scope.next.calls.count()).toBe(1); scope.$destroy(); $interval.flush(scope.interval); expect(scope.next.calls.count()).toBe(1); }); it('should be exposed in the template', inject(function($templateCache) { $templateCache.put('uib/template/carousel/carousel.html', '<div>{{carousel.text}}</div>'); var scope = $rootScope.$new(); var elm = $compile('<div uib-carousel interval="bar" no-transition="false" no-pause="true"></div>')(scope); $rootScope.$digest(); var ctrl = elm.controller('uibCarousel'); expect(ctrl).toBeDefined(); ctrl.text = 'foo'; $rootScope.$digest(); expect(elm.html()).toBe('<div class="ng-binding">foo</div>'); })); }); it('should expose a custom model in the carousel slide', function() { var scope = $rootScope.$new(); scope.slides = [ {active:false,content:'one'}, {active:false,content:'two'}, {active:false,content:'three'} ]; var elm = $compile( '<div uib-carousel active="active" interval="interval" no-transition="true" no-pause="nopause">' + '<div uib-slide ng-repeat="slide in slides" index="$index" actual="slide">' + '{{slide.content}}' + '</div>' + '</div>' )(scope); $rootScope.$digest(); var ctrl = elm.controller('uibCarousel'); expect(angular.equals(ctrl.slides.map(function(slide) { return slide.slide.actual; }), scope.slides)).toBe(true); }); });