blob: adb9c76ecce0c2fc9e34afaee9f117f9531e1661 [file] [log] [blame]
describe('carousel', function() {
beforeEach(module('ui.bootstrap.carousel', function($compileProvider, $provide) {
angular.forEach(['ngSwipeLeft', 'ngSwipeRight'], makeMock);
function makeMock(name) {
$provide.value(name + 'Directive', []); //remove existing directive if it exists
$compileProvider.directive(name, function() {
return function(scope, element, attr) {
element.on(name, function() {
scope.$apply(attr[name]);
});
};
});
}
}));
beforeEach(module('template/carousel/carousel.html', 'template/carousel/slide.html'));
var $rootScope, $compile, $controller, $interval, $templateCache;
beforeEach(inject(function(_$rootScope_, _$compile_, _$controller_, _$interval_, _$templateCache_) {
$rootScope = _$rootScope_;
$compile = _$compile_;
$controller = _$controller_;
$interval = _$interval_;
$templateCache = _$templateCache_;
}));
describe('basics', function() {
var elm, scope;
beforeEach(function() {
scope = $rootScope.$new();
scope.slides = [
{active:false,content:'one'},
{active:false,content:'two'},
{active:false,content:'three'}
];
elm = $compile(
'<uib-carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(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.slides[i].active).toBe(true);
} else {
expect(scope.slides[i].active).not.toBe(true);
}
}
}
it('should allow overriding of the carousel template', function() {
$templateCache.put('foo/bar.html', '<div>foo</div>');
elm = $compile('<uib-carousel template-url="foo/bar.html"></uib-carousel>')(scope);
$rootScope.$digest();
expect(elm.html()).toBe('foo');
});
it('should allow overriding of the slide template', function() {
$templateCache.put('foo/bar.html', '<div class="slide">bar</div>');
elm = $compile(
'<uib-carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<uib-slide template-url="foo/bar.html"></uib-slide>' +
'</uib-carousel>'
)(scope);
$rootScope.$digest();
var slide = elm.find('.slide');
expect(slide.html()).toBe('bar');
});
it('should set the selected slide to active = true', function() {
expect(scope.slides[0].content).toBe('one');
testSlideActive(0);
scope.$apply('slides[1].active=true');
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(
'<uib-carousel interval="interval" no-wrap="noWrap">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(scope);
scope.noWrap = true;
scope.$apply();
scope = elm.isolateScope();
spyOn(scope, 'pause');
for (var i = 0; i < scope.slides.length - 1; ++i) {
scope.next();
}
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(
'<uib-carousel interval="interval" no-wrap="noWrap">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(scope);
scope.noWrap = true;
scope.$apply();
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(
'<uib-carousel interval="interval" no-transition="true">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(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 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);
});
describe('swiping', function() {
it('should go next on swipeLeft', function() {
testSlideActive(0);
elm.triggerHandler('ngSwipeLeft');
testSlideActive(1);
});
it('should go prev on swipeRight', function() {
testSlideActive(0);
elm.triggerHandler('ngSwipeRight');
testSlideActive(2);
});
});
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');
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('slides[2].active = true');
testSlideActive(2);
scope.$apply('slides.splice(0,1)');
expect(elm.find('div.item').length).toBe(2);
testSlideActive(1);
$interval.flush(scope.interval);
testSlideActive(0);
scope.$apply('slides.splice(1,1)');
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'},{content:'new2'},{content:'new3'}];
scope.$apply();
var contents = elm.find('div.item');
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('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'},{content:'new2'},{content:'new3'}];
scope.$apply();
testSlideActive(0);
carouselScope.$currentTransition = true;
scope.slides = [];
scope.$apply();
expect(carouselScope.$currentTransition).toBe(null);
});
describe('slide order', function() {
beforeEach(function() {
scope.slides = [
{active:false,content:'one', id:1},
{active:false,content:'two', id:2},
{active:false,content:'three', id:3}
];
elm = $compile(
'<uib-carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<uib-slide ng-repeat="slide in slides | orderBy: \'id\' " active="slide.active" index="$index">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(scope);
scope.$apply();
scope.slides[0].id = 3;
scope.slides[1].id = 1;
scope.slides[2].id = 2;
scope.$apply();
});
it('should change dom when an order of the slides was changed', function() {
testSlideActive(0);
var contents = elm.find('div.item');
expect(contents.length).toBe(3);
expect(contents.eq(0).text()).toBe('two');
expect(contents.eq(1).text()).toBe('three');
expect(contents.eq(2).text()).toBe('one');
});
it('should select next after order change', function() {
testSlideActive(0);
var next = elm.find('a.right');
next.click();
testSlideActive(1);
});
it('should select prev after order change', function() {
testSlideActive(0);
var prev = elm.find('a.left');
prev.click();
testSlideActive(2);
});
it('should add slide in the specified position', function() {
testSlideActive(0);
scope.slides[2].id = 4;
scope.slides.push({active:false,content:'four', id:2});
scope.$apply();
var contents = elm.find('div.item');
expect(contents.length).toBe(4);
expect(contents.eq(0).text()).toBe('two');
expect(contents.eq(1).text()).toBe('four');
expect(contents.eq(2).text()).toBe('one');
expect(contents.eq(3).text()).toBe('three');
});
it('should remove slide after order change', function() {
testSlideActive(0);
scope.slides.splice(1, 1);
scope.$apply();
var contents = elm.find('div.item');
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},{'content':2},{'content':3},{'content':4}];
beforeEach(function() {
scope = $rootScope.$new();
ctrl = $controller('UibCarouselController', {$scope: scope, $element: angular.element('<div></div>')});
for(var i = 0;i < slides.length;i++){
ctrl.addSlide(slides[i]);
}
});
describe('addSlide', function() {
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.active).not.toBe(true);
} else {
expect(slide.active).toBe(true);
}
});
});
it('should add new slide and change active to true if active is true on the added slide', function() {
var newSlide = {active: true};
expect(ctrl.slides.length).toBe(4);
ctrl.addSlide(newSlide);
expect(ctrl.slides.length).toBe(5);
expect(ctrl.slides[4].active).toBe(true);
expect(ctrl.slides[0].active).toBe(false);
});
it('should add a new slide and not change the active slide', function() {
var newSlide = {active: false};
expect(ctrl.slides.length).toBe(4);
ctrl.addSlide(newSlide);
expect(ctrl.slides.length).toBe(5);
expect(ctrl.slides[4].active).toBe(false);
expect(ctrl.slides[0].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]);
expect(ctrl.slides.length).toBe(3);
expect(ctrl.currentSlide).toBe(ctrl.slides[0]);
ctrl.select(ctrl.slides[2]);
ctrl.removeSlide(ctrl.slides[2]);
expect(ctrl.slides.length).toBe(2);
expect(ctrl.currentSlide).toBe(ctrl.slides[1]);
ctrl.removeSlide(ctrl.slides[0]);
expect(ctrl.slides.length).toBe(1);
expect(ctrl.currentSlide).toBe(ctrl.slides[0]);
});
it('issue 1414 - should not continue running timers after scope is destroyed', function() {
spyOn(scope, 'next').and.callThrough();
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('template/carousel/carousel.html', '<div>{{carousel.text}}</div>');
var scope = $rootScope.$new();
var elm = $compile('<uib-carousel interval="bar" no-transition="false" no-pause="true"></uib-carousel>')(scope);
$rootScope.$digest();
var ctrl = elm.controller('uibCarousel');
expect(ctrl).toBeDefined();
ctrl.text = 'foo';
$rootScope.$digest();
expect(elm.html()).toBe('foo');
}));
});
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(
'<uib-carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<uib-slide ng-repeat="slide in slides" active="slide.active" actual="slide">' +
'{{slide.content}}' +
'</uib-slide>' +
'</uib-carousel>'
)(scope);
$rootScope.$digest();
var ctrl = elm.controller('uibCarousel');
expect(angular.equals(ctrl.slides.map(function(slide) {
return slide.actual;
}), scope.slides)).toBe(true);
});
});
describe('carousel deprecation', function() {
beforeEach(module('ui.bootstrap.carousel'));
beforeEach(module('template/carousel/carousel.html', 'template/carousel/slide.html'));
it('should suppress warning', function() {
module(function($provide) {
$provide.value('$carouselSuppressWarning', true);
});
inject(function($compile, $log, $rootScope) {
spyOn($log, 'warn');
var element = '<carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</slide>' +
'</carousel>';
element = $compile(element)($rootScope);
$rootScope.$digest();
expect($log.warn.calls.count()).toBe(0);
});
});
it('should give warning by default', inject(function($compile, $log, $rootScope) {
spyOn($log, 'warn');
var element = '<carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<slide ng-repeat="slide in slides" active="slide.active">' +
'{{slide.content}}' +
'</slide>' +
'</carousel>';
element = $compile(element)($rootScope);
$rootScope.$digest();
expect($log.warn.calls.count()).toBe(2);
expect($log.warn.calls.argsFor(0)).toEqual(['CarouselController is now deprecated. Use UibCarouselController instead.']);
expect($log.warn.calls.argsFor(1)).toEqual(['carousel is now deprecated. Use uib-carousel instead.']);
}));
it('should give warning by default for slider', inject(function($compile, $log, $rootScope) {
spyOn($log, 'warn');
var element = '<carousel interval="interval" no-transition="true" no-pause="nopause">' +
'<slide></slide>' +
'</carousel>';
element = $compile(element)($rootScope);
$rootScope.$digest();
expect($log.warn.calls.count()).toBe(3);
expect($log.warn.calls.argsFor(0)).toEqual(['CarouselController is now deprecated. Use UibCarouselController instead.']);
expect($log.warn.calls.argsFor(1)).toEqual(['slide is now deprecated. Use uib-slide instead.']);
expect($log.warn.calls.argsFor(2)).toEqual(['carousel is now deprecated. Use uib-carousel instead.']);
}));
});