Simon Egersand
2017-07-29 d2cf678ab2141cc0de805d56e2cad2c56dfa50e9
commit | author | age
25757d 1 /* global it, describe, expect, jasmine, done, jest */
SE 2
3 import React from 'react'; // eslint-disable-line no-unused-vars
290be5 4 import moment from 'moment';
SE 5 import utils from './testUtils';
6
7 describe('Datetime', () => {
8     it('create component', () => {
9         const component = utils.createDatetime({});
10
11         expect(component).toBeDefined();
12         expect(component.find('.rdt > .form-control').length).toEqual(1);
13         expect(component.find('.rdt > .rdtPicker').length).toEqual(1);
25757d 14     });
SE 15
16     it('viewMode=days: renders days, week days, month, year', () => {
17         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
18             component = utils.createDatetime({ viewMode: 'days', defaultValue: date });
19         utils.openDatepicker(component);
20
21         // Month and year
22         expect(component.find('.rdtSwitch').text()).toEqual('January 2000');
23
24         // Week days
25         const expectedWeekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
26         actualWeekdays = component.find('.rdtDays .dow').map((element) =>
27             element.text()
28         );
29         expect(actualWeekdays).toEqual(expectedWeekDays);
30
31         // Dates
32         // "Old" dates belonging to prev month
33         const oldDatesIndexes = [0, 1, 2, 3, 4, 5];
34         oldDatesIndexes.forEach((index) => {
35             expect(utils.getNthDay(component, index).hasClass('rdtOld')).toBeTruthy();
36         });
37
38         // Dates belonging to current month
39         for (let i = 6; i < 37; i++) {
40             expect(utils.getNthDay(component, i).hasClass('rdtDay')).toBeTruthy();
41             expect(utils.getNthDay(component, i).hasClass('rdtOld')).toBeFalsy();
42             expect(utils.getNthDay(component, i).hasClass('rdtNew')).toBeFalsy();
43         }
44
45         // "New" dates belonging to next month
46         const nextDatesIndexes = [37, 38, 39, 40, 41];
47         nextDatesIndexes.forEach((index) => {
48             expect(utils.getNthDay(component, index).hasClass('rdtNew')).toBeTruthy();
49         });
290be5 50     });
SE 51
39e146 52     it('switch from day view to time view and back', () => {
290be5 53         const component = utils.createDatetime({});
SE 54
55         expect(utils.isDayView(component)).toBeTruthy();
56         utils.clickOnElement(component.find('.rdtTimeToggle'));
57         expect(utils.isTimeView(component)).toBeTruthy();
39e146 58         utils.clickOnElement(component.find('.rdtSwitch'));
SE 59         expect(utils.isDayView(component)).toBeTruthy();
290be5 60     });
SE 61
62     it('persistent valid months going monthView->yearView->monthView', () => {
63         const dateBefore = new Date().getFullYear() + '-06-01',
64             component = utils.createDatetime({ viewMode: 'months', isValidDate: (current) =>
65                 current.isBefore(moment(dateBefore, 'YYYY-MM-DD'))
66             });
67
68         expect(utils.isMonthView(component)).toBeTruthy();
69         expect(utils.getNthMonth(component, 4).hasClass('rdtDisabled')).toEqual(false);
70         expect(utils.getNthMonth(component, 5).hasClass('rdtDisabled')).toEqual(true);
71
72         // Go to year view
73         utils.clickOnElement(component.find('.rdtSwitch'));
74         expect(utils.isYearView(component)).toBeTruthy();
75
76         expect(utils.getNthYear(component, 0).hasClass('rdtDisabled')).toEqual(false);
77         expect(utils.getNthYear(component, 9).hasClass('rdtDisabled')).toEqual(true);
78
79         utils.clickNthYear(component, 8);
80         expect(utils.getNthMonth(component, 4).hasClass('rdtDisabled')).toEqual(false);
81         expect(utils.getNthMonth(component, 5).hasClass('rdtDisabled')).toEqual(true);
82     });
83
84     it('step through views', () => {
85         const component = utils.createDatetime({ viewMode: 'time' });
86
87         expect(utils.isTimeView(component)).toBeTruthy();
88         utils.clickOnElement(component.find('.rdtSwitch'));
89         expect(utils.isDayView(component)).toBeTruthy();
90         utils.clickOnElement(component.find('.rdtSwitch'));
91         expect(utils.isMonthView(component)).toBeTruthy();
92         utils.clickOnElement(component.find('.rdtSwitch'));
93         expect(utils.isYearView(component)).toBeTruthy();
94     });
95
96     it('selectYear', () => {
97         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
98             component = utils.createDatetime({ viewMode: 'years', defaultValue: date });
99         expect(utils.isYearView(component)).toBeTruthy();
100         expect(component.find('.rdtSwitch').text()).toEqual('2000-2009');
101
102         // Click first year (1999)
103         utils.clickOnElement(component.find('.rdtYear').at(0));
104         expect(utils.isMonthView(component)).toBeTruthy();
105         expect(component.find('.rdtSwitch').text()).toEqual('1999');
106     });
107
108     it('increase decade', () => {
109         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
110             component = utils.createDatetime({ viewMode: 'years', defaultValue: date });
111
112         expect(component.find('.rdtSwitch').text()).toEqual('2000-2009');
113         utils.clickOnElement(component.find('.rdtNext span').at(0));
114         expect(component.find('.rdtSwitch').text()).toEqual('2010-2019');
115         utils.clickOnElement(component.find('.rdtNext span').at(0));
116         expect(component.find('.rdtSwitch').text()).toEqual('2020-2029');
117     });
118
119     it('decrease decade', () => {
120         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
121             component = utils.createDatetime({ viewMode: 'years', defaultValue: date });
122
123         expect(component.find('.rdtSwitch').text()).toEqual('2000-2009');
124         utils.clickOnElement(component.find('.rdtPrev span').at(0));
125         expect(component.find('.rdtSwitch').text()).toEqual('1990-1999');
126         utils.clickOnElement(component.find('.rdtPrev span').at(0));
127         expect(component.find('.rdtSwitch').text()).toEqual('1980-1989');
128     });
129
130     it('select month', () => {
131         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
132             component = utils.createDatetime({ viewMode: 'months', defaultValue: date });
133
134         expect(utils.isMonthView(component)).toBeTruthy();
135         expect(component.find('.rdtSwitch').text()).toEqual('2000');
136         // Click any month to enter day view
137         utils.clickNthMonth(component, 1);
138         expect(utils.isDayView(component)).toBeTruthy();
139         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('1');
140     });
141
142     it('increase year', () => {
143         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
144             component = utils.createDatetime({ viewMode: 'months', defaultValue: date });
145
146         expect(component.find('.rdtSwitch').text()).toEqual('2000');
147         utils.clickOnElement(component.find('.rdtNext span').at(0));
148         expect(component.find('.rdtSwitch').text()).toEqual('2001');
149         utils.clickOnElement(component.find('.rdtNext span').at(0));
150         expect(component.find('.rdtSwitch').text()).toEqual('2002');
151     });
152
153     it('decrease year', () => {
154         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
155             component = utils.createDatetime({ viewMode: 'months', defaultValue: date });
156
157         expect(component.find('.rdtSwitch').text()).toEqual('2000');
158         utils.clickOnElement(component.find('.rdtPrev span').at(0));
159         expect(component.find('.rdtSwitch').text()).toEqual('1999');
160         utils.clickOnElement(component.find('.rdtPrev span').at(0));
161         expect(component.find('.rdtSwitch').text()).toEqual('1998');
162     });
163
164     it('increase month', () => {
165         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
166             component = utils.createDatetime({ defaultValue: date });
167
168         expect(component.find('.rdtSwitch').text()).toEqual('January 2000');
169         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('0');
170         utils.clickOnElement(component.find('.rdtNext span').at(0));
171         expect(component.find('.rdtSwitch').text()).toEqual('February 2000');
172         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('1');
173         utils.clickOnElement(component.find('.rdtNext span').at(0));
174         expect(component.find('.rdtSwitch').text()).toEqual('March 2000');
175         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('2');
176     });
177
178     it('decrease month', () => {
179         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
180             component = utils.createDatetime({ defaultValue: date });
181
182         expect(component.find('.rdtSwitch').text()).toEqual('January 2000');
183         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('0');
184         utils.clickOnElement(component.find('.rdtPrev span').at(0));
185         expect(component.find('.rdtSwitch').text()).toEqual('December 1999');
186         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('11');
187         utils.clickOnElement(component.find('.rdtPrev span').at(0));
188         expect(component.find('.rdtSwitch').text()).toEqual('November 1999');
189         expect(component.find('.rdtSwitch').getDOMNode().getAttribute('data-value')).toEqual('10');
190     });
191
192     it('open picker', () => {
193         const component = utils.createDatetime();
194         expect(utils.isOpen(component)).toBeFalsy();
794700 195         utils.openDatepicker(component);
290be5 196         expect(utils.isOpen(component)).toBeTruthy();
39e146 197     });
SE 198
199     it('sets CSS class on selected item (day)', () => {
200         const component = utils.createDatetime({ viewMode: 'days' });
201         utils.openDatepicker(component);
202         utils.clickNthDay(component, 13);
203         expect(utils.getNthDay(component, 13).hasClass('rdtActive')).toBeTruthy();
204     });
205
206     it('sets CSS class on selected item (month)', () => {
207         const component = utils.createDatetime({ viewMode: 'months', dateFormat: 'YYYY-MM' });
208         utils.openDatepicker(component);
209         utils.clickNthMonth(component, 4);
210         expect(utils.getNthMonth(component, 4).hasClass('rdtActive')).toBeTruthy();
211     });
212
213     it('sets CSS class on selected item (year)', () => {
214         const component = utils.createDatetime({ viewMode: 'years', dateFormat: 'YYYY' });
215         utils.openDatepicker(component);
216         utils.clickNthYear(component, 3);
217         expect(utils.getNthYear(component, 3).hasClass('rdtActive')).toBeTruthy();
218     });
219
220     it('sets CSS class on days outside of month', () => {
221         const date = new Date(2000, 0, 15, 2, 2, 2, 2),
222             prevMonthDaysIndexes = [0, 1, 2, 3, 4, 5],
223             nextMonthDaysIndexes = [37, 38, 39, 40, 41],
224             component = utils.createDatetime({ viewMode: 'days', defaultValue: date });
225
226         utils.openDatepicker(component);
227
25757d 228         prevMonthDaysIndexes.forEach((index) => {
39e146 229             expect(utils.getNthDay(component, index).hasClass('rdtOld')).toBeTruthy();
SE 230         });
25757d 231         nextMonthDaysIndexes.forEach((index) => {
39e146 232             expect(utils.getNthDay(component, index).hasClass('rdtNew')).toBeTruthy();
SE 233         });
234     });
235
236     it('selected day persists (in UI) when navigating to prev month', () => {
237         const date = new Date(2000, 0, 3, 2, 2, 2, 2),
238             component = utils.createDatetime({ viewMode: 'days', defaultValue: date });
239
240         utils.openDatepicker(component);
241         expect(utils.getNthDay(component, 8).hasClass('rdtActive')).toBeTruthy();
242         // Go to previous month
243         utils.clickOnElement(component.find('.rdtDays .rdtPrev span'));
244         expect(utils.getNthDay(component, 36).hasClass('rdtActive')).toBeTruthy();
25757d 245     });
SE 246
247     it('sets CSS class on today date', () => {
248         const specificDate = moment('2015-04-19'),
249             component = utils.createDatetime({ defaultValue: specificDate });
250
251         // Mock the today date
252         jasmine.clock().mockDate(specificDate.toDate());
253
254         utils.openDatepicker(component);
255         expect(component.find('.rdtDay.rdtToday').text()).toEqual('19');
39e146 256     });
SE 257
436734 258     // Proof of bug [FIXED]
39e146 259     it('should show correct selected month when traversing view modes', () => {
SE 260         const date = new Date(2000, 4, 3, 2, 2, 2, 2),
261             component = utils.createDatetime({ viewMode: 'days', defaultValue: date });
262
263         utils.openDatepicker(component);
264
265         // Go to month view
266         utils.clickOnElement(component.find('.rdtSwitch'));
267
268         // Here the selected month is _May_, which is correct
269         expect(component.find('.rdtMonth .rdtActive').text()).toEqual('May');
270
271         // Go to year view
272         utils.clickOnElement(component.find('.rdtSwitch'));
273
274         // Click the selected year (2000)
275         utils.clickNthYear(component, 1);
276
277         // The selected month is now _January_
436734 278         expect(component.find('.rdtMonth .rdtActive').text()).toEqual('May');
290be5 279     });
SE 280
281     describe('with custom props', () => {
282         it('input=false', () => {
283             const component = utils.createDatetime({ input: false });
284             expect(component.find('.rdt > .form-control').length).toEqual(0);
285             expect(component.find('.rdt > .rdtPicker').length).toEqual(1);
286         });
287
288         it('dateFormat', () => {
289             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
290                 mDate = moment(date),
291                 component = utils.createDatetime({ value: date, dateFormat: 'M&D' });
292             expect(utils.getInputValue(component)).toEqual(mDate.format('M&D LT'));
293         });
294
295         it('dateFormat=false', () => {
296             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
297                 mDate = moment(date),
298                 component = utils.createDatetime({ value: date, dateFormat: false });
299             expect(utils.getInputValue(component)).toEqual(mDate.format('LT'));
300             // Make sure time view is active
301             expect(utils.isTimeView(component)).toBeTruthy();
302             // Make sure the date toggle is not rendered
303             expect(component.find('thead').length).toEqual(0);
304         });
305
306         it('timeFormat', () => {
307             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
308                 mDate = moment(date),
309                 format = 'HH:mm:ss:SSS',
310                 component = utils.createDatetime({ value: date, timeFormat: format });
311             expect(utils.getInputValue(component)).toEqual(mDate.format('L ' + format));
312         });
313
314         it('timeFormat=false', () => {
315             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
316                 mDate = moment(date),
317                 component = utils.createDatetime({ value: date, timeFormat: false });
318             expect(utils.getInputValue(component)).toEqual(mDate.format('L'));
319             // Make sure day view is active
320             expect(utils.isDayView(component)).toBeTruthy();
321             // Make sure the time toggle is not rendered
322             expect(component.find('.timeToggle').length).toEqual(0);
323         });
324
325         it('timeFormat with lowercase \'am\'', () => {
326             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
327                 format = 'HH:mm:ss:SSS a',
328                 component = utils.createDatetime({ value: date, timeFormat: format });
329             expect(utils.getInputValue(component)).toEqual(expect.stringMatching('.*am$'));
330         });
331
332         it('timeFormat with uppercase \'AM\'', () => {
333             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
334                 format = 'HH:mm:ss:SSS A',
335                 component = utils.createDatetime({ value: date, timeFormat: format });
336             expect(utils.getInputValue(component)).toEqual(expect.stringMatching('.*AM$'));
337         });
338
339         it('viewMode=years', () => {
340             const component = utils.createDatetime({ viewMode: 'years' });
341             expect(utils.isYearView(component)).toBeTruthy();
342         });
343
344         it('viewMode=months', () => {
345             const component = utils.createDatetime({ viewMode: 'months' });
346             expect(utils.isMonthView(component)).toBeTruthy();
347         });
348
349         it('viewMode=time', () => {
350             const component = utils.createDatetime({ viewMode: 'time' });
351             expect(utils.isTimeView(component)).toBeTruthy();
352         });
353
354         it('className -> type string', () => {
355             const component = utils.createDatetime({ className: 'custom-class' });
356             expect(component.find('.custom-class').length).toEqual(1);
357         });
358
359         it('className -> type string array', () => {
360             const component = utils.createDatetime({ className: ['custom-class1', 'custom-class2'] });
361             expect(component.find('.custom-class1').length).toEqual(1);
362             expect(component.find('.custom-class2').length).toEqual(1);
363         });
364
365         it('inputProps', () => {
366             const component = utils.createDatetime({
367                 inputProps: { className: 'custom-class', type: 'email', placeholder: 'custom-placeholder' }
368             });
369             expect(component.find('input.custom-class').length).toEqual(1);
370             expect(component.find('input').getDOMNode().type).toEqual('email');
371             expect(component.find('input').getDOMNode().placeholder).toEqual('custom-placeholder');
372         });
373
374         it('renderDay', () => {
375             let props = {},
376                 currentDate = '',
377                 selectedDate = '';
378             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
379                 mDate = moment(date),
380                 renderDayFn = (fnProps, current, selected) => {
381                     props = fnProps;
382                     currentDate = current;
383                     selectedDate = selected;
384
385                     return <td {...fnProps}>custom-content</td>;
386                 };
387
388             const component = utils.createDatetime({ value: mDate, renderDay: renderDayFn });
389
390             // Last day should be 6th of february
391             expect(currentDate.day()).toEqual(6);
392             expect(currentDate.month()).toEqual(1);
393
394             // The date must be the same
395             expect(selectedDate.isSame(mDate)).toEqual(true);
396
397             // There should be a onClick function in the props
398             expect(typeof props.onClick).toEqual('function');
399
400             // The cell text should match
401             expect(component.find('.rdtDay').at(0).text()).toEqual('custom-content');
402         });
403
404         it('renderMonth', () => {
405             let props = {},
406                 month = '',
407                 year = '',
408                 selectedDate = '';
409             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
410                 mDate = moment(date),
411                 renderMonthFn = (fnProps, fnMonth, fnYear, selected) => {
412                     props = fnProps;
413                     month = fnMonth;
414                     year = fnYear;
415                     selectedDate = selected;
416
417                     return <td {...fnProps}>custom-content</td>;
418                 };
419
420             const component = utils.createDatetime({ value: mDate, viewMode: 'months', renderMonth: renderMonthFn });
421
422             expect(month).toEqual(11);
423             expect(year).toEqual(2000);
424
425             // The date must be the same
426             expect(selectedDate.isSame(mDate)).toEqual(true);
427
428             // There should be a onClick function in the props
429             expect(typeof props.onClick).toEqual('function');
430
431             // The cell text should match
432             expect(component.find('.rdtMonth').at(0).text()).toEqual('custom-content');
433         });
434
435         it('renderYear', () => {
436             let props = {},
437                 year = '',
438                 selectedDate = '';
439             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
440                 mDate = moment(date),
441                 renderYearFn = (fnProps, fnYear, selected) => {
442                     props = fnProps;
443                     year = fnYear;
444                     selectedDate = selected;
445
446                     return <td {...fnProps}>custom-content</td>;
447                 };
448
449             const component = utils.createDatetime({ value: mDate, viewMode: 'years', renderYear: renderYearFn });
450
451             expect(year).toEqual(2010);
452
453             // The date must be the same
454             expect(selectedDate.isSame(mDate)).toEqual(true);
455
456             // There should be a onClick function in the props
457             expect(typeof props.onClick).toEqual('function');
458
459             // The cell text should match
460             expect(component.find('.rdtYear').at(0).text()).toEqual('custom-content');
461         });
462
463         it('closeOnTab=true', () => {
464             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
465                 component = utils.createDatetime({ value: date });
466
467             expect(utils.isOpen(component)).toBeFalsy();
794700 468             utils.openDatepicker(component);
290be5 469             expect(utils.isOpen(component)).toBeTruthy();
SE 470             component.find('.form-control').simulate('keyDown', { key: 'Tab', keyCode: 9, which: 9 });
471             expect(utils.isOpen(component)).toBeFalsy();
472         });
473
474         it('closeOnTab=false', () => {
475             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
476                 component = utils.createDatetime({ value: date, closeOnTab: false });
477
478             expect(utils.isOpen(component)).toBeFalsy();
794700 479             utils.openDatepicker(component);
290be5 480             expect(utils.isOpen(component)).toBeTruthy();
SE 481             component.find('.form-control').simulate('keyDown', { key: 'Tab', keyCode: 9, which: 9 });
482             expect(utils.isOpen(component)).toBeTruthy();
483         });
484
485         it('increase time', () => {
486             let i = 0;
487             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
488                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time',
489                     defaultValue: date, onChange: (selected) => {
490                         // TODO: Trigger onChange when increasing time
491                         i++;
492                         if (i > 2) {
493                             expect(true).toEqual(false); // Proof that this is not called
494                             expect(selected.hour()).toEqual(3);
495                             expect(selected.minute()).toEqual(3);
496                             expect(selected.second()).toEqual(3);
497                             done();
498                         }
499                     }});
500
501             // Check hour
f3c055 502             expect(utils.getHours(component)).toEqual('2');
290be5 503             utils.increaseHour(component);
f3c055 504             expect(utils.getHours(component)).toEqual('3');
290be5 505
SE 506             // Check minute
f3c055 507             expect(utils.getMinutes(component)).toEqual('02');
290be5 508             utils.increaseMinute(component);
f3c055 509             expect(utils.getMinutes(component)).toEqual('03');
290be5 510
SE 511             // Check second
f3c055 512             expect(utils.getSeconds(component)).toEqual('02');
290be5 513             utils.increaseSecond(component);
f3c055 514             expect(utils.getSeconds(component)).toEqual('03');
290be5 515         });
SE 516
517         it('decrease time', () => {
518             let i = 0;
519             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
520                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time',
521                     defaultValue: date, onChange: (selected) => {
522                         // TODO: Trigger onChange when increasing time
523                         i++;
524                         if (i > 2) {
525                             expect(true).toEqual(false); // Proof that this is not called
526                             expect(selected.hour()).toEqual(1);
527                             expect(selected.minute()).toEqual(1);
528                             expect(selected.second()).toEqual(1);
529                             done();
530                         }
531                     }});
532
533             // Check hour
f3c055 534             expect(utils.getHours(component)).toEqual('2');
290be5 535             utils.decreaseHour(component);
f3c055 536             expect(utils.getHours(component)).toEqual('1');
290be5 537
SE 538             // Check minute
f3c055 539             expect(utils.getMinutes(component)).toEqual('02');
290be5 540             utils.decreaseMinute(component);
f3c055 541             expect(utils.getMinutes(component)).toEqual('01');
290be5 542
SE 543             // Check second
f3c055 544             expect(utils.getSeconds(component)).toEqual('02');
290be5 545             utils.decreaseSecond(component);
f3c055 546             expect(utils.getSeconds(component)).toEqual('01');
290be5 547         });
SE 548
34dbeb 549         it('long increase time', (done) => {
290be5 550             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
SE 551                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time', defaultValue: date });
552
553             utils.increaseHour(component);
554             setTimeout(() => {
f3c055 555                 expect(utils.getHours(component)).not.toEqual('2');
SE 556                 expect(utils.getHours(component)).not.toEqual('3');
290be5 557                 done();
SE 558             }, 920);
559         });
560
34dbeb 561         it('long decrease time', (done) => {
290be5 562             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
SE 563                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time', defaultValue: date });
564
565             utils.decreaseHour(component);
566             setTimeout(() => {
f3c055 567                 expect(utils.getHours(component)).not.toEqual('1');
SE 568                 expect(utils.getHours(component)).not.toEqual('0');
290be5 569                 done();
SE 570             }, 920);
571         });
572
573         it('timeConstraints -> increase time', () => {
574             let i = 0;
575             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
576                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time',
577                     defaultValue: date, timeConstraints: { hours: { max: 6, step: 8 }, minutes: { step: 15 }},
578                     onChange: (selected) => {
579                         // TODO
580                         i++;
581                         if (i > 2) {
582                             expect(selected.minute()).toEqual(17);
583                             expect(selected.second()).toEqual(3);
584                             done();
585                         }
586                     }
587                 });
588
589             utils.increaseHour(component);
f3c055 590             expect(utils.getHours(component)).toEqual('3');
290be5 591
SE 592             utils.increaseMinute(component);
f3c055 593             expect(utils.getMinutes(component)).toEqual('17');
290be5 594
SE 595             utils.increaseSecond(component);
f3c055 596             expect(utils.getSeconds(component)).toEqual('03');
290be5 597         });
SE 598
599         it('timeConstraints -> decrease time', () => {
600             let i = 0;
601             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
602                 component = utils.createDatetime({ timeFormat: 'HH:mm:ss:SSS', viewMode: 'time',
603                     defaultValue: date, timeConstraints: { minutes: { step: 15 }}, onChange: (selected) => {
604                         // TODO
605                         i++;
606                         if (i > 2) {
607                             expect(selected.minute()).toEqual(17);
608                             expect(selected.second()).toEqual(3);
609                             done();
610                         }
611                     }
612                 });
613
614             utils.decreaseMinute(component);
f3c055 615             expect(utils.getMinutes(component)).toEqual('47');
290be5 616         });
SE 617
618         it('strictParsing=true', (done) => {
619             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
620                 mDate = moment(date),
621                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
622                 invalidStrDate = strDate + 'x',
623                 component = utils.createDatetime({ defaultValue: '', strictParsing: true,
624                     onChange: (updated) => {
625                         expect(updated, invalidStrDate);
626                         done();
627                     }});
628
629             component.find('.form-control').simulate('change', { target: { value: invalidStrDate }});
630         });
631
632         it('strictParsing=false', (done) => {
633             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
634                 mDate = moment(date),
635                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
636                 invalidStrDate = strDate + 'x',
637                 component = utils.createDatetime({ defaultValue: '', strictParsing: false,
638                     onChange: (updated) => {
639                         expect(mDate.format('L LT')).toEqual(updated.format('L LT'));
640                         done();
641                     }});
642
643             component.find('.form-control').simulate('change', { target: { value: invalidStrDate }});
644         });
645
646         it('isValidDate -> disable months', () => {
647             const dateBefore = new Date().getFullYear() + '-06-01',
648                 component = utils.createDatetime({ viewMode: 'months', isValidDate: (current) =>
649                     current.isBefore(moment(dateBefore, 'YYYY-MM-DD'))
650                 });
651
652             expect(utils.getNthMonth(component, 0).hasClass('rdtDisabled')).toEqual(false);
653             expect(utils.getNthMonth(component, 4).hasClass('rdtDisabled')).toEqual(false);
654             expect(utils.getNthMonth(component, 5).hasClass('rdtDisabled')).toEqual(true);
655             expect(utils.getNthMonth(component, 11).hasClass('rdtDisabled')).toEqual(true);
656         });
657
658         it('isValidDate -> disable years', () => {
659             const component = utils.createDatetime({ viewMode: 'years', isValidDate: (current) =>
660                 current.isBefore(moment('2016-01-01', 'YYYY-MM-DD'))
661             });
662
663             expect(utils.getNthYear(component, 0).hasClass('rdtDisabled')).toEqual(false);
664             expect(utils.getNthYear(component, 6).hasClass('rdtDisabled')).toEqual(false);
665             expect(utils.getNthYear(component, 7).hasClass('rdtDisabled')).toEqual(true);
666         });
667
668         it('locale', () => {
669             const component = utils.createDatetime({ locale: 'nl' }),
670                 expectedWeekDays = ['Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za', 'Zo'],
671                 actualWeekDays = component.find('.rdtDays .dow').map((element) =>
672                     element.text()
673                 );
674
675             expect(actualWeekDays).toEqual(expectedWeekDays);
676         });
677
678         it('locale with viewMode=months', () => {
679             const component = utils.createDatetime({ locale: 'nl', viewMode: 'months' }),
680                 expectedMonths = ['Mrt', 'Mei'],
681                 actualMonths = [utils.getNthMonth(component, 2).text(), utils.getNthMonth(component, 4).text()];
682
683             expect(actualMonths).toEqual(expectedMonths);
684         });
685
25757d 686         it('closeOnSelect=false', (done) => {
290be5 687             const component = utils.createDatetime({ closeOnSelect: false });
SE 688
25757d 689             // A unknown race condition is causing this test to fail without this time out,
SE 690             // and when the test fails it says:
691             // 'Timeout - Async callback was not invoked within timeout'
692             // Ideally it would say something else but at least we know the tests are passing now
39e146 693             setTimeout(() => {
SE 694                 expect(utils.isOpen(component)).toBeFalsy();
695                 utils.openDatepicker(component);
696                 expect(utils.isOpen(component)).toBeTruthy();
697                 utils.clickNthDay(component, 2);
698                 expect(utils.isOpen(component)).toBeTruthy();
25757d 699                 done();
39e146 700             }, 0);
290be5 701         });
SE 702
25757d 703         it('closeOnSelect=true', (done) => {
290be5 704             const component = utils.createDatetime({ closeOnSelect: true });
SE 705
25757d 706             // A unknown race condition is causing this test to fail without this time out,
SE 707             // and when the test fails it says:
708             // 'Timeout - Async callback was not invoked within timeout'
709             // Ideally it would say something else but at least we know the tests are passing now
39e146 710             setTimeout(() => {
SE 711                 expect(utils.isOpen(component)).toBeFalsy();
712                 utils.openDatepicker(component);
713                 expect(utils.isOpen(component)).toBeTruthy();
714                 utils.clickNthDay(component, 2);
715                 expect(utils.isOpen(component)).toBeFalsy();
25757d 716                 done();
39e146 717             }, 0);
290be5 718         });
SE 719
720         describe('defaultValue of type', () => {
721             it('date', () => {
722                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
723                     momentDate = moment(date),
724                     strDate = momentDate.format('L') + ' ' + momentDate.format('LT'),
725                     component = utils.createDatetime({ defaultValue: date });
726                 expect(utils.getInputValue(component)).toEqual(strDate);
727             });
728
729             it('moment', () => {
730                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
731                     momentDate = moment(date),
732                     strDate = momentDate.format('L') + ' ' + momentDate.format('LT'),
733                     component = utils.createDatetime({ defaultValue: momentDate });
734                 expect(utils.getInputValue(component)).toEqual(strDate);
735             });
736
737             it('string', () => {
738                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
739                     momentDate = moment(date),
740                     strDate = momentDate.format('L') + ' ' + momentDate.format('LT'),
741                     component = utils.createDatetime({ defaultValue: strDate });
742                 expect(utils.getInputValue(component)).toEqual(strDate);
743             });
744         });
745
746         describe('timeFormat with', () => {
747             it('milliseconds', () => {
748                 const component = utils.createDatetime({ viewMode: 'time', timeFormat: 'HH:mm:ss:SSS' });
749                 expect(component.find('.rdtCounter').length).toEqual(4);
750                 // TODO: Test that you can input a value in milli seconds input
751             });
752
753             it('seconds', () => {
754                 const component = utils.createDatetime({ viewMode: 'time', timeFormat: 'HH:mm:ss' });
755                 expect(component.find('.rdtCounter').length).toEqual(3);
756             });
757
758             it('minutes', () => {
759                 const component = utils.createDatetime({ viewMode: 'time', timeFormat: 'HH:mm' });
760                 expect(component.find('.rdtCounter').length).toEqual(2);
761             });
762
763             it('hours', () => {
764                 const component = utils.createDatetime({ viewMode: 'time', timeFormat: 'HH' });
765                 expect(component.find('.rdtCounter').length).toEqual(1);
766             });
767         });
64fc6a 768
SE 769         describe('being updated and should trigger update', () => {
25757d 770             it('dateFormat -> value should change format', (done) => {
64fc6a 771                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
SE 772                     component = utils.createDatetime({
773                         dateFormat: 'YYYY-MM-DD', timeFormat: false, defaultValue: date
774                     });
775
776                 const valueBefore = utils.getInputValue(component);
25757d 777                 // A unknown race condition is causing this test to fail without this time out,
SE 778                 // and when the test fails it says:
779                 // 'Timeout - Async callback was not invoked within timeout'
780                 // Ideally it would say something else but at least we know the tests are passing now
39e146 781                 setTimeout(() => {
SE 782                     component.setProps({ dateFormat: 'DD.MM.YYYY' });
783                     const valueAfter = utils.getInputValue(component);
64fc6a 784
39e146 785                     expect(valueBefore).not.toEqual(valueAfter);
25757d 786                     done();
39e146 787                 }, 0);
64fc6a 788             });
SE 789
790             it('UTC -> value should change format (true->false)', () => {
791                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
792                     momentDate = moment(date),
793                     component = utils.createDatetime({ value: momentDate, utc: true });
794
795                 const valueBefore = utils.getInputValue(component);
796                 component.setProps({ utc: false }, () => {
797                     const valueAfter = utils.getInputValue(component);
798
799                     expect(valueBefore).not.toEqual(valueAfter);
800                 });
801             });
802
803             it('UTC -> value should change format (false->true)', () => {
804                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
805                     momentDate = moment(date),
806                     component = utils.createDatetime({ value: momentDate, utc: false });
807
808                 const valueBefore = utils.getInputValue(component);
809                 component.setProps({ utc: true }, () => {
810                     const valueAfter = utils.getInputValue(component);
811
812                     expect(valueBefore).not.toEqual(valueAfter);
813                 });
814             });
815
816             it('locale -> picker should change language (viewMode=days)', () => {
817                 const component = utils.createDatetime({ viewMode: 'days', locale: 'nl' }),
818                     weekdaysBefore = component.find('.rdtDays .dow').map((element) =>
819                         element.text()
820                     );
821
822                 component.setProps({ locale: 'sv' });
823                 const weekdaysAfter = component.find('.rdtDays .dow').map((element) =>
824                     element.text()
825                 );
826
827                 expect(weekdaysBefore).not.toEqual(weekdaysAfter);
828             });
829
830             it('locale -> picker should change language (viewMode=months)', () => {
831                 const component = utils.createDatetime({ viewMode: 'months', locale: 'nl' }),
832                     monthsBefore = [utils.getNthMonth(component, 2).text(), utils.getNthMonth(component, 4).text()];
833
834                 component.setProps({ locale: 'sv' });
835                 const monthsAfter = [utils.getNthMonth(component, 2).text(), utils.getNthMonth(component, 4).text()];
836
837                 expect(monthsBefore).not.toEqual(monthsAfter);
838             });
839         });
290be5 840     });
SE 841
842     describe('event listeners', () => {
39e146 843         describe('onBlur', () => {
SE 844             it('when selecting a date', () => {
845                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
846                     onBlurFn = jest.fn(),
847                     component = utils.createDatetime({ value: date, onBlur: onBlurFn, closeOnSelect: true });
290be5 848
39e146 849                 utils.openDatepicker(component);
SE 850                 // Close component by selecting a date
851                 utils.clickNthDay(component, 2);
852                 expect(onBlurFn).toHaveBeenCalledTimes(1);
853             });
854
855             it('when selecting date (value=null and closeOnSelect=true)', () => {
856                 const onBlurFn = jest.fn(),
857                     component = utils.createDatetime({ value: null, onBlur: onBlurFn, closeOnSelect: true });
858
859                 utils.openDatepicker(component);
860                 // Close component by selecting a date
861                 utils.clickNthDay(component, 2);
862                 expect(onBlurFn).toHaveBeenCalledTimes(1);
863             });
864
865             it('when selecting date (value=null and closeOnSelect=false)', () => {
866                 const onBlurFn = jest.fn(),
867                     component = utils.createDatetime({ value: null, onBlur: onBlurFn, closeOnSelect: false });
868
869                 utils.openDatepicker(component);
870                 // Close component by selecting a date
871                 utils.clickNthDay(component, 2);
872                 expect(onBlurFn).not.toHaveBeenCalled();
873             });
794700 874         });
SE 875
39e146 876         it('onFocus when opening datepicker', () => {
290be5 877             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
SE 878                 onFocusFn = jest.fn(),
879                 component = utils.createDatetime({ value: date, onFocus: onFocusFn });
880
794700 881             utils.openDatepicker(component);
290be5 882             expect(onFocusFn).toHaveBeenCalledTimes(1);
SE 883         });
884
39e146 885         describe('onChange', () => {
SE 886             it('trigger only when last selection type is selected', () => {
887                 // By selection type I mean if you CAN select day, then selecting a month
888                 // should not trigger onChange
889                 const onChangeFn = jest.fn(),
890                     component = utils.createDatetime({ viewMode: 'years', onChange: onChangeFn });
290be5 891
39e146 892                 utils.openDatepicker(component);
290be5 893
39e146 894                 utils.clickNthYear(component, 2);
SE 895                 expect(onChangeFn).not.toHaveBeenCalled();
896
897                 utils.clickNthMonth(component, 2);
898                 expect(onChangeFn).not.toHaveBeenCalled();
899
900                 utils.clickNthDay(component, 2);
901                 expect(onChangeFn).toHaveBeenCalled();
902             });
903
904             it('when selecting date', (done) => {
905                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
906                     mDate = moment(date),
907                     component = utils.createDatetime({ defaultValue: date, onChange: (selected) => {
908                         expect(selected.date()).toEqual(2);
290be5 909                         expect(selected.month()).toEqual(mDate.month());
SE 910                         expect(selected.year()).toEqual(mDate.year());
911                         done();
39e146 912                     }});
290be5 913
39e146 914                 utils.clickNthDay(component, 7);
SE 915             });
916
917             it('when selecting multiple date in a row', (done) => {
918                 let i = 0;
919                 const date = new Date(2000, 0, 15, 2, 2, 2, 2),
920                     mDate = moment(date),
921                     component = utils.createDatetime({ defaultValue: date, onChange: (selected) => {
922                         i++;
923                         if (i > 2) {
924                             expect(selected.date()).toEqual(4);
925                             expect(selected.month()).toEqual(mDate.month());
926                             expect(selected.year()).toEqual(mDate.year());
927                             done();
928                         }
929                     }});
930
931                 utils.clickNthDay(component, 7);
932                 utils.clickNthDay(component, 8);
933                 utils.clickNthDay(component, 9);
934             });
935
936             it('when selecting month', () => {
752fa8 937                 const date = Date.UTC(2000, 0, 15, 2, 2, 2, 2),
39e146 938                     onChangeFn = jest.fn(),
SE 939                     component = utils.createDatetime({ defaultValue: date, dateFormat: 'YYYY-MM', onChange: onChangeFn });
940
941                 utils.clickNthMonth(component, 2);
942                 expect(onChangeFn).toHaveBeenCalledTimes(1);
752fa8 943                 expect(onChangeFn.mock.calls[0][0].toJSON()).toEqual('2000-03-15T02:02:02.002Z');
39e146 944             });
SE 945
946             it('when selecting year', () => {
752fa8 947                 const date = Date.UTC(2000, 0, 15, 2, 2, 2, 2),
39e146 948                     onChangeFn = jest.fn(),
SE 949                     component = utils.createDatetime({ defaultValue: date, dateFormat: 'YYYY', onChange: onChangeFn });
950
951                 utils.clickNthYear(component, 2);
952                 expect(onChangeFn).toHaveBeenCalledTimes(1);
752fa8 953                 expect(onChangeFn.mock.calls[0][0].toJSON()).toEqual('2001-01-15T02:02:02.002Z');
39e146 954             });
SE 955
956             it('when selecting time', () => {
957                 // Did not manage to be able to get onChange to trigger, even though I know it does.
958                 // The listener for the time buttons are set up differently because of having to handle both
959                 // onMouseDown and onMouseUp. Not sure how to test it.
960                 expect(true).toEqual(true);
961             });
962
290be5 963         });
39e146 964
290be5 965     });
SE 966
967     describe('with set value', () => {
968         it('date value', () => {
969             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
970                 mDate = moment(date),
971                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
972                 component = utils.createDatetime({ value: date });
973             expect(utils.getInputValue(component)).toEqual(strDate);
974         });
975
976         it('moment value', () => {
977             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
978                 mDate = moment(date),
979                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
980                 component = utils.createDatetime({ value: mDate });
981             expect(utils.getInputValue(component)).toEqual(strDate);
982         });
983
984         it('string value', () => {
985             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
986                 mDate = moment(date),
987                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
988                 component = utils.createDatetime({ value: strDate });
989             expect(utils.getInputValue(component)).toEqual(strDate);
990         });
991
992         it('UTC value from local moment', () => {
993             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
994                 momentDate = moment(date),
995                 momentDateUTC = moment.utc(date),
996                 strDateUTC = momentDateUTC.format('L') + ' ' + momentDateUTC.format('LT'),
997                 component = utils.createDatetime({ value: momentDate, utc: true });
998             expect(utils.getInputValue(component)).toEqual(strDateUTC);
999         });
1000
1001         it('UTC value from UTC moment', () => {
1002             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1003                 momentDateUTC = moment.utc(date),
1004                 strDateUTC = momentDateUTC.format('L') + ' ' + momentDateUTC.format('LT'),
1005                 component = utils.createDatetime({ value: momentDateUTC, utc: true });
1006             expect(utils.getInputValue(component)).toEqual(strDateUTC);
1007         });
1008
1009         it('UTC value from UTC string', () => {
1010             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1011                 momentDateUTC = moment.utc(date),
1012                 strDateUTC = momentDateUTC.format('L') + ' ' + momentDateUTC.format('LT'),
1013                 component = utils.createDatetime({ value: strDateUTC, utc: true });
1014             expect(utils.getInputValue(component)).toEqual(strDateUTC);
1015         });
1016
1017         it('invalid string value', (done) => {
1018             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1019                 mDate = moment(date),
1020                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
1021                 component = utils.createDatetime({ defaultValue: 'invalid-value', onChange: (updated) => {
1022                     expect(mDate.format('L LT')).toEqual(updated.format('L LT'));
1023                     done();
1024                 }});
1025
1026             expect(component.find('.form-control').getDOMNode().value).toEqual('invalid-value');
1027             component.find('.form-control').simulate('change', { target: { value: strDate }});
1028         });
1029
1030         it('delete invalid string value', (done) => {
1031             const date = new Date(2000, 0, 15, 2, 2, 2, 2),
1032                 component = utils.createDatetime({ defaultValue: date, onChange: (date) => {
1033                     expect(date).toEqual('');
1034                     done();
1035                 }});
1036
1037             component.find('.form-control').simulate('change', { target: { value: '' }});
1038         });
1039
1040         it('invalid moment object', (done) => {
1041             const invalidValue = moment(null),
1042                 date = new Date(2000, 0, 15, 2, 2, 2, 2),
1043                 mDate = moment(date),
1044                 strDate = mDate.format('L') + ' ' + mDate.format('LT'),
1045                 component = utils.createDatetime({ value: invalidValue, onChange: (updated) => {
1046                     expect(mDate.format('L LT')).toEqual(updated.format('L LT'));
1047                     done();
1048                 }});
1049
1050             expect(component.find('.form-control').getDOMNode().value).toEqual('');
1051             component.find('.form-control').simulate('change', { target: { value: strDate }});
1052         });
1053
1054     });
1055 });