@@ -75,47 +75,87 @@ describe('IsoDate.parse – valid inputs', () => {
7575 } ) ;
7676} ) ;
7777
78- describe ( 'IsoDate.parse – invalid inputs' , ( ) => {
79- const invalid = [
80- '202501' , // year+month without hyphen
81- '20250101' , // compact full date (properly rejected in this class)
82- '250101' , // two‑digit year
83- '2025-13-01' , // invalid month
84- '2025-02-30' , // invalid day (Feb 30)
85- '2025-04-31' , // invalid day (April 31)
86- '-2025-04-31' , // invalid year
87- '--01-01' , // leading hyphens
88- '-2025-01' , // leading hyphen before year
89- '2025--01' , // double hyphen between year and month
90- '2025-01--01' , // double hyphen before day
91- '2025-02-29' , // illegal leap year
92- '2025-01-01T014:00:00:00Z' , // datetime does not match in this class
93- ] ;
9478
95- invalid . forEach ( ( value ) => {
96- test ( `throws for "${ value } "` , ( ) => {
97- expect ( ( ) => IsoDate . parse ( value ) ) . toThrow ( Error ) ;
98- } ) ;
99- } ) ;
79+ describe ( 'IsoDate.parse/toString/isMonth/isDate/isYear' , ( ) => {
80+ const tests : Array < { value : string ; isYear ?: boolean ; isMonth ?: boolean ; isDate ?: boolean ; isDatetime ?: boolean ; threw ?: RegExp ; } > = [
81+ // valid ISO Date specs
82+ { value : `2025` , isYear : true } ,
83+ { value : ` 2025 ` , isYear : true } ,
84+ { value : `2025-10` , isMonth : true } ,
85+ { value : `2024-02-29` , isDate : true } ,
86+ // invalid ISO Date specs
87+ { value : `25` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // year must be after 1000 and before 2500
88+ { value : `1899` , threw : / Y e a r o u t o f r a n g e / } , // year must be after 1900 and before 2100
89+ { value : `2500` , threw : / Y e a r o u t o f r a n g e / } , // year must be after 1900 and before 2100
90+ { value : `1/1/25` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // bad format
91+ { value : `abc` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // bad format
92+ { value : `202501` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // year+month without hyphen
93+ { value : `20250101` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // compact full date (properly rejected in this class)
94+ { value : `250101` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // two‑digit year
95+ { value : `-2025-04-31` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // leading hyphen
96+ { value : `-2025-04` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } , // leading hyphen
97+ { value : `01-01` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } ,
98+ { value : `2025--01` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } ,
99+ { value : `2025-01-01T014:00:00:00Z` , threw : / I n v a l i d c a l e n d a r d a t e f o r m a t / } ,
100+ { value : `2025-13-01` , threw : / M o n t h o u t o f r a n g e / } ,
101+ { value : `2025-02-29` , threw : / D a y o u t o f r a n g e / } , // not a leap year
102+ { value : `2025-02-30` , threw : / D a y o u t o f r a n g e / } ,
103+ { value : `2025-04-31` , threw : / D a y o u t o f r a n g e / } ,
104+ ] ;
100105
101- invalid . forEach ( ( value ) => {
102- test ( `"${ value } " is not an IsoDate` , ( ) => {
103- expect ( isValidIsoDate ( value ) ) . toBeFalsy ( ) ;
106+ tests . forEach ( ( { value, isYear = false , isMonth = false , isDate = false , threw = '' } ) => {
107+ test ( `properly determines if ${ value } is a ${ isYear ? 'year' : '' } ${ isMonth ? 'month' : '' } ${ isDate ? 'date' : '' } ${ threw ? 'error' : '' } ` , ( ) => {
108+ if ( threw ) {
109+ expect ( ( ) => IsoDate . parse ( value ) ) . toThrow ( threw ) ;
110+ }
111+ else {
112+ const isoDate = IsoDate . parse ( value ) ;
113+ if ( isYear ) {
114+ expect ( isoDate . isYear ( ) ) . toBeTruthy ( ) ;
115+ expect ( isoDate . isMonth ( ) ) . toBeFalsy ( ) ;
116+ expect ( isoDate . isDate ( ) ) . toBeFalsy ( ) ;
117+ expect ( isoDate . isDatetime ( ) ) . toBeFalsy ( ) ;
118+ }
119+ else if ( isMonth ) {
120+ expect ( isoDate . isYear ( ) ) . toBeFalsy ( ) ;
121+ expect ( isoDate . isMonth ( ) ) . toBeTruthy ( ) ;
122+ expect ( isoDate . isDate ( ) ) . toBeFalsy ( ) ;
123+ expect ( isoDate . isDatetime ( ) ) . toBeFalsy ( ) ;
124+ }
125+ else if ( isDate ) {
126+ expect ( isoDate . isYear ( ) ) . toBeFalsy ( ) ;
127+ expect ( isoDate . isMonth ( ) ) . toBeFalsy ( ) ;
128+ expect ( isoDate . isDate ( ) ) . toBeTruthy ( ) ;
129+ expect ( isoDate . isDatetime ( ) ) . toBeFalsy ( ) ;
130+ }
131+ expect ( isoDate . toString ( ) ) . toBe ( value . trim ( ) ) ;
132+ }
104133 } ) ;
105134 } ) ;
106135} ) ;
107136
108- describe ( 'IsoDate.toString' , ( ) => {
109- const tests : Array < { input : string ; expected : string ; } > = [
110- { input : '2025-01-01' , expected : '2025-01-01' } ,
111- { input : '2025-01' , expected : '2025-01' } ,
112- { input : '2025' , expected : '2025' }
137+
138+ describe ( 'IsoDate.daysInMonth()' , ( ) => {
139+ const tests : Array < { year : number ; month : number , expected : number ; } > = [
140+ { year : 2025 , month : 1 , expected : 31 } ,
141+ { year : 2025 , month : 2 , expected : 28 } ,
142+ { year : 2025 , month : 3 , expected : 31 } ,
143+ { year : 2025 , month : 4 , expected : 30 } ,
144+ { year : 2025 , month : 5 , expected : 31 } ,
145+ { year : 2025 , month : 6 , expected : 30 } ,
146+ { year : 2025 , month : 7 , expected : 31 } ,
147+ { year : 2025 , month : 8 , expected : 31 } ,
148+ { year : 2025 , month : 9 , expected : 30 } ,
149+ { year : 2025 , month : 10 , expected : 31 } ,
150+ { year : 2025 , month : 11 , expected : 30 } ,
151+ { year : 2025 , month : 12 , expected : 31 } ,
152+ { year : 2024 , month : 2 , expected : 29 } , // leap year
113153 ] ;
114154
115- tests . forEach ( ( { input , expected} ) => {
116- test ( `properly prints out ' ${ input } ' as ' ${ expected } ' ` , ( ) => {
117- const isoDate = IsoDate . parse ( input )
118- expect ( isoDate . toString ( ) ) . toBe ( expected )
155+ tests . forEach ( ( { year , month , expected } ) => {
156+ test ( `properly calculates ${ year } - ${ month } to have ${ expected } days ` , ( ) => {
157+ const days = IsoDate . daysInMonth ( year , month ) ;
158+ expect ( days ) . toBe ( expected ) ;
119159 } ) ;
120160 } ) ;
121- } )
161+ } ) ;
0 commit comments