Commit 68e364211969e574fc824e8c0a543bec5fc1d948

Authored by Aresn
Committed by GitHub
2 parents 5da043ee db1b716f

Merge pull request #1712 from SergioCrisostomo/add-more-datepicker-tests

Refactor cell click handler and add more date picker and date range picker tests
src/components/date-picker/base/date-table.vue
1 <template> 1 <template>
2 <div 2 <div
3 :class="classes" 3 :class="classes"
4 - @click="handleClick"  
5 @mousemove="handleMouseMove"> 4 @mousemove="handleMouseMove">
6 <div :class="[prefixCls + '-header']"> 5 <div :class="[prefixCls + '-header']">
7 <span>{{ t('i.datepicker.weeks.sun') }}</span><span>{{ t('i.datepicker.weeks.mon') }}</span><span>{{ t('i.datepicker.weeks.tue') }}</span><span>{{ t('i.datepicker.weeks.wed') }}</span><span>{{ t('i.datepicker.weeks.thu') }}</span><span>{{ t('i.datepicker.weeks.fri') }}</span><span>{{ t('i.datepicker.weeks.sat') }}</span> 6 <span>{{ t('i.datepicker.weeks.sun') }}</span><span>{{ t('i.datepicker.weeks.mon') }}</span><span>{{ t('i.datepicker.weeks.tue') }}</span><span>{{ t('i.datepicker.weeks.wed') }}</span><span>{{ t('i.datepicker.weeks.thu') }}</span><span>{{ t('i.datepicker.weeks.fri') }}</span><span>{{ t('i.datepicker.weeks.sat') }}</span>
8 </div> 7 </div>
9 - <span :class="getCellCls(cell)" v-for="(cell, index) in readCells"><em :index="index">{{ cell.text }}</em></span> 8 + <span :class="getCellCls(cell)" v-for="(cell, index) in readCells"><em :index="index" @click="handleClick(cell)">{{ cell.text }}</em></span>
10 </div> 9 </div>
11 </template> 10 </template>
12 <script> 11 <script>
@@ -106,6 +105,7 @@ @@ -106,6 +105,7 @@
106 const cell_tmpl = { 105 const cell_tmpl = {
107 text: '', 106 text: '',
108 type: '', 107 type: '',
  108 + date: null,
109 selected: false, 109 selected: false,
110 disabled: false, 110 disabled: false,
111 range: false, 111 range: false,
@@ -117,14 +117,8 @@ @@ -117,14 +117,8 @@
117 const cell = deepCopy(cell_tmpl); 117 const cell = deepCopy(cell_tmpl);
118 cell.type = 'prev-month'; 118 cell.type = 'prev-month';
119 cell.text = dateCountOfLastMonth - (day - 1) + i; 119 cell.text = dateCountOfLastMonth - (day - 1) + i;
120 -  
121 - let prevMonth = this.month - 1;  
122 - let prevYear = this.year;  
123 - if (this.month === 0) {  
124 - prevMonth = 11;  
125 - prevYear -= 1;  
126 - }  
127 - const time = clearHours(new Date(prevYear, prevMonth, cell.text)); 120 + cell.date = new Date(this.year, this.month - 1, cell.text);
  121 + const time = clearHours(cell.date);
128 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time)); 122 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
129 cells.push(cell); 123 cells.push(cell);
130 } 124 }
@@ -132,9 +126,10 @@ @@ -132,9 +126,10 @@
132 126
133 for (let i = 1; i <= dateCountOfMonth; i++) { 127 for (let i = 1; i <= dateCountOfMonth; i++) {
134 const cell = deepCopy(cell_tmpl); 128 const cell = deepCopy(cell_tmpl);
135 - const time = clearHours(new Date(this.year, this.month, i));  
136 - cell.type = time === today ? 'today' : 'normal';  
137 cell.text = i; 129 cell.text = i;
  130 + cell.date = new Date(this.year, this.month, cell.text);
  131 + const time = clearHours(cell.date);
  132 + cell.type = time === today ? 'today' : 'normal';
138 cell.selected = time === selectDay; 133 cell.selected = time === selectDay;
139 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time)); 134 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
140 cell.range = time >= minDay && time <= maxDay; 135 cell.range = time >= minDay && time <= maxDay;
@@ -149,14 +144,8 @@ @@ -149,14 +144,8 @@
149 const cell = deepCopy(cell_tmpl); 144 const cell = deepCopy(cell_tmpl);
150 cell.type = 'next-month'; 145 cell.type = 'next-month';
151 cell.text = i; 146 cell.text = i;
152 -  
153 - let nextMonth = this.month + 1;  
154 - let nextYear = this.year;  
155 - if (this.month === 11) {  
156 - nextMonth = 0;  
157 - nextYear += 1;  
158 - }  
159 - const time = clearHours(new Date(nextYear, nextMonth, cell.text)); 147 + cell.date = new Date(this.year, this.month + 1, cell.text);
  148 + const time = clearHours(cell.date);
160 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time)); 149 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
161 cells.push(cell); 150 cells.push(cell);
162 } 151 }
@@ -165,71 +154,39 @@ @@ -165,71 +154,39 @@
165 } 154 }
166 }, 155 },
167 methods: { 156 methods: {
168 - getDateOfCell (cell) {  
169 - let year = this.year;  
170 - let month = this.month;  
171 - let day = cell.text;  
172 -  
173 - const date = this.date;  
174 - const hours = date.getHours();  
175 - const minutes = date.getMinutes();  
176 - const seconds = date.getSeconds();  
177 -  
178 - if (cell.type === 'prev-month') {  
179 - if (month === 0) {  
180 - month = 11;  
181 - year--;  
182 - } else {  
183 - month--;  
184 - }  
185 - } else if (cell.type === 'next-month') {  
186 - if (month === 11) {  
187 - month = 0;  
188 - year++;  
189 - } else {  
190 - month++;  
191 - }  
192 - }  
193 -  
194 - return new Date(year, month, day, hours, minutes, seconds);  
195 - },  
196 - handleClick (event) {  
197 - const target = event.target;  
198 - if (target.tagName === 'EM') {  
199 - const cell = this.cells[parseInt(event.target.getAttribute('index'))];  
200 - if (cell.disabled) return;  
201 -  
202 - const newDate = this.getDateOfCell(cell);  
203 -  
204 - if (this.selectionMode === 'range') {  
205 - if (this.minDate && this.maxDate) { 157 + handleClick (cell) {
  158 +
  159 + if (cell.disabled) return;
  160 + const newDate = cell.date;
  161 +
  162 + if (this.selectionMode === 'range') {
  163 + if (this.minDate && this.maxDate) {
  164 + const minDate = new Date(newDate.getTime());
  165 + const maxDate = null;
  166 + this.rangeState.selecting = true;
  167 + this.markRange(this.minDate);
  168 +
  169 + this.$emit('on-pick', {minDate, maxDate}, false);
  170 + } else if (this.minDate && !this.maxDate) {
  171 + if (newDate >= this.minDate) {
  172 + const maxDate = new Date(newDate.getTime());
  173 + this.rangeState.selecting = false;
  174 +
  175 + this.$emit('on-pick', {minDate: this.minDate, maxDate});
  176 + } else {
206 const minDate = new Date(newDate.getTime()); 177 const minDate = new Date(newDate.getTime());
207 - const maxDate = null;  
208 - this.rangeState.selecting = true;  
209 - this.markRange(this.minDate);  
210 -  
211 - this.$emit('on-pick', {minDate, maxDate}, false);  
212 - } else if (this.minDate && !this.maxDate) {  
213 - if (newDate >= this.minDate) {  
214 - const maxDate = new Date(newDate.getTime());  
215 - this.rangeState.selecting = false;  
216 -  
217 - this.$emit('on-pick', {minDate: this.minDate, maxDate});  
218 - } else {  
219 - const minDate = new Date(newDate.getTime());  
220 -  
221 - this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false);  
222 - }  
223 - } else if (!this.minDate) {  
224 - const minDate = new Date(newDate.getTime());  
225 - this.rangeState.selecting = true;  
226 - this.markRange(this.minDate);  
227 178
228 this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false); 179 this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false);
229 } 180 }
230 - } else {  
231 - this.$emit('on-pick', newDate); 181 + } else if (!this.minDate) {
  182 + const minDate = new Date(newDate.getTime());
  183 + this.rangeState.selecting = true;
  184 + this.markRange(this.minDate);
  185 +
  186 + this.$emit('on-pick', {minDate, maxDate: this.maxDate}, false);
232 } 187 }
  188 + } else {
  189 + this.$emit('on-pick', newDate);
233 } 190 }
234 this.$emit('on-pick-click'); 191 this.$emit('on-pick-click');
235 }, 192 },
@@ -246,7 +203,7 @@ @@ -246,7 +203,7 @@
246 if (target.tagName === 'EM') { 203 if (target.tagName === 'EM') {
247 const cell = this.cells[parseInt(event.target.getAttribute('index'))]; 204 const cell = this.cells[parseInt(event.target.getAttribute('index'))];
248 // if (cell.disabled) return; // todo 待确定 205 // if (cell.disabled) return; // todo 待确定
249 - this.rangeState.endDate = this.getDateOfCell(cell); 206 + this.rangeState.endDate = cell.date;
250 } 207 }
251 }, 208 },
252 markRange (maxDate) { 209 markRange (maxDate) {
test/unit/specs/date-picker.spec.js
1 -import { createVue, destroyVM } from '../util'; 1 +import { createVue, destroyVM, stringToDate } from '../util';
2 2
3 describe('DatePicker.vue', () => { 3 describe('DatePicker.vue', () => {
4 let vm; 4 let vm;
@@ -25,4 +25,112 @@ describe(&#39;DatePicker.vue&#39;, () =&gt; { @@ -25,4 +25,112 @@ describe(&#39;DatePicker.vue&#39;, () =&gt; {
25 done(); 25 done();
26 }); 26 });
27 }); 27 });
  28 +
  29 + it('should create a DatePicker component of type="datetimerange"', done => {
  30 + vm = createVue(`
  31 + <Date-Picker type="datetimerange"></Date-Picker>
  32 + `);
  33 + const picker = vm.$children[0];
  34 + expect(picker.$children.length).to.equal(2);
  35 + expect(Array.isArray(picker.currentValue)).to.equal(true);
  36 + done();
  37 + });
  38 +
  39 + it('should create a datetimerange component and pick 2 dates in the current month', done => {
  40 + vm = createVue(`
  41 + <Date-picker type="datetimerange"></Date-picker>
  42 + `);
  43 +
  44 + const picker = vm.$children[0];
  45 + picker.handleIconClick();
  46 + vm.$nextTick(() => {
  47 + const displayField = vm.$el.querySelector('.ivu-input');
  48 + const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
  49 + const lastMonthClass = 'ivu-date-picker-cells-cell-prev-month';
  50 + const firstDayInMonthIndex = [...clickableCells].findIndex(cell => !cell.classList.contains(lastMonthClass));
  51 +
  52 + clickableCells[firstDayInMonthIndex].firstElementChild.click();
  53 + vm.$nextTick(() => {
  54 + clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
  55 + vm.$nextTick(() => {
  56 + const dayOne = new Date();
  57 + dayOne.setDate(1);
  58 + dayOne.setHours(0, 0, 0, 0);
  59 + const dayFive = new Date(dayOne.getTime());
  60 + dayFive.setDate(5);
  61 + dayFive.setHours(0, 0, 0, 0);
  62 +
  63 + // check pickers internal value
  64 + const [startInternalValue, endInternalValue] = picker.currentValue; // Date Objects
  65 + expect(Math.abs(dayOne - startInternalValue)).to.equal(0);
  66 + expect(Math.abs(dayFive - endInternalValue)).to.equal(0);
  67 +
  68 + // check pickers display value
  69 + const [startDisplayValue, endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
  70 + expect(Math.abs(dayOne - startDisplayValue)).to.equal(0);
  71 + expect(Math.abs(dayFive - endDisplayValue)).to.equal(0);
  72 +
  73 + done();
  74 + });
  75 + });
  76 + });
  77 + });
  78 +
  79 + it('should have same behavior after a reset as before the reset', done => {
  80 + vm = createVue(`
  81 + <Date-picker type="datetimerange"></Date-picker>
  82 + `);
  83 +
  84 + const picker = vm.$children[0];
  85 + picker.handleIconClick();
  86 + vm.$nextTick(() => {
  87 + const displayField = vm.$el.querySelector('.ivu-input');
  88 + const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
  89 + const lastMonthClass = 'ivu-date-picker-cells-cell-prev-month';
  90 + const firstDayInMonthIndex = [...clickableCells].findIndex(cell => !cell.classList.contains(lastMonthClass));
  91 +
  92 + // choose first date
  93 + clickableCells[firstDayInMonthIndex].firstElementChild.click();
  94 + vm.$nextTick(() => {
  95 + // choose second date
  96 + clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
  97 + vm.$nextTick(() => {
  98 + // cache first values
  99 + const [startInternalValue, endInternalValue] = picker.currentValue; // Date Objects
  100 + const [startDisplayValue, endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
  101 +
  102 + // clear picker
  103 + picker.handleClear();
  104 + vm.$nextTick(() => {
  105 + // it should be closed by now
  106 + expect(picker.visible).to.equal(false);
  107 + // open picker again
  108 + picker.handleIconClick();
  109 +
  110 + vm.$nextTick(() => {
  111 + expect(picker.visible).to.equal(true);
  112 + expect(JSON.stringify(picker.currentValue)).to.equal('[null,null]');
  113 + expect(displayField.value).to.equal('');
  114 +
  115 + clickableCells[firstDayInMonthIndex].firstElementChild.click();
  116 + vm.$nextTick(() => {
  117 + clickableCells[firstDayInMonthIndex + 4].firstElementChild.click();
  118 + vm.$nextTick(() => {
  119 + // recheck internal values
  120 + expect(Math.abs(picker.currentValue[0] - startInternalValue)).to.equal(0);
  121 + expect(Math.abs(picker.currentValue[1] - endInternalValue)).to.equal(0);
  122 + // recheck display value
  123 + const [_startDisplayValue, _endDisplayValue] = displayField.value.split(' - ').map(stringToDate); // Date Objects
  124 + expect(Math.abs(_startDisplayValue - startDisplayValue)).to.equal(0);
  125 + expect(Math.abs(_endDisplayValue - endDisplayValue)).to.equal(0);
  126 +
  127 + done();
  128 + });
  129 + });
  130 + });
  131 + });
  132 + });
  133 + });
  134 + });
  135 + });
28 }); 136 });
@@ -58,6 +58,16 @@ exports.createTest = function(Compo, propsData = {}, mounted = false) { @@ -58,6 +58,16 @@ exports.createTest = function(Compo, propsData = {}, mounted = false) {
58 }; 58 };
59 59
60 /** 60 /**
  61 + * Transform Date string (yyyy-mm-dd hh:mm:ss) to Date object
  62 + * @param {String}
  63 + */
  64 +exports.stringToDate = function(str) {
  65 + const parts = str.split(/[^\d]/).filter(Boolean);
  66 + parts[1] = parts[1] - 1;
  67 + return new Date(...parts);
  68 +};
  69 +
  70 +/**
61 * 触发一个事件 71 * 触发一个事件
62 * mouseenter, mouseleave, mouseover, keyup, change, click 等 72 * mouseenter, mouseleave, mouseover, keyup, change, click 等
63 * @param {Element} elm 73 * @param {Element} elm