@@ -8,7 +8,7 @@ describe('timepicker directive', function () {
88 $rootScope = _$rootScope_ ;
99 $rootScope . time = newTime ( 14 , 40 ) ;
1010
11- element = $compile ( '<timepicker ng-model="time"></timepicker>' ) ( $rootScope ) ;
11+ element = $compile ( '<timepicker ng-model="$parent. time"></timepicker>' ) ( $rootScope ) ;
1212 $rootScope . $digest ( ) ;
1313 } ) ) ;
1414
@@ -82,6 +82,15 @@ describe('timepicker directive', function () {
8282 expect ( getModelState ( ) ) . toEqual ( [ 14 , 40 ] ) ;
8383 } ) ;
8484
85+ it ( 'has `selected` current time when model is initially cleared' , function ( ) {
86+ $rootScope . time = null ;
87+ element = $compile ( '<timepicker ng-model="$parent.time"></timepicker>' ) ( $rootScope ) ;
88+ $rootScope . $digest ( ) ;
89+
90+ expect ( $rootScope . time ) . toBe ( null ) ;
91+ expect ( getTimeState ( ) ) . not . toEqual ( [ '' , '' , '' ] ) ;
92+ } ) ;
93+
8594 it ( 'changes inputs when model changes value' , function ( ) {
8695 $rootScope . time = newTime ( 11 , 50 ) ;
8796 $rootScope . $digest ( ) ;
@@ -235,7 +244,7 @@ describe('timepicker directive', function () {
235244 } ) ;
236245
237246 it ( 'changes only the time part when minutes change' , function ( ) {
238- element = $compile ( '<timepicker ng-model="time" minute-step="15"></timepicker>' ) ( $rootScope ) ;
247+ element = $compile ( '<timepicker ng-model="$parent. time" minute-step="15"></timepicker>' ) ( $rootScope ) ;
239248 $rootScope . time = newTime ( 0 , 0 ) ;
240249 $rootScope . $digest ( ) ;
241250
@@ -367,7 +376,7 @@ describe('timepicker directive', function () {
367376 $rootScope . hstep = 2 ;
368377 $rootScope . mstep = 30 ;
369378 $rootScope . time = newTime ( 14 , 0 ) ;
370- element = $compile ( '<timepicker ng-model="time" hour-step="hstep" minute-step="mstep"></timepicker>' ) ( $rootScope ) ;
379+ element = $compile ( '<timepicker ng-model="$parent. time" hour-step="hstep" minute-step="mstep"></timepicker>' ) ( $rootScope ) ;
371380 $rootScope . $digest ( ) ;
372381 } ) ;
373382
@@ -530,7 +539,7 @@ describe('timepicker directive', function () {
530539 beforeEach ( function ( ) {
531540 $rootScope . meridian = false ;
532541 $rootScope . time = newTime ( 14 , 10 ) ;
533- element = $compile ( '<timepicker ng-model="time" show-meridian="meridian"></timepicker>' ) ( $rootScope ) ;
542+ element = $compile ( '<timepicker ng-model="$parent. time" show-meridian="meridian"></timepicker>' ) ( $rootScope ) ;
534543 $rootScope . $digest ( ) ;
535544 } ) ;
536545
@@ -559,6 +568,14 @@ describe('timepicker directive', function () {
559568 expect ( getModelState ( ) ) . toEqual ( [ 14 , 10 ] ) ;
560569 expect ( getMeridianTd ( ) . css ( 'display' ) ) . toBe ( 'none' ) ;
561570 } ) ;
571+
572+ it ( 'handles correctly initially empty model on parent element' , function ( ) {
573+ $rootScope . time = null ;
574+ element = $compile ( '<span ng-model="time"><timepicker show-meridian="meridian"></timepicker></span>' ) ( $rootScope ) ;
575+ $rootScope . $digest ( ) ;
576+
577+ expect ( $rootScope . time ) . toBe ( null ) ;
578+ } ) ;
562579 } ) ;
563580
564581 describe ( 'setting timepickerConfig steps' , function ( ) {
@@ -568,7 +585,7 @@ describe('timepicker directive', function () {
568585 timepickerConfig . hourStep = 2 ;
569586 timepickerConfig . minuteStep = 10 ;
570587 timepickerConfig . showMeridian = false ;
571- element = $compile ( '<timepicker ng-model="time"></timepicker>' ) ( $rootScope ) ;
588+ element = $compile ( '<timepicker ng-model="$parent. time"></timepicker>' ) ( $rootScope ) ;
572589 $rootScope . $digest ( ) ;
573590 } ) ) ;
574591 afterEach ( inject ( function ( timepickerConfig ) {
@@ -614,7 +631,7 @@ describe('timepicker directive', function () {
614631 angular . extend ( originalConfig , timepickerConfig ) ;
615632 timepickerConfig . meridians = [ 'π.μ.' , 'μ.μ.' ] ;
616633 timepickerConfig . showMeridian = true ;
617- element = $compile ( '<timepicker ng-model="time"></timepicker>' ) ( $rootScope ) ;
634+ element = $compile ( '<timepicker ng-model="$parent. time"></timepicker>' ) ( $rootScope ) ;
618635 $rootScope . $digest ( ) ;
619636 } ) ) ;
620637 afterEach ( inject ( function ( timepickerConfig ) {
@@ -637,10 +654,9 @@ describe('timepicker directive', function () {
637654 } ) ;
638655
639656 describe ( 'user input validation' , function ( ) {
640-
641657 var changeInputValueTo ;
642658
643- beforeEach ( inject ( function ( _$compile_ , _$rootScope_ , $sniffer ) {
659+ beforeEach ( inject ( function ( $sniffer ) {
644660 changeInputValueTo = function ( inputEl , value ) {
645661 inputEl . val ( value ) ;
646662 inputEl . trigger ( $sniffer . hasEvent ( 'input' ) ? 'input' : 'change' ) ;
@@ -661,7 +677,7 @@ describe('timepicker directive', function () {
661677 expect ( getModelState ( ) ) . toEqual ( [ 14 , 40 ] ) ;
662678 } ) ;
663679
664- it ( 'updates hours & pads on input blur' , function ( ) {
680+ it ( 'updates hours & pads on input change & pads on blur' , function ( ) {
665681 var el = getHoursInputEl ( ) ;
666682
667683 changeInputValueTo ( el , 5 ) ;
@@ -673,7 +689,7 @@ describe('timepicker directive', function () {
673689 expect ( getModelState ( ) ) . toEqual ( [ 17 , 40 ] ) ;
674690 } ) ;
675691
676- it ( 'updates minutes & pads on input blur' , function ( ) {
692+ it ( 'updates minutes & pads on input change & pads on blur' , function ( ) {
677693 var el = getMinutesInputEl ( ) ;
678694
679695 changeInputValueTo ( el , 9 ) ;
@@ -691,13 +707,15 @@ describe('timepicker directive', function () {
691707 changeInputValueTo ( el , 'pizza' ) ;
692708 expect ( $rootScope . time ) . toBe ( null ) ;
693709 expect ( el . parent ( ) . hasClass ( 'error' ) ) . toBe ( true ) ;
710+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
694711
695712 changeInputValueTo ( el , 8 ) ;
696713 el . blur ( ) ;
697714 $rootScope . $digest ( ) ;
698715 expect ( getTimeState ( ) ) . toEqual ( [ '08' , '40' , 'PM' ] ) ;
699716 expect ( getModelState ( ) ) . toEqual ( [ 20 , 40 ] ) ;
700717 expect ( el . parent ( ) . hasClass ( 'error' ) ) . toBe ( false ) ;
718+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
701719 } ) ;
702720
703721 it ( 'clears model when input minutes is invalid & alerts the UI' , function ( ) {
@@ -706,28 +724,130 @@ describe('timepicker directive', function () {
706724 changeInputValueTo ( el , 'pizza' ) ;
707725 expect ( $rootScope . time ) . toBe ( null ) ;
708726 expect ( el . parent ( ) . hasClass ( 'error' ) ) . toBe ( true ) ;
727+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
709728
710729 changeInputValueTo ( el , 22 ) ;
711730 expect ( getTimeState ( ) ) . toEqual ( [ '02' , '22' , 'PM' ] ) ;
712731 expect ( getModelState ( ) ) . toEqual ( [ 14 , 22 ] ) ;
713732 expect ( el . parent ( ) . hasClass ( 'error' ) ) . toBe ( false ) ;
733+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
714734 } ) ;
715735
716736 it ( 'handles 12/24H mode change' , function ( ) {
717737 $rootScope . meridian = true ;
718- element = $compile ( '<timepicker ng-model="time" show-meridian="meridian"></timepicker>' ) ( $rootScope ) ;
738+ element = $compile ( '<timepicker ng-model="$parent. time" show-meridian="meridian"></timepicker>' ) ( $rootScope ) ;
719739 $rootScope . $digest ( ) ;
720740
721741 var el = getHoursInputEl ( ) ;
722742
723743 changeInputValueTo ( el , '16' ) ;
724744 expect ( $rootScope . time ) . toBe ( null ) ;
725745 expect ( el . parent ( ) . hasClass ( 'error' ) ) . toBe ( true ) ;
746+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
726747
727748 $rootScope . meridian = false ;
728749 $rootScope . $digest ( ) ;
729750 expect ( getTimeState ( true ) ) . toEqual ( [ '16' , '40' ] ) ;
730751 expect ( getModelState ( ) ) . toEqual ( [ 16 , 40 ] ) ;
752+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
753+ } ) ;
754+ } ) ;
755+
756+ describe ( 'when model is not a Date' , function ( ) {
757+ beforeEach ( inject ( function ( ) {
758+ eelement = $compile ( '<timepicker ng-model="$parent.time"></timepicker>' ) ( $rootScope ) ;
759+ } ) ) ;
760+
761+ it ( 'should not be invalid when the model is null' , function ( ) {
762+ $rootScope . time = null ;
763+ $rootScope . $digest ( ) ;
764+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
765+ } ) ;
766+
767+ it ( 'should not be invalid when the model is undefined' , function ( ) {
768+ $rootScope . time = undefined ;
769+ $rootScope . $digest ( ) ;
770+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
771+ } ) ;
772+
773+ it ( 'should not be invalid when the model is a valid string date representation' , function ( ) {
774+ $rootScope . time = 'September 30, 2010 15:30:00' ;
775+ $rootScope . $digest ( ) ;
776+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
777+ expect ( getTimeState ( ) ) . toEqual ( [ '03' , '30' , 'PM' ] ) ;
778+ } ) ;
779+
780+ it ( 'should be invalid when the model is not a valid string date representation' , function ( ) {
781+ $rootScope . time = 'pizza' ;
782+ $rootScope . $digest ( ) ;
783+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
784+ } ) ;
785+
786+ it ( 'should return valid when the model becomes valid' , function ( ) {
787+ $rootScope . time = 'pizza' ;
788+ $rootScope . $digest ( ) ;
789+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
790+
791+ $rootScope . time = new Date ( ) ;
792+ $rootScope . $digest ( ) ;
793+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
794+ } ) ;
795+
796+ it ( 'should return valid when the model is cleared' , function ( ) {
797+ $rootScope . time = 'pizza' ;
798+ $rootScope . $digest ( ) ;
799+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( true ) ;
800+
801+ $rootScope . time = null ;
802+ $rootScope . $digest ( ) ;
803+ expect ( element . hasClass ( 'ng-invalid-time' ) ) . toBe ( false ) ;
804+ } ) ;
805+ } ) ;
806+
807+ describe ( 'use with `ng-required` directive' , function ( ) {
808+ beforeEach ( inject ( function ( ) {
809+ $rootScope . time = null ;
810+ element = $compile ( '<timepicker ng-model="$parent.time" ng-required="true"></timepicker>' ) ( $rootScope ) ;
811+ $rootScope . $digest ( ) ;
812+ } ) ) ;
813+
814+ it ( 'should be invalid initially' , function ( ) {
815+ expect ( element . hasClass ( 'ng-invalid' ) ) . toBe ( true ) ;
816+ } ) ;
817+
818+ it ( 'should be valid if model has been specified' , function ( ) {
819+ $rootScope . time = new Date ( ) ;
820+ $rootScope . $digest ( ) ;
821+ expect ( element . hasClass ( 'ng-invalid' ) ) . toBe ( false ) ;
822+ } ) ;
823+ } ) ;
824+
825+ describe ( 'use with `ng-change` directive' , function ( ) {
826+ beforeEach ( inject ( function ( ) {
827+ $rootScope . changeHandler = jasmine . createSpy ( 'changeHandler' ) ;
828+ $rootScope . time = new Date ( ) ;
829+ element = $compile ( '<timepicker ng-model="$parent.time" ng-change="$parent.changeHandler()"></timepicker>' ) ( $rootScope ) ;
830+ $rootScope . $digest ( ) ;
831+ } ) ) ;
832+
833+ it ( 'should not be called initially' , function ( ) {
834+ expect ( $rootScope . changeHandler ) . not . toHaveBeenCalled ( ) ;
835+ } ) ;
836+
837+ it ( 'should be called when hours / minutes buttons clicked' , function ( ) {
838+ var btn1 = getHoursButton ( true ) ;
839+ var btn2 = getMinutesButton ( false ) ;
840+
841+ doClick ( btn1 , 2 ) ;
842+ doClick ( btn2 , 3 ) ;
843+ $rootScope . $digest ( ) ;
844+ expect ( $rootScope . changeHandler . callCount ) . toBe ( 5 ) ;
845+ } ) ;
846+
847+ it ( 'should not be called when model changes programatically' , function ( ) {
848+ $rootScope . time = new Date ( ) ;
849+ $rootScope . $digest ( ) ;
850+ expect ( $rootScope . changeHandler ) . not . toHaveBeenCalled ( ) ;
731851 } ) ;
732852 } ) ;
733853
0 commit comments