diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index e9da91e0d6..921707b6d6 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -1,5 +1,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.position']) +.value('$datepickerSuppressError', false) + .constant('datepickerConfig', { formatDay: 'dd', formatMonth: 'MMMM', @@ -18,7 +20,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst shortcutPropagation: false }) -.controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$log', 'dateFilter', 'datepickerConfig', function($scope, $attrs, $parse, $interpolate, $log, dateFilter, datepickerConfig) { +.controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$log', 'dateFilter', 'datepickerConfig', '$datepickerSuppressError', function($scope, $attrs, $parse, $interpolate, $log, dateFilter, datepickerConfig, $datepickerSuppressError) { var self = this, ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl; @@ -82,7 +84,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst if ( isValid ) { this.activeDate = date; - } else { + } else if ( !$datepickerSuppressError ) { $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } } diff --git a/src/datepicker/test/datepicker.spec.js b/src/datepicker/test/datepicker.spec.js index 4656df8ed2..30a0df4f36 100644 --- a/src/datepicker/test/datepicker.spec.js +++ b/src/datepicker/test/datepicker.spec.js @@ -25,12 +25,7 @@ describe('datepicker directive', function () { } }; }); - })); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.date = new Date('September 30, 2010 15:30:00'); - })); + })); function getTitleButton() { return element.find('th').eq(1).find('button').first(); @@ -136,1265 +131,1182 @@ describe('datepicker directive', function () { } element.trigger(e); } - - describe('', function () { - beforeEach(function() { - element = $compile('')($rootScope); - $rootScope.$digest(); - }); - - it('is has a `` element', function() { - expect(element.find('table').length).toBe(1); - }); - - it('shows the correct title', function() { - expect(getTitle()).toBe('September 2010'); - }); - - it('shows the label row & the correct day labels', function() { - expect(getLabelsRow().css('display')).not.toBe('none'); - expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); - }); - - it('renders the calendar days correctly', function() { - expect(getOptions(true)).toEqual([ - ['29', '30', '31', '01', '02', '03', '04'], - ['05', '06', '07', '08', '09', '10', '11'], - ['12', '13', '14', '15', '16', '17', '18'], - ['19', '20', '21', '22', '23', '24', '25'], - ['26', '27', '28', '29', '30', '01', '02'], - ['03', '04', '05', '06', '07', '08', '09'] - ]); - }); - - it('renders the week numbers based on ISO 8601', function() { - expect(getWeeks()).toEqual(['35', '36', '37', '38', '39', '40']); - }); - - it('value is correct', function() { - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - }); - - it('has `selected` only the correct day', function() { - expectSelectedElement( 32 ); - }); - - it('has no `selected` day when model is cleared', function() { - $rootScope.date = null; - $rootScope.$digest(); - - expect($rootScope.date).toBe(null); - expectSelectedElement( null ); - }); - - it('does not change current view when model is cleared', function() { - $rootScope.date = null; - $rootScope.$digest(); - - expect($rootScope.date).toBe(null); - expect(getTitle()).toBe('September 2010'); + + describe('$datepickerSuppressError', function() { + var $compile, + $log, + $scope; + + it('should not suppress log error message for ng-model date error by default', function() { + inject(function(_$log_, _$rootScope_, _$compile_) { + $log = _$log_; + $scope = _$rootScope_.$new(); + $compile = _$compile_; + }); + + spyOn($log, 'error'); + element = $compile('')($scope); + + $scope.locals = { + date: 'lalala' + }; + $scope.$digest(); + expect($log.error).toHaveBeenCalled(); + }); + + it('should not suppress log error message for ng-model date error when false', function() { + module(function($provide) { + $provide.value('$datepickerSuppressError', false); + }); + + inject(function(_$log_, _$rootScope_, _$compile_) { + $log = _$log_; + $scope = _$rootScope_.$new(); + $compile = _$compile_; + }); + + spyOn($log, 'error'); + element = $compile('')($scope); + + $scope.locals = { + date: 'lalala' + }; + $scope.$digest(); + expect($log.error).toHaveBeenCalled(); }); - it('`disables` visible dates from other months', function() { - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).find('span').hasClass('text-muted')).toBe( index < 3 || index > 32 ); + it('should suppress log error message for ng-model date error when true', function() { + module(function($provide) { + $provide.value('$datepickerSuppressError', true); }); - }); - - it('updates the model when a day is clicked', function() { - clickOption( 17 ); - expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); - }); - - it('moves to the previous month & renders correctly when `previous` button is clicked', function() { - clickPreviousButton(); - - expect(getTitle()).toBe('August 2010'); - expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); - expect(getOptions(true)).toEqual([ - ['01', '02', '03', '04', '05', '06', '07'], - ['08', '09', '10', '11', '12', '13', '14'], - ['15', '16', '17', '18', '19', '20', '21'], - ['22', '23', '24', '25', '26', '27', '28'], - ['29', '30', '31', '01', '02', '03', '04'], - ['05', '06', '07', '08', '09', '10', '11'] - ]); - - expectSelectedElement( null, null ); - }); - - it('updates the model only when a day is clicked in the `previous` month', function() { - clickPreviousButton(); - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - - clickOption( 17 ); - expect($rootScope.date).toEqual(new Date('August 18, 2010 15:30:00')); - }); - it('moves to the next month & renders correctly when `next` button is clicked', function() { - clickNextButton(); - - expect(getTitle()).toBe('October 2010'); - expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); - expect(getOptions(true)).toEqual([ - ['26', '27', '28', '29', '30', '01', '02'], - ['03', '04', '05', '06', '07', '08', '09'], - ['10', '11', '12', '13', '14', '15', '16'], - ['17', '18', '19', '20', '21', '22', '23'], - ['24', '25', '26', '27', '28', '29', '30'], - ['31', '01', '02', '03', '04', '05', '06'] - ]); - - expectSelectedElement( 4 ); - }); - - it('updates the model only when a day is clicked in the `next` month', function() { - clickNextButton(); - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - - clickOption( 17 ); - expect($rootScope.date).toEqual(new Date('October 13, 2010 15:30:00')); - }); + inject(function(_$log_, _$rootScope_, _$compile_) { + $log = _$log_; + $scope = _$rootScope_.$new(); + $compile = _$compile_; + }); + spyOn($log, 'error'); - it('updates the calendar when a day of another month is selected', function() { - clickOption( 33 ); - expect($rootScope.date).toEqual(new Date('October 01, 2010 15:30:00')); - expect(getTitle()).toBe('October 2010'); - expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); - expect(getOptions(true)).toEqual([ - ['26', '27', '28', '29', '30', '01', '02'], - ['03', '04', '05', '06', '07', '08', '09'], - ['10', '11', '12', '13', '14', '15', '16'], - ['17', '18', '19', '20', '21', '22', '23'], - ['24', '25', '26', '27', '28', '29', '30'], - ['31', '01', '02', '03', '04', '05', '06'] - ]); - - expectSelectedElement( 5 ); - }); + element = $compile('')($scope); - // issue #1697 - it('should not "jump" months', function() { - $rootScope.date = new Date('January 30, 2014'); - $rootScope.$digest(); - clickNextButton(); - expect(getTitle()).toBe('February 2014'); - clickPreviousButton(); - expect(getTitle()).toBe('January 2014'); + $scope.locals = { + date: 'lalala' + }; + $scope.$digest(); + expect($log.error).not.toHaveBeenCalled(); }); - - // issue #3079 - describe('time zone bug', function () { - - it('should deal with time zone bug', function() { - var ctrl = element.controller('datepicker'), - date = new Date('January 1, 2014'); - spyOn(date, 'getHours').and.returnValue(23); - spyOn(date, 'setHours').and.returnValue(); - - ctrl.fixTimeZone(date); - - expect(date.setHours).toHaveBeenCalledWith(25); + }); + + describe('', function () { + beforeEach(inject(function(_$compile_, _$rootScope_) { + $compile = _$compile_; + $rootScope = _$rootScope_; + $rootScope.date = new Date('September 30, 2010 15:30:00'); + })); + + + describe('', function () { + beforeEach(function() { + element = $compile('')($rootScope); + $rootScope.$digest(); }); - it('should not change hours if time zone bug does not occur', function() { - var ctrl = element.controller('datepicker'), - date = new Date('January 1, 2014'); - spyOn(date, 'getHours').and.returnValue(0); - spyOn(date, 'setHours').and.returnValue(); - - ctrl.fixTimeZone(date); + it('is has a `
` element', function() { + expect(element.find('table').length).toBe(1); + }); - expect(date.setHours).toHaveBeenCalledWith(0); + it('shows the correct title', function() { + expect(getTitle()).toBe('September 2010'); }); - }); + it('shows the label row & the correct day labels', function() { + expect(getLabelsRow().css('display')).not.toBe('none'); + expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); + }); - describe('when `model` changes', function () { - function testCalendar() { - expect(getTitle()).toBe('November 2005'); + it('renders the calendar days correctly', function() { expect(getOptions(true)).toEqual([ - ['30', '31', '01', '02', '03', '04', '05'], - ['06', '07', '08', '09', '10', '11', '12'], - ['13', '14', '15', '16', '17', '18', '19'], - ['20', '21', '22', '23', '24', '25', '26'], - ['27', '28', '29', '30', '01', '02', '03'], - ['04', '05', '06', '07', '08', '09', '10'] + ['29', '30', '31', '01', '02', '03', '04'], + ['05', '06', '07', '08', '09', '10', '11'], + ['12', '13', '14', '15', '16', '17', '18'], + ['19', '20', '21', '22', '23', '24', '25'], + ['26', '27', '28', '29', '30', '01', '02'], + ['03', '04', '05', '06', '07', '08', '09'] ]); - - expectSelectedElement( 8 ); - } - - describe('to a Date object', function() { - it('updates', function() { - $rootScope.date = new Date('November 7, 2005 23:30:00'); - $rootScope.$digest(); - testCalendar(); - expect(angular.isDate($rootScope.date)).toBe(true); - }); - - it('to a date that is invalid, it doesn\`t update', function() { - $rootScope.date = new Date('pizza'); - $rootScope.$digest(); - expect(getTitle()).toBe('September 2010'); - expect(angular.isDate($rootScope.date)).toBe(true); - expect(isNaN($rootScope.date)).toBe(true); - }); }); - describe('not to a Date object', function() { - - it('to a Number, it updates calendar', function() { - $rootScope.date = parseInt((new Date('November 7, 2005 23:30:00')).getTime(), 10); - $rootScope.$digest(); - testCalendar(); - expect(angular.isNumber($rootScope.date)).toBe(true); - }); - - it('to a string that can be parsed by Date, it updates calendar', function() { - $rootScope.date = 'November 7, 2005 23:30:00'; - $rootScope.$digest(); - testCalendar(); - expect(angular.isString($rootScope.date)).toBe(true); - }); - - it('to a string that cannot be parsed by Date, it doesn\'t update', function() { - $rootScope.date = 'pizza'; - $rootScope.$digest(); - expect(getTitle()).toBe('September 2010'); - expect($rootScope.date).toBe('pizza'); - }); + it('renders the week numbers based on ISO 8601', function() { + expect(getWeeks()).toEqual(['35', '36', '37', '38', '39', '40']); }); - }); - it('does not loop between after max mode', function() { - expect(getTitle()).toBe('September 2010'); - - clickTitleButton(); - expect(getTitle()).toBe('2010'); + it('value is correct', function() { + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + }); - clickTitleButton(); - expect(getTitle()).toBe('2001 - 2020'); + it('has `selected` only the correct day', function() { + expectSelectedElement( 32 ); + }); - clickTitleButton(); - expect(getTitle()).toBe('2001 - 2020'); - }); + it('has no `selected` day when model is cleared', function() { + $rootScope.date = null; + $rootScope.$digest(); - describe('month selection mode', function () { - beforeEach(function() { - clickTitleButton(); + expect($rootScope.date).toBe(null); + expectSelectedElement( null ); }); - it('shows the year as title', function() { - expect(getTitle()).toBe('2010'); - }); + it('does not change current view when model is cleared', function() { + $rootScope.date = null; + $rootScope.$digest(); - it('shows months as options', function() { - expect(getOptions()).toEqual([ - ['January', 'February', 'March'], - ['April', 'May', 'June'], - ['July', 'August', 'September'], - ['October', 'November', 'December'] - ]); + expect($rootScope.date).toBe(null); + expect(getTitle()).toBe('September 2010'); }); - it('does not change the model', function() { - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + it('`disables` visible dates from other months', function() { + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).find('span').hasClass('text-muted')).toBe( index < 3 || index > 32 ); + }); }); - it('has `selected` only the correct month', function() { - expectSelectedElement( 8 ); + it('updates the model when a day is clicked', function() { + clickOption( 17 ); + expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); }); - it('moves to the previous year when `previous` button is clicked', function() { + it('moves to the previous month & renders correctly when `previous` button is clicked', function() { clickPreviousButton(); - expect(getTitle()).toBe('2009'); - expect(getOptions()).toEqual([ - ['January', 'February', 'March'], - ['April', 'May', 'June'], - ['July', 'August', 'September'], - ['October', 'November', 'December'] + expect(getTitle()).toBe('August 2010'); + expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); + expect(getOptions(true)).toEqual([ + ['01', '02', '03', '04', '05', '06', '07'], + ['08', '09', '10', '11', '12', '13', '14'], + ['15', '16', '17', '18', '19', '20', '21'], + ['22', '23', '24', '25', '26', '27', '28'], + ['29', '30', '31', '01', '02', '03', '04'], + ['05', '06', '07', '08', '09', '10', '11'] ]); - expectSelectedElement( null ); + expectSelectedElement( null, null ); }); - it('moves to the next year when `next` button is clicked', function() { - clickNextButton(); - - expect(getTitle()).toBe('2011'); - expect(getOptions()).toEqual([ - ['January', 'February', 'March'], - ['April', 'May', 'June'], - ['July', 'August', 'September'], - ['October', 'November', 'December'] - ]); + it('updates the model only when a day is clicked in the `previous` month', function() { + clickPreviousButton(); + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - expectSelectedElement( null ); + clickOption( 17 ); + expect($rootScope.date).toEqual(new Date('August 18, 2010 15:30:00')); }); - it('renders correctly when a month is clicked', function() { - clickPreviousButton(5); - expect(getTitle()).toBe('2005'); + it('moves to the next month & renders correctly when `next` button is clicked', function() { + clickNextButton(); - clickOption( 10 ); - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - expect(getTitle()).toBe('November 2005'); + expect(getTitle()).toBe('October 2010'); + expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); expect(getOptions(true)).toEqual([ - ['30', '31', '01', '02', '03', '04', '05'], - ['06', '07', '08', '09', '10', '11', '12'], - ['13', '14', '15', '16', '17', '18', '19'], - ['20', '21', '22', '23', '24', '25', '26'], - ['27', '28', '29', '30', '01', '02', '03'], - ['04', '05', '06', '07', '08', '09', '10'] + ['26', '27', '28', '29', '30', '01', '02'], + ['03', '04', '05', '06', '07', '08', '09'], + ['10', '11', '12', '13', '14', '15', '16'], + ['17', '18', '19', '20', '21', '22', '23'], + ['24', '25', '26', '27', '28', '29', '30'], + ['31', '01', '02', '03', '04', '05', '06'] ]); - clickOption( 17 ); - expect($rootScope.date).toEqual(new Date('November 16, 2005 15:30:00')); + expectSelectedElement( 4 ); }); - }); - describe('year selection mode', function () { - beforeEach(function() { - clickTitleButton(); - clickTitleButton(); - }); + it('updates the model only when a day is clicked in the `next` month', function() { + clickNextButton(); + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); - it('shows the year range as title', function() { - expect(getTitle()).toBe('2001 - 2020'); + clickOption( 17 ); + expect($rootScope.date).toEqual(new Date('October 13, 2010 15:30:00')); }); - it('shows years as options', function() { - expect(getOptions()).toEqual([ - ['2001', '2002', '2003', '2004', '2005'], - ['2006', '2007', '2008', '2009', '2010'], - ['2011', '2012', '2013', '2014', '2015'], - ['2016', '2017', '2018', '2019', '2020'] + it('updates the calendar when a day of another month is selected', function() { + clickOption( 33 ); + expect($rootScope.date).toEqual(new Date('October 01, 2010 15:30:00')); + expect(getTitle()).toBe('October 2010'); + expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); + expect(getOptions(true)).toEqual([ + ['26', '27', '28', '29', '30', '01', '02'], + ['03', '04', '05', '06', '07', '08', '09'], + ['10', '11', '12', '13', '14', '15', '16'], + ['17', '18', '19', '20', '21', '22', '23'], + ['24', '25', '26', '27', '28', '29', '30'], + ['31', '01', '02', '03', '04', '05', '06'] ]); - }); - it('does not change the model', function() { - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + expectSelectedElement( 5 ); }); - it('has `selected` only the selected year', function() { - expectSelectedElement( 9 ); + // issue #1697 + it('should not "jump" months', function() { + $rootScope.date = new Date('January 30, 2014'); + $rootScope.$digest(); + clickNextButton(); + expect(getTitle()).toBe('February 2014'); + clickPreviousButton(); + expect(getTitle()).toBe('January 2014'); }); - it('moves to the previous year set when `previous` button is clicked', function() { - clickPreviousButton(); + // issue #3079 + describe('time zone bug', function () { - expect(getTitle()).toBe('1981 - 2000'); - expect(getOptions()).toEqual([ - ['1981', '1982', '1983', '1984', '1985'], - ['1986', '1987', '1988', '1989', '1990'], - ['1991', '1992', '1993', '1994', '1995'], - ['1996', '1997', '1998', '1999', '2000'] - ]); - expectSelectedElement( null ); - }); + it('should deal with time zone bug', function() { + var ctrl = element.controller('datepicker'), + date = new Date('January 1, 2014'); + spyOn(date, 'getHours').and.returnValue(23); + spyOn(date, 'setHours').and.returnValue(); - it('moves to the next year set when `next` button is clicked', function() { - clickNextButton(); + ctrl.fixTimeZone(date); - expect(getTitle()).toBe('2021 - 2040'); - expect(getOptions()).toEqual([ - ['2021', '2022', '2023', '2024', '2025'], - ['2026', '2027', '2028', '2029', '2030'], - ['2031', '2032', '2033', '2034', '2035'], - ['2036', '2037', '2038', '2039', '2040'] - ]); + expect(date.setHours).toHaveBeenCalledWith(25); + }); - expectSelectedElement( null ); - }); - }); + it('should not change hours if time zone bug does not occur', function() { + var ctrl = element.controller('datepicker'), + date = new Date('January 1, 2014'); + spyOn(date, 'getHours').and.returnValue(0); + spyOn(date, 'setHours').and.returnValue(); - describe('keyboard navigation', function() { - function getActiveLabel() { - return element.find('.active').eq(0).text(); - } + ctrl.fixTimeZone(date); - describe('day mode', function() { - it('will be able to activate previous day', function() { - triggerKeyDown(element, 'left'); - expect(getActiveLabel()).toBe('29'); + expect(date.setHours).toHaveBeenCalledWith(0); }); - it('will be able to select with enter', function() { - triggerKeyDown(element, 'left'); - triggerKeyDown(element, 'enter'); - expect($rootScope.date).toEqual(new Date('September 29, 2010 15:30:00')); - }); + }); - it('will be able to select with space', function() { - triggerKeyDown(element, 'left'); - triggerKeyDown(element, 'space'); - expect($rootScope.date).toEqual(new Date('September 29, 2010 15:30:00')); - }); + describe('when `model` changes', function () { + function testCalendar() { + expect(getTitle()).toBe('November 2005'); + expect(getOptions(true)).toEqual([ + ['30', '31', '01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10', '11', '12'], + ['13', '14', '15', '16', '17', '18', '19'], + ['20', '21', '22', '23', '24', '25', '26'], + ['27', '28', '29', '30', '01', '02', '03'], + ['04', '05', '06', '07', '08', '09', '10'] + ]); - it('will be able to activate next day', function() { - triggerKeyDown(element, 'right'); - expect(getActiveLabel()).toBe('01'); - expect(getTitle()).toBe('October 2010'); - }); + expectSelectedElement( 8 ); + } - it('will be able to activate same day in previous week', function() { - triggerKeyDown(element, 'up'); - expect(getActiveLabel()).toBe('23'); - }); + describe('to a Date object', function() { + it('updates', function() { + $rootScope.date = new Date('November 7, 2005 23:30:00'); + $rootScope.$digest(); + testCalendar(); + expect(angular.isDate($rootScope.date)).toBe(true); + }); - it('will be able to activate same day in next week', function() { - triggerKeyDown(element, 'down'); - expect(getActiveLabel()).toBe('07'); - expect(getTitle()).toBe('October 2010'); + it('to a date that is invalid, it doesn\`t update', function() { + $rootScope.date = new Date('pizza'); + $rootScope.$digest(); + expect(getTitle()).toBe('September 2010'); + expect(angular.isDate($rootScope.date)).toBe(true); + expect(isNaN($rootScope.date)).toBe(true); + }); }); - it('will be able to activate same date in previous month', function() { - triggerKeyDown(element, 'pageup'); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('August 2010'); - }); + describe('not to a Date object', function() { - it('will be able to activate same date in next month', function() { - triggerKeyDown(element, 'pagedown'); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('October 2010'); - }); + it('to a Number, it updates calendar', function() { + $rootScope.date = parseInt((new Date('November 7, 2005 23:30:00')).getTime(), 10); + $rootScope.$digest(); + testCalendar(); + expect(angular.isNumber($rootScope.date)).toBe(true); + }); + + it('to a string that can be parsed by Date, it updates calendar', function() { + $rootScope.date = 'November 7, 2005 23:30:00'; + $rootScope.$digest(); + testCalendar(); + expect(angular.isString($rootScope.date)).toBe(true); + }); - it('will be able to activate first day of the month', function() { - triggerKeyDown(element, 'home'); - expect(getActiveLabel()).toBe('01'); - expect(getTitle()).toBe('September 2010'); + it('to a string that cannot be parsed by Date, it doesn\'t update', function() { + $rootScope.date = 'pizza'; + $rootScope.$digest(); + expect(getTitle()).toBe('September 2010'); + expect($rootScope.date).toBe('pizza'); + }); }); + }); - it('will be able to activate last day of the month', function() { - $rootScope.date = new Date('September 1, 2010 15:30:00'); - $rootScope.$digest(); + it('does not loop between after max mode', function() { + expect(getTitle()).toBe('September 2010'); - triggerKeyDown(element, 'end'); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('September 2010'); - }); + clickTitleButton(); + expect(getTitle()).toBe('2010'); - it('will be able to move to month mode', function() { - triggerKeyDown(element, 'up', true); - expect(getActiveLabel()).toBe('September'); - expect(getTitle()).toBe('2010'); - }); + clickTitleButton(); + expect(getTitle()).toBe('2001 - 2020'); - it('will not respond when trying to move to lower mode', function() { - triggerKeyDown(element, 'down', true); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('September 2010'); - }); + clickTitleButton(); + expect(getTitle()).toBe('2001 - 2020'); }); - describe('month mode', function() { + describe('month selection mode', function () { beforeEach(function() { - triggerKeyDown(element, 'up', true); + clickTitleButton(); }); - it('will be able to activate previous month', function() { - triggerKeyDown(element, 'left'); - expect(getActiveLabel()).toBe('August'); + it('shows the year as title', function() { + expect(getTitle()).toBe('2010'); }); - it('will be able to activate next month', function() { - triggerKeyDown(element, 'right'); - expect(getActiveLabel()).toBe('October'); + it('shows months as options', function() { + expect(getOptions()).toEqual([ + ['January', 'February', 'March'], + ['April', 'May', 'June'], + ['July', 'August', 'September'], + ['October', 'November', 'December'] + ]); }); - it('will be able to activate same month in previous row', function() { - triggerKeyDown(element, 'up'); - expect(getActiveLabel()).toBe('June'); + it('does not change the model', function() { + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); }); - it('will be able to activate same month in next row', function() { - triggerKeyDown(element, 'down'); - expect(getActiveLabel()).toBe('December'); + it('has `selected` only the correct month', function() { + expectSelectedElement( 8 ); }); - it('will be able to activate same date in previous year', function() { - triggerKeyDown(element, 'pageup'); - expect(getActiveLabel()).toBe('September'); + it('moves to the previous year when `previous` button is clicked', function() { + clickPreviousButton(); + expect(getTitle()).toBe('2009'); - }); + expect(getOptions()).toEqual([ + ['January', 'February', 'March'], + ['April', 'May', 'June'], + ['July', 'August', 'September'], + ['October', 'November', 'December'] + ]); - it('will be able to activate same date in next year', function() { - triggerKeyDown(element, 'pagedown'); - expect(getActiveLabel()).toBe('September'); - expect(getTitle()).toBe('2011'); + expectSelectedElement( null ); }); - it('will be able to activate first month of the year', function() { - triggerKeyDown(element, 'home'); - expect(getActiveLabel()).toBe('January'); - expect(getTitle()).toBe('2010'); - }); + it('moves to the next year when `next` button is clicked', function() { + clickNextButton(); - it('will be able to activate last month of the year', function() { - triggerKeyDown(element, 'end'); - expect(getActiveLabel()).toBe('December'); - expect(getTitle()).toBe('2010'); - }); + expect(getTitle()).toBe('2011'); + expect(getOptions()).toEqual([ + ['January', 'February', 'March'], + ['April', 'May', 'June'], + ['July', 'August', 'September'], + ['October', 'November', 'December'] + ]); - it('will be able to move to year mode', function() { - triggerKeyDown(element, 'up', true); - expect(getActiveLabel()).toBe('2010'); - expect(getTitle()).toBe('2001 - 2020'); + expectSelectedElement( null ); }); - it('will be able to move to day mode', function() { - triggerKeyDown(element, 'down', true); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('September 2010'); - }); + it('renders correctly when a month is clicked', function() { + clickPreviousButton(5); + expect(getTitle()).toBe('2005'); - it('will move to day mode when selecting', function() { - triggerKeyDown(element, 'left', true); - triggerKeyDown(element, 'enter', true); - expect(getActiveLabel()).toBe('30'); - expect(getTitle()).toBe('August 2010'); + clickOption( 10 ); expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + expect(getTitle()).toBe('November 2005'); + expect(getOptions(true)).toEqual([ + ['30', '31', '01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10', '11', '12'], + ['13', '14', '15', '16', '17', '18', '19'], + ['20', '21', '22', '23', '24', '25', '26'], + ['27', '28', '29', '30', '01', '02', '03'], + ['04', '05', '06', '07', '08', '09', '10'] + ]); + + clickOption( 17 ); + expect($rootScope.date).toEqual(new Date('November 16, 2005 15:30:00')); }); }); - describe('year mode', function() { + describe('year selection mode', function () { beforeEach(function() { - triggerKeyDown(element, 'up', true); - triggerKeyDown(element, 'up', true); - }); - - it('will be able to activate previous year', function() { - triggerKeyDown(element, 'left'); - expect(getActiveLabel()).toBe('2009'); + clickTitleButton(); + clickTitleButton(); }); - it('will be able to activate next year', function() { - triggerKeyDown(element, 'right'); - expect(getActiveLabel()).toBe('2011'); - }); - - it('will be able to activate same year in previous row', function() { - triggerKeyDown(element, 'up'); - expect(getActiveLabel()).toBe('2005'); + it('shows the year range as title', function() { + expect(getTitle()).toBe('2001 - 2020'); }); - it('will be able to activate same year in next row', function() { - triggerKeyDown(element, 'down'); - expect(getActiveLabel()).toBe('2015'); + it('shows years as options', function() { + expect(getOptions()).toEqual([ + ['2001', '2002', '2003', '2004', '2005'], + ['2006', '2007', '2008', '2009', '2010'], + ['2011', '2012', '2013', '2014', '2015'], + ['2016', '2017', '2018', '2019', '2020'] + ]); }); - it('will be able to activate same date in previous view', function() { - triggerKeyDown(element, 'pageup'); - expect(getActiveLabel()).toBe('1990'); + it('does not change the model', function() { + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); }); - it('will be able to activate same date in next view', function() { - triggerKeyDown(element, 'pagedown'); - expect(getActiveLabel()).toBe('2030'); + it('has `selected` only the selected year', function() { + expectSelectedElement( 9 ); }); - it('will be able to activate first year of the year', function() { - triggerKeyDown(element, 'home'); - expect(getActiveLabel()).toBe('2001'); - }); + it('moves to the previous year set when `previous` button is clicked', function() { + clickPreviousButton(); - it('will be able to activate last year of the year', function() { - triggerKeyDown(element, 'end'); - expect(getActiveLabel()).toBe('2020'); + expect(getTitle()).toBe('1981 - 2000'); + expect(getOptions()).toEqual([ + ['1981', '1982', '1983', '1984', '1985'], + ['1986', '1987', '1988', '1989', '1990'], + ['1991', '1992', '1993', '1994', '1995'], + ['1996', '1997', '1998', '1999', '2000'] + ]); + expectSelectedElement( null ); }); - it('will not respond when trying to move to upper mode', function() { - triggerKeyDown(element, 'up', true); - expect(getTitle()).toBe('2001 - 2020'); - }); + it('moves to the next year set when `next` button is clicked', function() { + clickNextButton(); - it('will be able to move to month mode', function() { - triggerKeyDown(element, 'down', true); - expect(getActiveLabel()).toBe('September'); - expect(getTitle()).toBe('2010'); - }); + expect(getTitle()).toBe('2021 - 2040'); + expect(getOptions()).toEqual([ + ['2021', '2022', '2023', '2024', '2025'], + ['2026', '2027', '2028', '2029', '2030'], + ['2031', '2032', '2033', '2034', '2035'], + ['2036', '2037', '2038', '2039', '2040'] + ]); - it('will move to month mode when selecting', function() { - triggerKeyDown(element, 'left', true); - triggerKeyDown(element, 'enter', true); - expect(getActiveLabel()).toBe('September'); - expect(getTitle()).toBe('2009'); - expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + expectSelectedElement( null ); }); }); - describe('`aria-activedescendant`', function() { - function checkActivedescendant() { - var activeId = element.find('table').attr('aria-activedescendant'); - expect(element.find('#' + activeId + ' > button')).toHaveClass('active'); + describe('keyboard navigation', function() { + function getActiveLabel() { + return element.find('.active').eq(0).text(); } - it('updates correctly', function() { - triggerKeyDown(element, 'left'); - checkActivedescendant(); + describe('day mode', function() { + it('will be able to activate previous day', function() { + triggerKeyDown(element, 'left'); + expect(getActiveLabel()).toBe('29'); + }); + + it('will be able to select with enter', function() { + triggerKeyDown(element, 'left'); + triggerKeyDown(element, 'enter'); + expect($rootScope.date).toEqual(new Date('September 29, 2010 15:30:00')); + }); + + it('will be able to select with space', function() { + triggerKeyDown(element, 'left'); + triggerKeyDown(element, 'space'); + expect($rootScope.date).toEqual(new Date('September 29, 2010 15:30:00')); + }); + + it('will be able to activate next day', function() { + triggerKeyDown(element, 'right'); + expect(getActiveLabel()).toBe('01'); + expect(getTitle()).toBe('October 2010'); + }); + + it('will be able to activate same day in previous week', function() { + triggerKeyDown(element, 'up'); + expect(getActiveLabel()).toBe('23'); + }); + + it('will be able to activate same day in next week', function() { + triggerKeyDown(element, 'down'); + expect(getActiveLabel()).toBe('07'); + expect(getTitle()).toBe('October 2010'); + }); + + it('will be able to activate same date in previous month', function() { + triggerKeyDown(element, 'pageup'); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('August 2010'); + }); + + it('will be able to activate same date in next month', function() { + triggerKeyDown(element, 'pagedown'); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('October 2010'); + }); + + it('will be able to activate first day of the month', function() { + triggerKeyDown(element, 'home'); + expect(getActiveLabel()).toBe('01'); + expect(getTitle()).toBe('September 2010'); + }); + + it('will be able to activate last day of the month', function() { + $rootScope.date = new Date('September 1, 2010 15:30:00'); + $rootScope.$digest(); - triggerKeyDown(element, 'down'); - checkActivedescendant(); + triggerKeyDown(element, 'end'); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('September 2010'); + }); - triggerKeyDown(element, 'up', true); - checkActivedescendant(); + it('will be able to move to month mode', function() { + triggerKeyDown(element, 'up', true); + expect(getActiveLabel()).toBe('September'); + expect(getTitle()).toBe('2010'); + }); - triggerKeyDown(element, 'up', true); - checkActivedescendant(); + it('will not respond when trying to move to lower mode', function() { + triggerKeyDown(element, 'down', true); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('September 2010'); + }); }); - }); - }); + describe('month mode', function() { + beforeEach(function() { + triggerKeyDown(element, 'up', true); + }); - }); + it('will be able to activate previous month', function() { + triggerKeyDown(element, 'left'); + expect(getActiveLabel()).toBe('August'); + }); - describe('attribute `starting-day`', function () { - beforeEach(function() { - $rootScope.startingDay = 1; - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + it('will be able to activate next month', function() { + triggerKeyDown(element, 'right'); + expect(getActiveLabel()).toBe('October'); + }); - it('shows the day labels rotated', function() { - expect(getLabels(true)).toEqual(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']); - }); + it('will be able to activate same month in previous row', function() { + triggerKeyDown(element, 'up'); + expect(getActiveLabel()).toBe('June'); + }); - it('renders the calendar days correctly', function() { - expect(getOptions(true)).toEqual([ - ['30', '31', '01', '02', '03', '04', '05'], - ['06', '07', '08', '09', '10', '11', '12'], - ['13', '14', '15', '16', '17', '18', '19'], - ['20', '21', '22', '23', '24', '25', '26'], - ['27', '28', '29', '30', '01', '02', '03'], - ['04', '05', '06', '07', '08', '09', '10'] - ]); - }); + it('will be able to activate same month in next row', function() { + triggerKeyDown(element, 'down'); + expect(getActiveLabel()).toBe('December'); + }); - it('renders the week numbers correctly', function() { - expect(getWeeks()).toEqual(['35', '36', '37', '38', '39', '40']); - }); - }); + it('will be able to activate same date in previous year', function() { + triggerKeyDown(element, 'pageup'); + expect(getActiveLabel()).toBe('September'); + expect(getTitle()).toBe('2009'); + }); - describe('attribute `show-weeks`', function () { - beforeEach(function() { - $rootScope.showWeeks = false; - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + it('will be able to activate same date in next year', function() { + triggerKeyDown(element, 'pagedown'); + expect(getActiveLabel()).toBe('September'); + expect(getTitle()).toBe('2011'); + }); - it('hides week numbers based on variable', function() { - expect(getLabelsRow().find('th').length).toEqual(7); - var tr = element.find('tbody').find('tr'); - for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').length).toEqual(7); - } - }); - }); + it('will be able to activate first month of the year', function() { + triggerKeyDown(element, 'home'); + expect(getActiveLabel()).toBe('January'); + expect(getTitle()).toBe('2010'); + }); - describe('`min-date` attribute', function () { - beforeEach(function() { - $rootScope.mindate = new Date('September 12, 2010'); - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + it('will be able to activate last month of the year', function() { + triggerKeyDown(element, 'end'); + expect(getActiveLabel()).toBe('December'); + expect(getTitle()).toBe('2010'); + }); - it('disables appropriate days in current month', function() { - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index < 14 ); - }); - }); + it('will be able to move to year mode', function() { + triggerKeyDown(element, 'up', true); + expect(getActiveLabel()).toBe('2010'); + expect(getTitle()).toBe('2001 - 2020'); + }); - it('disables appropriate days when min date changes', function() { - $rootScope.mindate = new Date('September 5, 2010'); - $rootScope.$digest(); + it('will be able to move to day mode', function() { + triggerKeyDown(element, 'down', true); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('September 2010'); + }); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index < 7 ); - }); - }); + it('will move to day mode when selecting', function() { + triggerKeyDown(element, 'left', true); + triggerKeyDown(element, 'enter', true); + expect(getActiveLabel()).toBe('30'); + expect(getTitle()).toBe('August 2010'); + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + }); + }); - it('invalidates when model is a disabled date', function() { - $rootScope.mindate = new Date('September 5, 2010'); - $rootScope.date = new Date('September 2, 2010'); - $rootScope.$digest(); - expect(element.hasClass('ng-invalid')).toBeTruthy(); - expect(element.hasClass('ng-invalid-date-disabled')).toBeTruthy(); - }); + describe('year mode', function() { + beforeEach(function() { + triggerKeyDown(element, 'up', true); + triggerKeyDown(element, 'up', true); + }); - it('disables all days in previous month', function() { - clickPreviousButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( true ); - }); - }); + it('will be able to activate previous year', function() { + triggerKeyDown(element, 'left'); + expect(getActiveLabel()).toBe('2009'); + }); - it('disables no days in next month', function() { - clickNextButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); - }); - }); + it('will be able to activate next year', function() { + triggerKeyDown(element, 'right'); + expect(getActiveLabel()).toBe('2011'); + }); - it('disables appropriate months in current year', function() { - clickTitleButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index < 8 ); - }); - }); + it('will be able to activate same year in previous row', function() { + triggerKeyDown(element, 'up'); + expect(getActiveLabel()).toBe('2005'); + }); - it('disables all months in previous year', function() { - clickTitleButton(); - clickPreviousButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( true ); - }); - }); + it('will be able to activate same year in next row', function() { + triggerKeyDown(element, 'down'); + expect(getActiveLabel()).toBe('2015'); + }); - it('disables no months in next year', function() { - clickTitleButton(); - clickNextButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); - }); - }); + it('will be able to activate same date in previous view', function() { + triggerKeyDown(element, 'pageup'); + expect(getActiveLabel()).toBe('1990'); + }); - it('enables everything before if it is cleared', function() { - $rootScope.mindate = null; - $rootScope.date = new Date('December 20, 1949'); - $rootScope.$digest(); + it('will be able to activate same date in next view', function() { + triggerKeyDown(element, 'pagedown'); + expect(getActiveLabel()).toBe('2030'); + }); - clickTitleButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); - }); - }); + it('will be able to activate first year of the year', function() { + triggerKeyDown(element, 'home'); + expect(getActiveLabel()).toBe('2001'); + }); - }); + it('will be able to activate last year of the year', function() { + triggerKeyDown(element, 'end'); + expect(getActiveLabel()).toBe('2020'); + }); - describe('`max-date` attribute', function () { - beforeEach(function() { - $rootScope.maxdate = new Date('September 25, 2010'); - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + it('will not respond when trying to move to upper mode', function() { + triggerKeyDown(element, 'up', true); + expect(getTitle()).toBe('2001 - 2020'); + }); - it('disables appropriate days in current month', function() { - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index > 27 ); - }); - }); + it('will be able to move to month mode', function() { + triggerKeyDown(element, 'down', true); + expect(getActiveLabel()).toBe('September'); + expect(getTitle()).toBe('2010'); + }); - it('disables appropriate days when max date changes', function() { - $rootScope.maxdate = new Date('September 18, 2010'); - $rootScope.$digest(); + it('will move to month mode when selecting', function() { + triggerKeyDown(element, 'left', true); + triggerKeyDown(element, 'enter', true); + expect(getActiveLabel()).toBe('September'); + expect(getTitle()).toBe('2009'); + expect($rootScope.date).toEqual(new Date('September 30, 2010 15:30:00')); + }); + }); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index > 20 ); - }); - }); + describe('`aria-activedescendant`', function() { + function checkActivedescendant() { + var activeId = element.find('table').attr('aria-activedescendant'); + expect(element.find('#' + activeId + ' > button')).toHaveClass('active'); + } - it('invalidates when model is a disabled date', function() { - $rootScope.maxdate = new Date('September 18, 2010'); - $rootScope.$digest(); - expect(element.hasClass('ng-invalid')).toBeTruthy(); - expect(element.hasClass('ng-invalid-date-disabled')).toBeTruthy(); - }); + it('updates correctly', function() { + triggerKeyDown(element, 'left'); + checkActivedescendant(); + + triggerKeyDown(element, 'down'); + checkActivedescendant(); + + triggerKeyDown(element, 'up', true); + checkActivedescendant(); + + triggerKeyDown(element, 'up', true); + checkActivedescendant(); + }); + }); - it('disables no days in previous month', function() { - clickPreviousButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); }); + }); - it('disables all days in next month', function() { - clickNextButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( true ); + describe('attribute `starting-day`', function () { + beforeEach(function() { + $rootScope.startingDay = 1; + element = $compile('')($rootScope); + $rootScope.$digest(); }); - }); - it('disables appropriate months in current year', function() { - clickTitleButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( index > 8 ); + it('shows the day labels rotated', function() { + expect(getLabels(true)).toEqual(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']); }); - }); - it('disables no months in previous year', function() { - clickTitleButton(); - clickPreviousButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); + it('renders the calendar days correctly', function() { + expect(getOptions(true)).toEqual([ + ['30', '31', '01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10', '11', '12'], + ['13', '14', '15', '16', '17', '18', '19'], + ['20', '21', '22', '23', '24', '25', '26'], + ['27', '28', '29', '30', '01', '02', '03'], + ['04', '05', '06', '07', '08', '09', '10'] + ]); }); - }); - it('disables all months in next year', function() { - clickTitleButton(); - clickNextButton(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( true ); + it('renders the week numbers correctly', function() { + expect(getWeeks()).toEqual(['35', '36', '37', '38', '39', '40']); }); }); - it('enables everything after if it is cleared', function() { - $rootScope.maxdate = null; - $rootScope.$digest(); - var buttons = getAllOptionsEl(); - angular.forEach(buttons, function( button, index ) { - expect(angular.element(button).prop('disabled')).toBe( false ); + describe('attribute `show-weeks`', function () { + beforeEach(function() { + $rootScope.showWeeks = false; + element = $compile('')($rootScope); + $rootScope.$digest(); }); - }); - }); - describe('date-disabled expression', function () { - beforeEach(function() { - $rootScope.dateDisabledHandler = jasmine.createSpy('dateDisabledHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); + it('hides week numbers based on variable', function() { + expect(getLabelsRow().find('th').length).toEqual(7); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').length).toEqual(7); + } + }); }); - it('executes the dateDisabled expression for each visible day plus one for validation', function() { - expect($rootScope.dateDisabledHandler.calls.count()).toEqual(42 + 1); - }); + describe('`min-date` attribute', function () { + beforeEach(function() { + $rootScope.mindate = new Date('September 12, 2010'); + element = $compile('')($rootScope); + $rootScope.$digest(); + }); - it('executes the dateDisabled expression for each visible month plus one for validation', function() { - $rootScope.dateDisabledHandler.calls.reset(); - clickTitleButton(); - expect($rootScope.dateDisabledHandler.calls.count()).toEqual(12 + 1); - }); + it('disables appropriate days in current month', function() { + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index < 14 ); + }); + }); - it('executes the dateDisabled expression for each visible year plus one for validation', function() { - clickTitleButton(); - $rootScope.dateDisabledHandler.calls.reset(); - clickTitleButton(); - expect($rootScope.dateDisabledHandler.calls.count()).toEqual(20 + 1); - }); - }); + it('disables appropriate days when min date changes', function() { + $rootScope.mindate = new Date('September 5, 2010'); + $rootScope.$digest(); - describe('custom-class expression', function () { - beforeEach(function() { - $rootScope.customClassHandler = jasmine.createSpy('customClassHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index < 7 ); + }); + }); - it('executes the customClass expression for each visible day plus one for validation', function() { - expect($rootScope.customClassHandler.calls.count()).toEqual(42); - }); + it('invalidates when model is a disabled date', function() { + $rootScope.mindate = new Date('September 5, 2010'); + $rootScope.date = new Date('September 2, 2010'); + $rootScope.$digest(); + expect(element.hasClass('ng-invalid')).toBeTruthy(); + expect(element.hasClass('ng-invalid-date-disabled')).toBeTruthy(); + }); - it('executes the customClass expression for each visible month plus one for validation', function() { - $rootScope.customClassHandler.calls.reset(); - clickTitleButton(); - expect($rootScope.customClassHandler.calls.count()).toEqual(12); - }); + it('disables all days in previous month', function() { + clickPreviousButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( true ); + }); + }); - it('executes the customClass expression for each visible year plus one for validation', function() { - clickTitleButton(); - $rootScope.customClassHandler.calls.reset(); - clickTitleButton(); - expect($rootScope.customClassHandler.calls.count()).toEqual(20); - }); - }); + it('disables no days in next month', function() { + clickNextButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); - describe('formatting', function () { - beforeEach(function() { - $rootScope.dayTitle = 'MMMM, yy'; - element = $compile('')($rootScope); - $rootScope.$digest(); - }); + it('disables appropriate months in current year', function() { + clickTitleButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index < 8 ); + }); + }); - it('changes the title format in `day` mode', function() { - expect(getTitle()).toBe('September, 10'); - }); + it('disables all months in previous year', function() { + clickTitleButton(); + clickPreviousButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( true ); + }); + }); - it('changes the title & months format in `month` mode', function() { - clickTitleButton(); + it('disables no months in next year', function() { + clickTitleButton(); + clickNextButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); - expect(getTitle()).toBe('10'); - expect(getOptions()).toEqual([ - ['Jan', 'Feb', 'Mar'], - ['Apr', 'May', 'Jun'], - ['Jul', 'Aug', 'Sep'], - ['Oct', 'Nov', 'Dec'] - ]); - }); + it('enables everything before if it is cleared', function() { + $rootScope.mindate = null; + $rootScope.date = new Date('December 20, 1949'); + $rootScope.$digest(); - it('changes the title, year format & range in `year` mode', function() { - clickTitleButton(); - clickTitleButton(); + clickTitleButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); - expect(getTitle()).toBe('01 - 10'); - expect(getOptions()).toEqual([ - ['01', '02', '03', '04', '05'], - ['06', '07', '08', '09', '10'] - ]); }); - it('shows day labels', function() { - expect(getLabels(true)).toEqual(['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']); - }); + describe('`max-date` attribute', function () { + beforeEach(function() { + $rootScope.maxdate = new Date('September 25, 2010'); + element = $compile('')($rootScope); + $rootScope.$digest(); + }); - it('changes the day format', function() { - expect(getOptions(true)).toEqual([ - ['29', '30', '31', '1', '2', '3', '4'], - ['5', '6', '7', '8', '9', '10', '11'], - ['12', '13', '14', '15', '16', '17', '18'], - ['19', '20', '21', '22', '23', '24', '25'], - ['26', '27', '28', '29', '30', '1', '2'], - ['3', '4', '5', '6', '7', '8', '9'] - ]); - }); - }); + it('disables appropriate days in current month', function() { + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index > 27 ); + }); + }); - describe('setting datepickerConfig', function() { - var originalConfig = {}; - beforeEach(inject(function(datepickerConfig) { - angular.extend(originalConfig, datepickerConfig); - datepickerConfig.formatDay = 'd'; - datepickerConfig.formatMonth = 'MMM'; - datepickerConfig.formatYear = 'yy'; - datepickerConfig.formatDayHeader = 'EEEE'; - datepickerConfig.formatDayTitle = 'MMM, yy'; - datepickerConfig.formatMonthTitle = 'yy'; - datepickerConfig.showWeeks = false; - datepickerConfig.yearRange = 10; - datepickerConfig.startingDay = 6; - - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - afterEach(inject(function(datepickerConfig) { - // return it to the original state - angular.extend(datepickerConfig, originalConfig); - })); + it('disables appropriate days when max date changes', function() { + $rootScope.maxdate = new Date('September 18, 2010'); + $rootScope.$digest(); - it('changes the title format in `day` mode', function() { - expect(getTitle()).toBe('Sep, 10'); - }); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index > 20 ); + }); + }); - it('changes the title & months format in `month` mode', function() { - clickTitleButton(); + it('invalidates when model is a disabled date', function() { + $rootScope.maxdate = new Date('September 18, 2010'); + $rootScope.$digest(); + expect(element.hasClass('ng-invalid')).toBeTruthy(); + expect(element.hasClass('ng-invalid-date-disabled')).toBeTruthy(); + }); - expect(getTitle()).toBe('10'); - expect(getOptions()).toEqual([ - ['Jan', 'Feb', 'Mar'], - ['Apr', 'May', 'Jun'], - ['Jul', 'Aug', 'Sep'], - ['Oct', 'Nov', 'Dec'] - ]); - }); + it('disables no days in previous month', function() { + clickPreviousButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); - it('changes the title, year format & range in `year` mode', function() { - clickTitleButton(); - clickTitleButton(); + it('disables all days in next month', function() { + clickNextButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( true ); + }); + }); - expect(getTitle()).toBe('01 - 10'); - expect(getOptions()).toEqual([ - ['01', '02', '03', '04', '05'], - ['06', '07', '08', '09', '10'] - ]); - }); + it('disables appropriate months in current year', function() { + clickTitleButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( index > 8 ); + }); + }); - it('changes the `starting-day` & day headers & format', function() { - expect(getLabels()).toEqual(['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']); - expect(getOptions(false)).toEqual([ - ['28', '29', '30', '31', '1', '2', '3'], - ['4', '5', '6', '7', '8', '9', '10'], - ['11', '12', '13', '14', '15', '16', '17'], - ['18', '19', '20', '21', '22', '23', '24'], - ['25', '26', '27', '28', '29', '30', '1'], - ['2', '3', '4', '5', '6', '7', '8'] - ]); - }); + it('disables no months in previous year', function() { + clickTitleButton(); + clickPreviousButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); - it('changes initial visibility for weeks', function() { - expect(getLabelsRow().find('th').length).toEqual(7); - var tr = element.find('tbody').find('tr'); - for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').length).toEqual(7); - } + it('disables all months in next year', function() { + clickTitleButton(); + clickNextButton(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( true ); + }); + }); + + it('enables everything after if it is cleared', function() { + $rootScope.maxdate = null; + $rootScope.$digest(); + var buttons = getAllOptionsEl(); + angular.forEach(buttons, function( button, index ) { + expect(angular.element(button).prop('disabled')).toBe( false ); + }); + }); }); - }); + describe('date-disabled expression', function () { + beforeEach(function() { + $rootScope.dateDisabledHandler = jasmine.createSpy('dateDisabledHandler'); + element = $compile('')($rootScope); + $rootScope.$digest(); + }); - describe('setting datepickerPopupConfig', function() { - var originalConfig = {}; - beforeEach(inject(function(datepickerPopupConfig) { - angular.extend(originalConfig, datepickerPopupConfig); - datepickerPopupConfig.datepickerPopup = 'MM-dd-yyyy'; + it('executes the dateDisabled expression for each visible day plus one for validation', function() { + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(42 + 1); + }); - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - afterEach(inject(function(datepickerPopupConfig) { - // return it to the original state - angular.extend(datepickerPopupConfig, originalConfig); - })); + it('executes the dateDisabled expression for each visible month plus one for validation', function() { + $rootScope.dateDisabledHandler.calls.reset(); + clickTitleButton(); + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(12 + 1); + }); - it('changes date format', function() { - expect(element.val()).toEqual('09-30-2010'); + it('executes the dateDisabled expression for each visible year plus one for validation', function() { + clickTitleButton(); + $rootScope.dateDisabledHandler.calls.reset(); + clickTitleButton(); + expect($rootScope.dateDisabledHandler.calls.count()).toEqual(20 + 1); + }); }); - }); + describe('custom-class expression', function () { + beforeEach(function() { + $rootScope.customClassHandler = jasmine.createSpy('customClassHandler'); + element = $compile('')($rootScope); + $rootScope.$digest(); + }); - describe('setting datepickerPopupConfig inside ng-if', function() { - var originalConfig = {}; - beforeEach(inject(function (datepickerPopupConfig) { - angular.extend(originalConfig, datepickerPopupConfig); - datepickerPopupConfig.datepickerPopup = 'MM-dd-yyyy'; + it('executes the customClass expression for each visible day plus one for validation', function() { + expect($rootScope.customClassHandler.calls.count()).toEqual(42); + }); - element = $compile('
')($rootScope); - $rootScope.$digest(); - })); - afterEach(inject(function (datepickerPopupConfig) { - // return it to the original state - angular.extend(datepickerPopupConfig, originalConfig); - })); + it('executes the customClass expression for each visible month plus one for validation', function() { + $rootScope.customClassHandler.calls.reset(); + clickTitleButton(); + expect($rootScope.customClassHandler.calls.count()).toEqual(12); + }); - it('changes date format', function () { - expect(element.find('input').val()).toEqual('09-30-2010'); + it('executes the customClass expression for each visible year plus one for validation', function() { + clickTitleButton(); + $rootScope.customClassHandler.calls.reset(); + clickTitleButton(); + expect($rootScope.customClassHandler.calls.count()).toEqual(20); + }); }); - }); - - describe('as popup', function () { - var inputEl, dropdownEl, $document, $sniffer, $timeout; - function assignElements(wrapElement) { - inputEl = wrapElement.find('input'); - dropdownEl = wrapElement.find('ul'); - element = dropdownEl.find('table'); - } - - function changeInputValueTo(el, value) { - el.val(value); - el.trigger($sniffer.hasEvent('input') ? 'input' : 'change'); - $rootScope.$digest(); - } - - describe('initially', function () { - beforeEach(inject(function(_$document_, _$sniffer_) { - $document = _$document_; - $sniffer = _$sniffer_; - $rootScope.isopen = true; - $rootScope.date = new Date('September 30, 2010 15:30:00'); - var wrapElement = $compile('
')($rootScope); + describe('formatting', function () { + beforeEach(function() { + $rootScope.dayTitle = 'MMMM, yy'; + element = $compile('')($rootScope); $rootScope.$digest(); - assignElements(wrapElement); - })); + }); - it('does not to display datepicker initially', function() { - expect(dropdownEl.length).toBe(0); + it('changes the title format in `day` mode', function() { + expect(getTitle()).toBe('September, 10'); }); - it('to display the correct value in input', function() { - expect(inputEl.val()).toBe('2010-09-30'); + it('changes the title & months format in `month` mode', function() { + clickTitleButton(); + + expect(getTitle()).toBe('10'); + expect(getOptions()).toEqual([ + ['Jan', 'Feb', 'Mar'], + ['Apr', 'May', 'Jun'], + ['Jul', 'Aug', 'Sep'], + ['Oct', 'Nov', 'Dec'] + ]); }); - }); - describe('initially opened', function () { - var wrapElement; + it('changes the title, year format & range in `year` mode', function() { + clickTitleButton(); + clickTitleButton(); - beforeEach(inject(function(_$document_, _$sniffer_, _$timeout_) { - $document = _$document_; - $sniffer = _$sniffer_; - $timeout = _$timeout_; - $rootScope.isopen = true; - $rootScope.date = new Date('September 30, 2010 15:30:00'); - wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); + expect(getTitle()).toBe('01 - 10'); + expect(getOptions()).toEqual([ + ['01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10'] + ]); + }); - it('datepicker is displayed', function() { - expect(dropdownEl.length).toBe(1); + it('shows day labels', function() { + expect(getLabels(true)).toEqual(['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']); }); - it('renders the calendar correctly', function() { - expect(getLabelsRow().css('display')).not.toBe('none'); - expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); + it('changes the day format', function() { expect(getOptions(true)).toEqual([ - ['29', '30', '31', '01', '02', '03', '04'], - ['05', '06', '07', '08', '09', '10', '11'], + ['29', '30', '31', '1', '2', '3', '4'], + ['5', '6', '7', '8', '9', '10', '11'], ['12', '13', '14', '15', '16', '17', '18'], ['19', '20', '21', '22', '23', '24', '25'], - ['26', '27', '28', '29', '30', '01', '02'], - ['03', '04', '05', '06', '07', '08', '09'] + ['26', '27', '28', '29', '30', '1', '2'], + ['3', '4', '5', '6', '7', '8', '9'] ]); }); + }); - it('updates the input when a day is clicked', function() { - clickOption(17); - expect(inputEl.val()).toBe('2010-09-15'); - expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); - }); + describe('setting datepickerConfig', function() { + var originalConfig = {}; + beforeEach(inject(function(datepickerConfig) { + angular.extend(originalConfig, datepickerConfig); + datepickerConfig.formatDay = 'd'; + datepickerConfig.formatMonth = 'MMM'; + datepickerConfig.formatYear = 'yy'; + datepickerConfig.formatDayHeader = 'EEEE'; + datepickerConfig.formatDayTitle = 'MMM, yy'; + datepickerConfig.formatMonthTitle = 'yy'; + datepickerConfig.showWeeks = false; + datepickerConfig.yearRange = 10; + datepickerConfig.startingDay = 6; - it('should mark the input field dirty when a day is clicked', function() { - expect(inputEl).toHaveClass('ng-pristine'); - clickOption(17); - expect(inputEl).toHaveClass('ng-dirty'); - }); + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + afterEach(inject(function(datepickerConfig) { + // return it to the original state + angular.extend(datepickerConfig, originalConfig); + })); - it('updates the input correctly when model changes', function() { - $rootScope.date = new Date('January 10, 1983 10:00:00'); - $rootScope.$digest(); - expect(inputEl.val()).toBe('1983-01-10'); + it('changes the title format in `day` mode', function() { + expect(getTitle()).toBe('Sep, 10'); }); - it('closes the dropdown when a day is clicked', function() { - expect(dropdownEl.length).toBe(1); + it('changes the title & months format in `month` mode', function() { + clickTitleButton(); - clickOption(17); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(0); + expect(getTitle()).toBe('10'); + expect(getOptions()).toEqual([ + ['Jan', 'Feb', 'Mar'], + ['Apr', 'May', 'Jun'], + ['Jul', 'Aug', 'Sep'], + ['Oct', 'Nov', 'Dec'] + ]); }); - it('updates the model & calendar when input value changes', function() { - changeInputValueTo(inputEl, '2010-09-15'); - - expect($rootScope.date.getFullYear()).toEqual(2010); - expect($rootScope.date.getMonth()).toEqual(8); - expect($rootScope.date.getDate()).toEqual(15); + it('changes the title, year format & range in `year` mode', function() { + clickTitleButton(); + clickTitleButton(); - expect(getOptions(true)).toEqual([ - ['29', '30', '31', '01', '02', '03', '04'], - ['05', '06', '07', '08', '09', '10', '11'], - ['12', '13', '14', '15', '16', '17', '18'], - ['19', '20', '21', '22', '23', '24', '25'], - ['26', '27', '28', '29', '30', '01', '02'], - ['03', '04', '05', '06', '07', '08', '09'] + expect(getTitle()).toBe('01 - 10'); + expect(getOptions()).toEqual([ + ['01', '02', '03', '04', '05'], + ['06', '07', '08', '09', '10'] ]); - expectSelectedElement( 17 ); }); - it('closes when click outside of calendar', function() { - expect(dropdownEl.length).toBe(1); - - $timeout.flush(0); - $document.find('body').click(); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(0); + it('changes the `starting-day` & day headers & format', function() { + expect(getLabels()).toEqual(['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']); + expect(getOptions(false)).toEqual([ + ['28', '29', '30', '31', '1', '2', '3'], + ['4', '5', '6', '7', '8', '9', '10'], + ['11', '12', '13', '14', '15', '16', '17'], + ['18', '19', '20', '21', '22', '23', '24'], + ['25', '26', '27', '28', '29', '30', '1'], + ['2', '3', '4', '5', '6', '7', '8'] + ]); }); - it('sets `ng-invalid` for invalid input', function() { - changeInputValueTo(inputEl, 'pizza'); - - expect(inputEl).toHaveClass('ng-invalid'); - expect(inputEl).toHaveClass('ng-invalid-date'); - expect($rootScope.date).toBeUndefined(); - expect(inputEl.val()).toBe('pizza'); + it('changes initial visibility for weeks', function() { + expect(getLabelsRow().find('th').length).toEqual(7); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').length).toEqual(7); + } }); - it('unsets `ng-invalid` for valid input', function() { - changeInputValueTo(inputEl, 'pizza'); - expect(inputEl).toHaveClass('ng-invalid-date'); + }); - $rootScope.date = new Date('August 11, 2013'); + describe('setting datepickerPopupConfig', function() { + var originalConfig = {}; + beforeEach(inject(function(datepickerPopupConfig) { + angular.extend(originalConfig, datepickerPopupConfig); + datepickerPopupConfig.datepickerPopup = 'MM-dd-yyyy'; + + element = $compile('')($rootScope); $rootScope.$digest(); - expect(inputEl).not.toHaveClass('ng-invalid'); - expect(inputEl).not.toHaveClass('ng-invalid-date'); + })); + afterEach(inject(function(datepickerPopupConfig) { + // return it to the original state + angular.extend(datepickerPopupConfig, originalConfig); + })); + + it('changes date format', function() { + expect(element.val()).toEqual('09-30-2010'); }); - describe('focus', function () { - beforeEach(function() { - var body = $document.find('body'); - body.append(inputEl); - body.append(dropdownEl); - }); + }); - afterEach(function() { - inputEl.remove(); - dropdownEl.remove(); - }); + describe('setting datepickerPopupConfig inside ng-if', function() { + var originalConfig = {}; + beforeEach(inject(function (datepickerPopupConfig) { + angular.extend(originalConfig, datepickerPopupConfig); + datepickerPopupConfig.datepickerPopup = 'MM-dd-yyyy'; - it('returns to the input when ESC key is pressed in the popup and closes', function() { - expect(dropdownEl.length).toBe(1); + element = $compile('
')($rootScope); + $rootScope.$digest(); + })); + afterEach(inject(function (datepickerPopupConfig) { + // return it to the original state + angular.extend(datepickerPopupConfig, originalConfig); + })); - dropdownEl.find('button').eq(0).focus(); - expect(document.activeElement.tagName).toBe('BUTTON'); + it('changes date format', function () { + expect(element.find('input').val()).toEqual('09-30-2010'); + }); + }); - triggerKeyDown(dropdownEl, 'esc'); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(0); - expect(document.activeElement.tagName).toBe('INPUT'); - }); + describe('as popup', function () { + var inputEl, dropdownEl, $document, $sniffer, $timeout; - it('returns to the input when ESC key is pressed in the input and closes', function() { - expect(dropdownEl.length).toBe(1); + function assignElements(wrapElement) { + inputEl = wrapElement.find('input'); + dropdownEl = wrapElement.find('ul'); + element = dropdownEl.find('table'); + } - dropdownEl.find('button').eq(0).focus(); - expect(document.activeElement.tagName).toBe('BUTTON'); + function changeInputValueTo(el, value) { + el.val(value); + el.trigger($sniffer.hasEvent('input') ? 'input' : 'change'); + $rootScope.$digest(); + } - triggerKeyDown(inputEl, 'esc'); + describe('initially', function () { + beforeEach(inject(function(_$document_, _$sniffer_) { + $document = _$document_; + $sniffer = _$sniffer_; + $rootScope.isopen = true; + $rootScope.date = new Date('September 30, 2010 15:30:00'); + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); + })); + + it('does not to display datepicker initially', function() { expect(dropdownEl.length).toBe(0); - expect(document.activeElement.tagName).toBe('INPUT'); }); - it('stops the ESC key from propagating if the dropdown is open, but not when closed', function() { - var documentKey = -1; - var getKey = function(evt) { documentKey = evt.which; }; - $document.bind('keydown', getKey); - - triggerKeyDown(inputEl, 'esc'); - expect(documentKey).toBe(-1); - - triggerKeyDown(inputEl, 'esc'); - expect(documentKey).toBe(27); - - $document.unbind('keydown', getKey); + it('to display the correct value in input', function() { + expect(inputEl.val()).toBe('2010-09-30'); }); }); - describe('works with ngModelOptions', function () { - var $timeout; + describe('initially opened', function () { + var wrapElement; beforeEach(inject(function(_$document_, _$sniffer_, _$timeout_) { $document = _$document_; + $sniffer = _$sniffer_; $timeout = _$timeout_; $rootScope.isopen = true; $rootScope.date = new Date('September 30, 2010 15:30:00'); - var wrapElement = $compile('
')($rootScope); + wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); - it('should change model and update calendar after debounce timeout', function() { - changeInputValueTo(inputEl, '1980-03-05'); - - expect($rootScope.date.getFullYear()).toEqual(2010); - expect($rootScope.date.getMonth()).toEqual(9 - 1); - expect($rootScope.date.getDate()).toEqual(30); + it('datepicker is displayed', function() { + expect(dropdownEl.length).toBe(1); + }); + it('renders the calendar correctly', function() { + expect(getLabelsRow().css('display')).not.toBe('none'); + expect(getLabels(true)).toEqual(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); expect(getOptions(true)).toEqual([ ['29', '30', '31', '01', '02', '03', '04'], ['05', '06', '07', '08', '09', '10', '11'], @@ -1403,12 +1315,40 @@ describe('datepicker directive', function () { ['26', '27', '28', '29', '30', '01', '02'], ['03', '04', '05', '06', '07', '08', '09'] ]); + }); + + it('updates the input when a day is clicked', function() { + clickOption(17); + expect(inputEl.val()).toBe('2010-09-15'); + expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); + }); + + it('should mark the input field dirty when a day is clicked', function() { + expect(inputEl).toHaveClass('ng-pristine'); + clickOption(17); + expect(inputEl).toHaveClass('ng-dirty'); + }); + + it('updates the input correctly when model changes', function() { + $rootScope.date = new Date('January 10, 1983 10:00:00'); + $rootScope.$digest(); + expect(inputEl.val()).toBe('1983-01-10'); + }); + + it('closes the dropdown when a day is clicked', function() { + expect(dropdownEl.length).toBe(1); + + clickOption(17); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); + }); + + it('updates the model & calendar when input value changes', function() { + changeInputValueTo(inputEl, '2010-09-15'); - // No changes yet - $timeout.flush(2000); expect($rootScope.date.getFullYear()).toEqual(2010); - expect($rootScope.date.getMonth()).toEqual(9 - 1); - expect($rootScope.date.getDate()).toEqual(30); + expect($rootScope.date.getMonth()).toEqual(8); + expect($rootScope.date.getDate()).toEqual(15); expect(getOptions(true)).toEqual([ ['29', '30', '31', '01', '02', '03', '04'], @@ -1418,584 +1358,794 @@ describe('datepicker directive', function () { ['26', '27', '28', '29', '30', '01', '02'], ['03', '04', '05', '06', '07', '08', '09'] ]); + expectSelectedElement( 17 ); + }); - $timeout.flush(10000); - expect($rootScope.date.getFullYear()).toEqual(1980); - expect($rootScope.date.getMonth()).toEqual(2); - expect($rootScope.date.getDate()).toEqual(5); + it('closes when click outside of calendar', function() { + expect(dropdownEl.length).toBe(1); - expect(getOptions(true)).toEqual([ - ['24', '25', '26', '27', '28', '29', '01'], - ['02', '03', '04', '05', '06', '07', '08'], - ['09', '10', '11', '12', '13', '14', '15'], - ['16', '17', '18', '19', '20', '21', '22'], - ['23', '24', '25', '26', '27', '28', '29'], - ['30', '31', '01', '02', '03', '04', '05'] - ]); - expectSelectedElement( 10 ); + $timeout.flush(0); + $document.find('body').click(); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); }); - }); - - describe('works with HTML5 date input types', function () { - var date2 = new Date('October 1, 2010 12:34:56.789'); - beforeEach(inject(function(_$document_) { - $document = _$document_; - $rootScope.isopen = true; - $rootScope.date = new Date('September 30, 2010 15:30:00'); - })); - it('works as date', function() { - setupInputWithType('date'); - expect(dropdownEl.length).toBe(1); - expect(inputEl.val()).toBe('2010-09-30'); + it('sets `ng-invalid` for invalid input', function() { + changeInputValueTo(inputEl, 'pizza'); - changeInputValueTo(inputEl, '1980-03-05'); + expect(inputEl).toHaveClass('ng-invalid'); + expect(inputEl).toHaveClass('ng-invalid-date'); + expect($rootScope.date).toBeUndefined(); + expect(inputEl.val()).toBe('pizza'); + }); - expect($rootScope.date.getFullYear()).toEqual(1980); - expect($rootScope.date.getMonth()).toEqual(2); - expect($rootScope.date.getDate()).toEqual(5); + it('unsets `ng-invalid` for valid input', function() { + changeInputValueTo(inputEl, 'pizza'); + expect(inputEl).toHaveClass('ng-invalid-date'); - expect(getOptions(true)).toEqual([ - ['24', '25', '26', '27', '28', '29', '01'], - ['02', '03', '04', '05', '06', '07', '08'], - ['09', '10', '11', '12', '13', '14', '15'], - ['16', '17', '18', '19', '20', '21', '22'], - ['23', '24', '25', '26', '27', '28', '29'], - ['30', '31', '01', '02', '03', '04', '05'] - ]); - expect(selectedElementIndex()).toEqual( 10 ); + $rootScope.date = new Date('August 11, 2013'); + $rootScope.$digest(); + expect(inputEl).not.toHaveClass('ng-invalid'); + expect(inputEl).not.toHaveClass('ng-invalid-date'); }); - it('works as datetime-local', function() { - setupInputWithType('datetime-local'); - expect(inputEl.val()).toBe('2010-09-30T15:30:00.000'); + describe('focus', function () { + beforeEach(function() { + var body = $document.find('body'); + body.append(inputEl); + body.append(dropdownEl); + }); + + afterEach(function() { + inputEl.remove(); + dropdownEl.remove(); + }); - changeInputValueTo(inputEl, '1980-03-05T12:34:56.000'); + it('returns to the input when ESC key is pressed in the popup and closes', function() { + expect(dropdownEl.length).toBe(1); - expect($rootScope.date.getFullYear()).toEqual(1980); - expect($rootScope.date.getMonth()).toEqual(2); - expect($rootScope.date.getDate()).toEqual(5); + dropdownEl.find('button').eq(0).focus(); + expect(document.activeElement.tagName).toBe('BUTTON'); - expect(getOptions(true)).toEqual([ - ['24', '25', '26', '27', '28', '29', '01'], - ['02', '03', '04', '05', '06', '07', '08'], - ['09', '10', '11', '12', '13', '14', '15'], - ['16', '17', '18', '19', '20', '21', '22'], - ['23', '24', '25', '26', '27', '28', '29'], - ['30', '31', '01', '02', '03', '04', '05'] - ]); - expect(selectedElementIndex()).toEqual( 10 ); + triggerKeyDown(dropdownEl, 'esc'); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); + expect(document.activeElement.tagName).toBe('INPUT'); + }); + + it('returns to the input when ESC key is pressed in the input and closes', function() { + expect(dropdownEl.length).toBe(1); + + dropdownEl.find('button').eq(0).focus(); + expect(document.activeElement.tagName).toBe('BUTTON'); + + triggerKeyDown(inputEl, 'esc'); + $rootScope.$digest(); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); + expect(document.activeElement.tagName).toBe('INPUT'); + }); + + it('stops the ESC key from propagating if the dropdown is open, but not when closed', function() { + var documentKey = -1; + var getKey = function(evt) { documentKey = evt.which; }; + $document.bind('keydown', getKey); + + triggerKeyDown(inputEl, 'esc'); + expect(documentKey).toBe(-1); + + triggerKeyDown(inputEl, 'esc'); + expect(documentKey).toBe(27); + + $document.unbind('keydown', getKey); + }); }); - it('works as month', function() { - setupInputWithType('month'); - expect(inputEl.val()).toBe('2010-09'); + describe('works with ngModelOptions', function () { + var $timeout; + + beforeEach(inject(function(_$document_, _$sniffer_, _$timeout_) { + $document = _$document_; + $timeout = _$timeout_; + $rootScope.isopen = true; + $rootScope.date = new Date('September 30, 2010 15:30:00'); + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + })); + + it('should change model and update calendar after debounce timeout', function() { + changeInputValueTo(inputEl, '1980-03-05'); + + expect($rootScope.date.getFullYear()).toEqual(2010); + expect($rootScope.date.getMonth()).toEqual(9 - 1); + expect($rootScope.date.getDate()).toEqual(30); + + expect(getOptions(true)).toEqual([ + ['29', '30', '31', '01', '02', '03', '04'], + ['05', '06', '07', '08', '09', '10', '11'], + ['12', '13', '14', '15', '16', '17', '18'], + ['19', '20', '21', '22', '23', '24', '25'], + ['26', '27', '28', '29', '30', '01', '02'], + ['03', '04', '05', '06', '07', '08', '09'] + ]); + + // No changes yet + $timeout.flush(2000); + expect($rootScope.date.getFullYear()).toEqual(2010); + expect($rootScope.date.getMonth()).toEqual(9 - 1); + expect($rootScope.date.getDate()).toEqual(30); + + expect(getOptions(true)).toEqual([ + ['29', '30', '31', '01', '02', '03', '04'], + ['05', '06', '07', '08', '09', '10', '11'], + ['12', '13', '14', '15', '16', '17', '18'], + ['19', '20', '21', '22', '23', '24', '25'], + ['26', '27', '28', '29', '30', '01', '02'], + ['03', '04', '05', '06', '07', '08', '09'] + ]); + + $timeout.flush(10000); + expect($rootScope.date.getFullYear()).toEqual(1980); + expect($rootScope.date.getMonth()).toEqual(2); + expect($rootScope.date.getDate()).toEqual(5); + + expect(getOptions(true)).toEqual([ + ['24', '25', '26', '27', '28', '29', '01'], + ['02', '03', '04', '05', '06', '07', '08'], + ['09', '10', '11', '12', '13', '14', '15'], + ['16', '17', '18', '19', '20', '21', '22'], + ['23', '24', '25', '26', '27', '28', '29'], + ['30', '31', '01', '02', '03', '04', '05'] + ]); + expectSelectedElement( 10 ); + }); + }); - changeInputValueTo(inputEl, '1980-03'); + describe('works with HTML5 date input types', function () { + var date2 = new Date('October 1, 2010 12:34:56.789'); + beforeEach(inject(function(_$document_) { + $document = _$document_; + $rootScope.isopen = true; + $rootScope.date = new Date('September 30, 2010 15:30:00'); + })); + + it('works as date', function() { + setupInputWithType('date'); + expect(dropdownEl.length).toBe(1); + expect(inputEl.val()).toBe('2010-09-30'); + + changeInputValueTo(inputEl, '1980-03-05'); + + expect($rootScope.date.getFullYear()).toEqual(1980); + expect($rootScope.date.getMonth()).toEqual(2); + expect($rootScope.date.getDate()).toEqual(5); + + expect(getOptions(true)).toEqual([ + ['24', '25', '26', '27', '28', '29', '01'], + ['02', '03', '04', '05', '06', '07', '08'], + ['09', '10', '11', '12', '13', '14', '15'], + ['16', '17', '18', '19', '20', '21', '22'], + ['23', '24', '25', '26', '27', '28', '29'], + ['30', '31', '01', '02', '03', '04', '05'] + ]); + expect(selectedElementIndex()).toEqual( 10 ); + }); - expect($rootScope.date.getFullYear()).toEqual(1980); - expect($rootScope.date.getMonth()).toEqual(2); - expect($rootScope.date.getDate()).toEqual(30); + it('works as datetime-local', function() { + setupInputWithType('datetime-local'); + expect(inputEl.val()).toBe('2010-09-30T15:30:00.000'); + + changeInputValueTo(inputEl, '1980-03-05T12:34:56.000'); + + expect($rootScope.date.getFullYear()).toEqual(1980); + expect($rootScope.date.getMonth()).toEqual(2); + expect($rootScope.date.getDate()).toEqual(5); + + expect(getOptions(true)).toEqual([ + ['24', '25', '26', '27', '28', '29', '01'], + ['02', '03', '04', '05', '06', '07', '08'], + ['09', '10', '11', '12', '13', '14', '15'], + ['16', '17', '18', '19', '20', '21', '22'], + ['23', '24', '25', '26', '27', '28', '29'], + ['30', '31', '01', '02', '03', '04', '05'] + ]); + expect(selectedElementIndex()).toEqual( 10 ); + }); - expect(getOptions()).toEqual([ - ['January', 'February', 'March'], - ['April', 'May', 'June'], - ['July', 'August', 'September'], - ['October', 'November', 'December'] - ]); - expect(selectedElementIndex()).toEqual( 2 ); + it('works as month', function() { + setupInputWithType('month'); + expect(inputEl.val()).toBe('2010-09'); + + changeInputValueTo(inputEl, '1980-03'); + + expect($rootScope.date.getFullYear()).toEqual(1980); + expect($rootScope.date.getMonth()).toEqual(2); + expect($rootScope.date.getDate()).toEqual(30); + + expect(getOptions()).toEqual([ + ['January', 'February', 'March'], + ['April', 'May', 'June'], + ['July', 'August', 'September'], + ['October', 'November', 'December'] + ]); + expect(selectedElementIndex()).toEqual( 2 ); + }); + + function setupInputWithType(type) { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + } }); - function setupInputWithType(type) { - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - } }); - }); + describe('attribute `datepickerOptions`', function () { - describe('attribute `datepickerOptions`', function () { + describe('show-weeks', function(){ + beforeEach(function() { + $rootScope.opts = { + 'show-weeks': false + }; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + }); - describe('show-weeks', function(){ - beforeEach(function() { - $rootScope.opts = { - 'show-weeks': false - }; - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); + it('hides week numbers based on variable', function() { + expect(getLabelsRow().find('th').length).toEqual(7); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').length).toEqual(7); + } + }); }); - it('hides week numbers based on variable', function() { - expect(getLabelsRow().find('th').length).toEqual(7); - var tr = element.find('tbody').find('tr'); - for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').length).toEqual(7); - } + describe('init-date', function(){ + beforeEach(function() { + $rootScope.date = null; + $rootScope.opts = { + 'initDate': new Date('November 9, 1980') + }; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + }); + + it('does not alter the model', function() { + expect($rootScope.date).toBe(null); + }); + + it('shows the correct title', function() { + expect(getTitle()).toBe('November 1980'); + }); }); }); - describe('init-date', function(){ + describe('attribute `init-date`', function(){ beforeEach(function() { $rootScope.date = null; - $rootScope.opts = { - 'initDate': new Date('November 9, 1980') - }; - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); + $rootScope.initDate = new Date('November 9, 1980'); }); - it('does not alter the model', function() { - expect($rootScope.date).toBe(null); + describe('when initially set', function(){ + beforeEach(function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + }); + + it('does not alter the model', function() { + expect($rootScope.date).toBe(null); + }); + + it('shows the correct title', function() { + expect(getTitle()).toBe('November 1980'); + }); }); - it('shows the correct title', function() { - expect(getTitle()).toBe('November 1980'); + describe('when modified before date selected.', function(){ + beforeEach(function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + + $rootScope.initDate = new Date('December 20, 1981'); + $rootScope.$digest(); + }); + + it('does not alter the model', function() { + expect($rootScope.date).toBe(null); + }); + + it('shows the correct title', function() { + expect(getTitle()).toBe('December 1981'); + }); }); - }); - }); - describe('attribute `init-date`', function(){ - beforeEach(function() { - $rootScope.date = null; - $rootScope.initDate = new Date('November 9, 1980'); + describe('when modified after date selected.', function(){ + beforeEach(function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + $rootScope.date = new Date('April 1, 1982'); + $rootScope.initDate = new Date('December 20, 1981'); + $rootScope.$digest(); + }); + + it('does not alter the model', function() { + expect($rootScope.date).toEqual(new Date('April 1, 1982')); + }); + + it('shows the correct title', function() { + expect(getTitle()).toBe('April 1982'); + }); + }); }); - describe('when initially set', function(){ - beforeEach(function() { - var wrapElement = $compile('
')($rootScope); + describe('toggles programatically by `open` attribute', function () { + var wrapElement; + + beforeEach(inject(function() { + $rootScope.open = true; + wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); - }); + })); - it('does not alter the model', function() { - expect($rootScope.date).toBe(null); + it('to display initially', function() { + expect(dropdownEl.length).toBe(1); }); - it('shows the correct title', function() { - expect(getTitle()).toBe('November 1980'); + it('to close / open from scope variable', function() { + expect(dropdownEl.length).toBe(1); + $rootScope.open = false; + $rootScope.$digest(); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); + + $rootScope.open = true; + $rootScope.$digest(); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(1); }); }); - describe('when modified before date selected.', function(){ - beforeEach(function() { - var wrapElement = $compile('
')($rootScope); + describe('custom format', function () { + beforeEach(inject(function() { + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); + })); - $rootScope.initDate = new Date('December 20, 1981'); - $rootScope.$digest(); + it('to display the correct value in input', function() { + expect(inputEl.val()).toBe('30-September-2010'); }); - it('does not alter the model', function() { - expect($rootScope.date).toBe(null); + it('updates the input when a day is clicked', function() { + clickOption(17); + expect(inputEl.val()).toBe('15-September-2010'); + expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); }); - it('shows the correct title', function() { - expect(getTitle()).toBe('December 1981'); + it('updates the input correctly when model changes', function() { + $rootScope.date = new Date('January 10, 1983 10:00:00'); + $rootScope.$digest(); + expect(inputEl.val()).toBe('10-January-1983'); }); }); - describe('when modified after date selected.', function(){ - beforeEach(function() { - var wrapElement = $compile('
')($rootScope); + describe('dynamic custom format', function () { + beforeEach(inject(function() { + $rootScope.format = 'dd-MMMM-yyyy'; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); - $rootScope.date = new Date('April 1, 1982'); - $rootScope.initDate = new Date('December 20, 1981'); - $rootScope.$digest(); + })); + + it('to display the correct value in input', function() { + expect(inputEl.val()).toBe('30-September-2010'); }); - it('does not alter the model', function() { - expect($rootScope.date).toEqual(new Date('April 1, 1982')); + it('updates the input when a day is clicked', function() { + clickOption(17); + expect(inputEl.val()).toBe('15-September-2010'); + expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); }); - it('shows the correct title', function() { - expect(getTitle()).toBe('April 1982'); + it('updates the input correctly when model changes', function() { + $rootScope.date = new Date('August 11, 2013 09:09:00'); + $rootScope.$digest(); + expect(inputEl.val()).toBe('11-August-2013'); }); - }); - }); - describe('toggles programatically by `open` attribute', function () { - var wrapElement; + it('updates the input correctly when format changes', function() { + $rootScope.format = 'dd/MM/yyyy'; + $rootScope.$digest(); + expect(inputEl.val()).toBe('30/09/2010'); + }); + }); - beforeEach(inject(function() { - $rootScope.open = true; - wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); + describe('european format', function () { + it('dd.MM.yyyy', function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); - it('to display initially', function() { - expect(dropdownEl.length).toBe(1); + changeInputValueTo(inputEl, '11.08.2013'); + expect($rootScope.date.getFullYear()).toEqual(2013); + expect($rootScope.date.getMonth()).toEqual(7); + expect($rootScope.date.getDate()).toEqual(11); + }); }); - it('to close / open from scope variable', function() { - expect(dropdownEl.length).toBe(1); - $rootScope.open = false; - $rootScope.$digest(); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(0); + describe('`close-on-date-selection` attribute', function () { + var wrapElement; + beforeEach(inject(function() { + $rootScope.close = false; + wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + })); - $rootScope.open = true; - $rootScope.$digest(); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(1); + it('does not close the dropdown when a day is clicked', function() { + clickOption(17); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(1); + }); }); - }); - describe('custom format', function () { - beforeEach(inject(function() { - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); + describe('button bar', function() { + var buttons, buttonBarElement; - it('to display the correct value in input', function() { - expect(inputEl.val()).toBe('30-September-2010'); - }); + function assignButtonBar() { + buttonBarElement = dropdownEl.find('li').eq(-1); + buttons = buttonBarElement.find('button'); + } - it('updates the input when a day is clicked', function() { - clickOption(17); - expect(inputEl.val()).toBe('15-September-2010'); - expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); - }); + describe('', function () { + var wrapElement; - it('updates the input correctly when model changes', function() { - $rootScope.date = new Date('January 10, 1983 10:00:00'); - $rootScope.$digest(); - expect(inputEl.val()).toBe('10-January-1983'); - }); - }); + beforeEach(inject(function() { + $rootScope.isopen = true; + wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + assignButtonBar(); + })); - describe('dynamic custom format', function () { - beforeEach(inject(function() { - $rootScope.format = 'dd-MMMM-yyyy'; - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); + it('should exist', function() { + expect(dropdownEl.length).toBe(1); + expect(dropdownEl.find('li').length).toBe(2); + }); + + it('should have three buttons', function() { + expect(buttons.length).toBe(3); + + expect(buttons.eq(0).text()).toBe('Today'); + expect(buttons.eq(1).text()).toBe('Clear'); + expect(buttons.eq(2).text()).toBe('Done'); + }); - it('to display the correct value in input', function() { - expect(inputEl.val()).toBe('30-September-2010'); - }); + it('should have a button to set today date without altering time part', function() { + var today = new Date(); + buttons.eq(0).click(); + expect($rootScope.date.getFullYear()).toBe(today.getFullYear()); + expect($rootScope.date.getMonth()).toBe(today.getMonth()); + expect($rootScope.date.getDate()).toBe(today.getDate()); - it('updates the input when a day is clicked', function() { - clickOption(17); - expect(inputEl.val()).toBe('15-September-2010'); - expect($rootScope.date).toEqual(new Date('September 15, 2010 15:30:00')); - }); + expect($rootScope.date.getHours()).toBe(15); + expect($rootScope.date.getMinutes()).toBe(30); + expect($rootScope.date.getSeconds()).toBe(0); + }); - it('updates the input correctly when model changes', function() { - $rootScope.date = new Date('August 11, 2013 09:09:00'); - $rootScope.$digest(); - expect(inputEl.val()).toBe('11-August-2013'); - }); + it('should have a button to set today date if blank', function() { + $rootScope.date = null; + $rootScope.$digest(); - it('updates the input correctly when format changes', function() { - $rootScope.format = 'dd/MM/yyyy'; - $rootScope.$digest(); - expect(inputEl.val()).toBe('30/09/2010'); - }); - }); + var today = new Date(); + buttons.eq(0).click(); + expect($rootScope.date.getFullYear()).toBe(today.getFullYear()); + expect($rootScope.date.getMonth()).toBe(today.getMonth()); + expect($rootScope.date.getDate()).toBe(today.getDate()); - describe('european format', function () { - it('dd.MM.yyyy', function() { - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); + expect($rootScope.date.getHours()).toBe(0); + expect($rootScope.date.getMinutes()).toBe(0); + expect($rootScope.date.getSeconds()).toBe(0); + }); - changeInputValueTo(inputEl, '11.08.2013'); - expect($rootScope.date.getFullYear()).toEqual(2013); - expect($rootScope.date.getMonth()).toEqual(7); - expect($rootScope.date.getDate()).toEqual(11); - }); - }); + it('should have a button to clear value', function() { + buttons.eq(1).click(); + expect($rootScope.date).toBe(null); + }); - describe('`close-on-date-selection` attribute', function () { - var wrapElement; - beforeEach(inject(function() { - $rootScope.close = false; - wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); + it('should have a button to close calendar', function() { + buttons.eq(2).click(); + assignElements(wrapElement); + expect(dropdownEl.length).toBe(0); + }); + }); - it('does not close the dropdown when a day is clicked', function() { - clickOption(17); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(1); - }); - }); + describe('customization', function() { + it('should change text from attributes', function() { + $rootScope.clearText = 'Null it!'; + $rootScope.close = 'Close'; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + assignButtonBar(); - describe('button bar', function() { - var buttons, buttonBarElement; + expect(buttons.eq(0).text()).toBe('Now'); + expect(buttons.eq(1).text()).toBe('Null it!'); + expect(buttons.eq(2).text()).toBe('CloseME'); + }); - function assignButtonBar() { - buttonBarElement = dropdownEl.find('li').eq(-1); - buttons = buttonBarElement.find('button'); - } + it('should remove bar', function() { + $rootScope.showBar = false; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + expect(dropdownEl.find('li').length).toBe(1); + }); - describe('', function () { - var wrapElement; + it('should hide weeks column on popup', function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); - beforeEach(inject(function() { - $rootScope.isopen = true; - wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - assignButtonBar(); - })); + expect(getLabelsRow().find('th').length).toEqual(7); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').length).toEqual(7); + } + }); - it('should exist', function() { - expect(dropdownEl.length).toBe(1); - expect(dropdownEl.find('li').length).toBe(2); + it('should show weeks column on popup', function() { + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + + expect(getLabelsRow().find('th').eq(0)).not.toBeHidden(); + var tr = element.find('tbody').find('tr'); + for (var i = 0; i < 5; i++) { + expect(tr.eq(i).find('td').eq(0)).not.toBeHidden(); + } + }); }); - it('should have three buttons', function() { - expect(buttons.length).toBe(3); + describe('`ng-change`', function() { + beforeEach(inject(function() { + $rootScope.changeHandler = jasmine.createSpy('changeHandler'); + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + assignButtonBar(); + })); - expect(buttons.eq(0).text()).toBe('Today'); - expect(buttons.eq(1).text()).toBe('Clear'); - expect(buttons.eq(2).text()).toBe('Done'); - }); + it('should be called when `today` is clicked', function() { + buttons.eq(0).click(); + expect($rootScope.changeHandler).toHaveBeenCalled(); + }); - it('should have a button to set today date without altering time part', function() { - var today = new Date(); - buttons.eq(0).click(); - expect($rootScope.date.getFullYear()).toBe(today.getFullYear()); - expect($rootScope.date.getMonth()).toBe(today.getMonth()); - expect($rootScope.date.getDate()).toBe(today.getDate()); + it('should be called when `clear` is clicked', function() { + buttons.eq(1).click(); + expect($rootScope.changeHandler).toHaveBeenCalled(); + }); - expect($rootScope.date.getHours()).toBe(15); - expect($rootScope.date.getMinutes()).toBe(30); - expect($rootScope.date.getSeconds()).toBe(0); + it('should not be called when `close` is clicked', function() { + buttons.eq(2).click(); + expect($rootScope.changeHandler).not.toHaveBeenCalled(); + }); }); + }); - it('should have a button to set today date if blank', function() { - $rootScope.date = null; - $rootScope.$digest(); + describe('use with `ng-required` directive', function() { + describe('`ng-required is true`', function() { + beforeEach(inject(function() { + $rootScope.date = ''; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + })); - var today = new Date(); - buttons.eq(0).click(); - expect($rootScope.date.getFullYear()).toBe(today.getFullYear()); - expect($rootScope.date.getMonth()).toBe(today.getMonth()); - expect($rootScope.date.getDate()).toBe(today.getDate()); + it('should be invalid initially and when no date', function() { + expect(inputEl.hasClass('ng-invalid')).toBeTruthy(); + }); - expect($rootScope.date.getHours()).toBe(0); - expect($rootScope.date.getMinutes()).toBe(0); - expect($rootScope.date.getSeconds()).toBe(0); - }); + it('should be valid if model has been specified', function() { + $rootScope.date = new Date(); + $rootScope.$digest(); + expect(inputEl.hasClass('ng-valid')).toBeTruthy(); + }); - it('should have a button to clear value', function() { - buttons.eq(1).click(); - expect($rootScope.date).toBe(null); + it('should be valid if model value is a valid timestamp', function() { + $rootScope.date = Date.now(); + $rootScope.$digest(); + expect(inputEl.hasClass('ng-valid')).toBeTruthy(); + }); }); + describe('`ng-required is false`', function() { + beforeEach(inject(function() { + $rootScope.date = ''; + var wrapElement = $compile('
')($rootScope); + $rootScope.$digest(); + assignElements(wrapElement); + })); - it('should have a button to close calendar', function() { - buttons.eq(2).click(); - assignElements(wrapElement); - expect(dropdownEl.length).toBe(0); + it('should be valid initially and when no date', function() { + expect(inputEl.hasClass('ng-valid')).toBeTruthy(); + }); }); }); - describe('customization', function() { - it('should change text from attributes', function() { - $rootScope.clearText = 'Null it!'; - $rootScope.close = 'Close'; - var wrapElement = $compile('
')($rootScope); + describe('use with `ng-change` directive', function() { + beforeEach(inject(function() { + $rootScope.changeHandler = jasmine.createSpy('changeHandler'); + $rootScope.date = new Date('09/16/2010'); + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); - assignButtonBar(); + })); - expect(buttons.eq(0).text()).toBe('Now'); - expect(buttons.eq(1).text()).toBe('Null it!'); - expect(buttons.eq(2).text()).toBe('CloseME'); + it('should not be called initially', function() { + expect($rootScope.changeHandler).not.toHaveBeenCalled(); + }); + + it('should be called when a day is clicked', function() { + clickOption(17); + expect($rootScope.changeHandler).toHaveBeenCalled(); }); - it('should remove bar', function() { - $rootScope.showBar = false; - var wrapElement = $compile('
')($rootScope); + it('should not be called when model changes programatically', function() { + $rootScope.date = new Date(); $rootScope.$digest(); - assignElements(wrapElement); - expect(dropdownEl.find('li').length).toBe(1); + expect($rootScope.changeHandler).not.toHaveBeenCalled(); + }); + }); + + describe('with an append-to-body attribute', function() { + beforeEach(function() { + $rootScope.date = new Date(); }); - it('should hide weeks column on popup', function() { - var wrapElement = $compile('
')($rootScope); + afterEach(function () { + $document.find('body').find('.dropdown-menu').remove(); + }); + + it('should append to the body', function() { + var $body = $document.find('body'), + bodyLength = $body.children().length, + elm = angular.element( + '
' + ); + $compile(elm)($rootScope); $rootScope.$digest(); - assignElements(wrapElement); - expect(getLabelsRow().find('th').length).toEqual(7); - var tr = element.find('tbody').find('tr'); - for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').length).toEqual(7); - } + expect($body.children().length).toEqual(bodyLength + 1); + expect(elm.children().length).toEqual(1); }); + it('should be removed on scope destroy', function() { + var $body = $document.find('body'), + bodyLength = $body.children().length, + isolatedScope = $rootScope.$new(), + elm = angular.element( + '' + ); + $compile(elm)(isolatedScope); + isolatedScope.$digest(); + expect($body.children().length).toEqual(bodyLength + 1); + isolatedScope.$destroy(); + expect($body.children().length).toEqual(bodyLength); + }); + }); - it('should show weeks column on popup', function() { - var wrapElement = $compile('
')($rootScope); + describe('with setting datepickerConfig.showWeeks to false', function() { + var originalConfig = {}; + beforeEach(inject(function(datepickerConfig) { + angular.extend(originalConfig, datepickerConfig); + datepickerConfig.showWeeks = false; + + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); + })); + afterEach(inject(function(datepickerConfig) { + // return it to the original state + angular.extend(datepickerConfig, originalConfig); + })); - expect(getLabelsRow().find('th').eq(0)).not.toBeHidden(); + it('changes initial visibility for weeks', function() { + expect(getLabelsRow().find('th').length).toEqual(7); var tr = element.find('tbody').find('tr'); for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').eq(0)).not.toBeHidden(); + expect(tr.eq(i).find('td').length).toEqual(7); } }); }); - describe('`ng-change`', function() { + describe('`datepicker-mode`', function () { beforeEach(inject(function() { - $rootScope.changeHandler = jasmine.createSpy('changeHandler'); - var wrapElement = $compile('
')($rootScope); + $rootScope.date = new Date('August 11, 2013'); + $rootScope.mode = 'month'; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); - assignButtonBar(); })); - it('should be called when `today` is clicked', function() { - buttons.eq(0).click(); - expect($rootScope.changeHandler).toHaveBeenCalled(); - }); - - it('should be called when `clear` is clicked', function() { - buttons.eq(1).click(); - expect($rootScope.changeHandler).toHaveBeenCalled(); + it('shows the correct title', function() { + expect(getTitle()).toBe('2013'); }); - it('should not be called when `close` is clicked', function() { - buttons.eq(2).click(); - expect($rootScope.changeHandler).not.toHaveBeenCalled(); + it('updates binding', function() { + clickTitleButton(); + expect($rootScope.mode).toBe('year'); }); }); - }); - describe('use with `ng-required` directive', function() { - describe('`ng-required is true`', function() { - beforeEach(inject(function() { - $rootScope.date = ''; - var wrapElement = $compile('
')($rootScope); + describe('attribute `initDate`', function () { + var weekHeader, weekElement; + beforeEach(function() { + $rootScope.date = null; + $rootScope.initDate = new Date('November 9, 1980'); + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); - })); - - it('should be invalid initially and when no date', function() { - expect(inputEl.hasClass('ng-invalid')).toBeTruthy(); - }); - - it('should be valid if model has been specified', function() { - $rootScope.date = new Date(); - $rootScope.$digest(); - expect(inputEl.hasClass('ng-valid')).toBeTruthy(); }); - it('should be valid if model value is a valid timestamp', function() { - $rootScope.date = Date.now(); - $rootScope.$digest(); - expect(inputEl.hasClass('ng-valid')).toBeTruthy(); + it('should not alter the model', function() { + expect($rootScope.date).toBe(null); }); - }); - describe('`ng-required is false`', function() { - beforeEach(inject(function() { - $rootScope.date = ''; - var wrapElement = $compile('
')($rootScope); - $rootScope.$digest(); - assignElements(wrapElement); - })); - it('should be valid initially and when no date', function() { - expect(inputEl.hasClass('ng-valid')).toBeTruthy(); + it('shows the correct title', function() { + expect(getTitle()).toBe('November 1980'); }); }); }); - describe('use with `ng-change` directive', function() { + describe('with empty initial state', function () { beforeEach(inject(function() { - $rootScope.changeHandler = jasmine.createSpy('changeHandler'); - $rootScope.date = new Date('09/16/2010'); - var wrapElement = $compile('
')($rootScope); + $rootScope.date = null; + element = $compile('')($rootScope); $rootScope.$digest(); - assignElements(wrapElement); })); - it('should not be called initially', function() { - expect($rootScope.changeHandler).not.toHaveBeenCalled(); + it('is has a `
` element', function() { + expect(element.find('table').length).toBe(1); }); - it('should be called when a day is clicked', function() { - clickOption(17); - expect($rootScope.changeHandler).toHaveBeenCalled(); + it('is shows rows with days', function() { + expect(element.find('tbody').find('tr').length).toBeGreaterThan(3); }); - it('should not be called when model changes programatically', function() { - $rootScope.date = new Date(); + it('sets default 00:00:00 time for selected date', function() { + $rootScope.date = new Date('August 1, 2013'); $rootScope.$digest(); - expect($rootScope.changeHandler).not.toHaveBeenCalled(); - }); - }); - - describe('with an append-to-body attribute', function() { - beforeEach(function() { - $rootScope.date = new Date(); - }); - - afterEach(function () { - $document.find('body').find('.dropdown-menu').remove(); - }); - - it('should append to the body', function() { - var $body = $document.find('body'), - bodyLength = $body.children().length, - elm = angular.element( - '
' - ); - $compile(elm)($rootScope); + $rootScope.date = null; $rootScope.$digest(); - expect($body.children().length).toEqual(bodyLength + 1); - expect(elm.children().length).toEqual(1); - }); - it('should be removed on scope destroy', function() { - var $body = $document.find('body'), - bodyLength = $body.children().length, - isolatedScope = $rootScope.$new(), - elm = angular.element( - '' - ); - $compile(elm)(isolatedScope); - isolatedScope.$digest(); - expect($body.children().length).toEqual(bodyLength + 1); - isolatedScope.$destroy(); - expect($body.children().length).toEqual(bodyLength); + clickOption(14); + expect($rootScope.date).toEqual(new Date('August 11, 2013 00:00:00')); }); }); - describe('with setting datepickerConfig.showWeeks to false', function() { - var originalConfig = {}; - beforeEach(inject(function(datepickerConfig) { - angular.extend(originalConfig, datepickerConfig); - datepickerConfig.showWeeks = false; - - var wrapElement = $compile('
')($rootScope); + describe('`init-date`', function () { + beforeEach(inject(function() { + $rootScope.date = null; + $rootScope.initDate = new Date('November 9, 1980'); + element = $compile('')($rootScope); $rootScope.$digest(); - assignElements(wrapElement); - })); - afterEach(inject(function(datepickerConfig) { - // return it to the original state - angular.extend(datepickerConfig, originalConfig); })); - it('changes initial visibility for weeks', function() { - expect(getLabelsRow().find('th').length).toEqual(7); - var tr = element.find('tbody').find('tr'); - for (var i = 0; i < 5; i++) { - expect(tr.eq(i).find('td').length).toEqual(7); - } + it('does not alter the model', function() { + expect($rootScope.date).toBe(null); + }); + + it('shows the correct title', function() { + expect(getTitle()).toBe('November 1980'); }); }); @@ -2003,9 +2153,8 @@ describe('datepicker directive', function () { beforeEach(inject(function() { $rootScope.date = new Date('August 11, 2013'); $rootScope.mode = 'month'; - var wrapElement = $compile('
')($rootScope); + element = $compile('')($rootScope); $rootScope.$digest(); - assignElements(wrapElement); })); it('shows the correct title', function() { @@ -2018,219 +2167,139 @@ describe('datepicker directive', function () { }); }); - describe('attribute `initDate`', function () { - var weekHeader, weekElement; - beforeEach(function() { - $rootScope.date = null; - $rootScope.initDate = new Date('November 9, 1980'); - var wrapElement = $compile('
')($rootScope); + describe('`min-mode`', function () { + beforeEach(inject(function() { + $rootScope.date = new Date('August 11, 2013'); + $rootScope.mode = 'month'; + element = $compile('')($rootScope); $rootScope.$digest(); - assignElements(wrapElement); - }); - - it('should not alter the model', function() { - expect($rootScope.date).toBe(null); - }); + })); - it('shows the correct title', function() { - expect(getTitle()).toBe('November 1980'); + it('does not move below it', function() { + expect(getTitle()).toBe('2013'); + clickOption( 5 ); + expect(getTitle()).toBe('2013'); + clickTitleButton(); + expect(getTitle()).toBe('2001 - 2020'); }); }); - }); - - describe('with empty initial state', function () { - beforeEach(inject(function() { - $rootScope.date = null; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - - it('is has a `
` element', function() { - expect(element.find('table').length).toBe(1); - }); - - it('is shows rows with days', function() { - expect(element.find('tbody').find('tr').length).toBeGreaterThan(3); - }); - - it('sets default 00:00:00 time for selected date', function() { - $rootScope.date = new Date('August 1, 2013'); - $rootScope.$digest(); - $rootScope.date = null; - $rootScope.$digest(); - - clickOption(14); - expect($rootScope.date).toEqual(new Date('August 11, 2013 00:00:00')); - }); - }); - - describe('`init-date`', function () { - beforeEach(inject(function() { - $rootScope.date = null; - $rootScope.initDate = new Date('November 9, 1980'); - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - - it('does not alter the model', function() { - expect($rootScope.date).toBe(null); - }); - - it('shows the correct title', function() { - expect(getTitle()).toBe('November 1980'); - }); - }); - - describe('`datepicker-mode`', function () { - beforeEach(inject(function() { - $rootScope.date = new Date('August 11, 2013'); - $rootScope.mode = 'month'; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - - it('shows the correct title', function() { - expect(getTitle()).toBe('2013'); - }); - - it('updates binding', function() { - clickTitleButton(); - expect($rootScope.mode).toBe('year'); - }); - }); - - describe('`min-mode`', function () { - beforeEach(inject(function() { - $rootScope.date = new Date('August 11, 2013'); - $rootScope.mode = 'month'; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - - it('does not move below it', function() { - expect(getTitle()).toBe('2013'); - clickOption( 5 ); - expect(getTitle()).toBe('2013'); - clickTitleButton(); - expect(getTitle()).toBe('2001 - 2020'); - }); - }); - describe('`max-mode`', function () { - beforeEach(inject(function() { - $rootScope.date = new Date('August 11, 2013'); - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + describe('`max-mode`', function () { + beforeEach(inject(function() { + $rootScope.date = new Date('August 11, 2013'); + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('does not move above it', function() { - expect(getTitle()).toBe('August 2013'); - clickTitleButton(); - expect(getTitle()).toBe('2013'); - clickTitleButton(); - expect(getTitle()).toBe('2013'); - }); + it('does not move above it', function() { + expect(getTitle()).toBe('August 2013'); + clickTitleButton(); + expect(getTitle()).toBe('2013'); + clickTitleButton(); + expect(getTitle()).toBe('2013'); + }); - it('disables the title button at it', function() { - expect(getTitleButton().prop('disabled')).toBe(false); - clickTitleButton(); - expect(getTitleButton().prop('disabled')).toBe(true); - clickTitleButton(); - expect(getTitleButton().prop('disabled')).toBe(true); + it('disables the title button at it', function() { + expect(getTitleButton().prop('disabled')).toBe(false); + clickTitleButton(); + expect(getTitleButton().prop('disabled')).toBe(true); + clickTitleButton(); + expect(getTitleButton().prop('disabled')).toBe(true); + }); }); - }); - describe('with an ngModelController having formatters and parsers', function() { - beforeEach(inject(function() { - // Custom date object. - $rootScope.date = { type: 'date', date: 'April 1, 2015 00:00:00' }; + describe('with an ngModelController having formatters and parsers', function() { + beforeEach(inject(function() { + // Custom date object. + $rootScope.date = { type: 'date', date: 'April 1, 2015 00:00:00' }; - // Use dateModel directive to add formatters and parsers to the - // ngModelController that translate the custom date object. - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + // Use dateModel directive to add formatters and parsers to the + // ngModelController that translate the custom date object. + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('updates the view', function() { - $rootScope.date = { type: 'date', date: 'April 15, 2015 00:00:00' }; - $rootScope.$digest(); + it('updates the view', function() { + $rootScope.date = { type: 'date', date: 'April 15, 2015 00:00:00' }; + $rootScope.$digest(); - expectSelectedElement(17); - }); + expectSelectedElement(17); + }); - it('updates the model', function() { - clickOption(17); + it('updates the model', function() { + clickOption(17); - expect($rootScope.date.type).toEqual('date'); - expect(new Date($rootScope.date.date)).toEqual(new Date('April 15, 2015 00:00:00')); + expect($rootScope.date.type).toEqual('date'); + expect(new Date($rootScope.date.date)).toEqual(new Date('April 15, 2015 00:00:00')); + }); }); - }); - - describe('thurdays determine week count', function() { - - beforeEach(inject(function() { - $rootScope.date = new Date('June 07, 2014'); - })); - it('with the default starting day (sunday)', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + describe('thurdays determine week count', function() { - expect(getWeeks()).toEqual(['23', '24', '25', '26', '27', '28']); - }); + beforeEach(inject(function() { + $rootScope.date = new Date('June 07, 2014'); + })); - describe('when starting date', function() { - it('is monday', function() { - element = $compile('')($rootScope); + it('with the default starting day (sunday)', function() { + element = $compile('')($rootScope); $rootScope.$digest(); - expect(getWeeks()).toEqual(['22', '23', '24', '25', '26', '27']); + expect(getWeeks()).toEqual(['23', '24', '25', '26', '27', '28']); }); - it('is thursday', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + describe('when starting date', function() { + it('is monday', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - expect(getWeeks()).toEqual(['22', '23', '24', '25', '26', '27']); - }); + expect(getWeeks()).toEqual(['22', '23', '24', '25', '26', '27']); + }); - it('is saturday', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + it('is thursday', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - expect(getWeeks()).toEqual(['23', '24', '25', '26', '27', '28']); - }); - }); + expect(getWeeks()).toEqual(['22', '23', '24', '25', '26', '27']); + }); - describe('first week in january', function() { - it('in current year', function() { - $rootScope.date = new Date('January 07, 2014'); - element = $compile('')($rootScope); - $rootScope.$digest(); + it('is saturday', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - expect(getWeeks()).toEqual(['1', '2', '3', '4', '5', '6']); + expect(getWeeks()).toEqual(['23', '24', '25', '26', '27', '28']); + }); }); - it('in last year', function() { - $rootScope.date = new Date('January 07, 2010'); - element = $compile('')($rootScope); - $rootScope.$digest(); + describe('first week in january', function() { + it('in current year', function() { + $rootScope.date = new Date('January 07, 2014'); + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect(getWeeks()).toEqual(['1', '2', '3', '4', '5', '6']); + }); - expect(getWeeks()).toEqual(['53', '1', '2', '3', '4', '5']); + it('in last year', function() { + $rootScope.date = new Date('January 07, 2010'); + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect(getWeeks()).toEqual(['53', '1', '2', '3', '4', '5']); + }); }); - }); - describe('last week(s) in december', function() { - beforeEach(inject(function() { - $rootScope.date = new Date('December 07, 2014'); - })); + describe('last week(s) in december', function() { + beforeEach(inject(function() { + $rootScope.date = new Date('December 07, 2014'); + })); - it('in next year', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + it('in next year', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - expect(getWeeks()).toEqual(['49', '50', '51', '52', '1', '2']); - }); + expect(getWeeks()).toEqual(['49', '50', '51', '52', '1', '2']); + }); + }); }); }); });