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 1 <template>
2 2 <div
3 3 :class="classes"
4   - @click="handleClick"
5 4 @mousemove="handleMouseMove">
6 5 <div :class="[prefixCls + '-header']">
7 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 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 9 </div>
11 10 </template>
12 11 <script>
... ... @@ -106,6 +105,7 @@
106 105 const cell_tmpl = {
107 106 text: '',
108 107 type: '',
  108 + date: null,
109 109 selected: false,
110 110 disabled: false,
111 111 range: false,
... ... @@ -117,14 +117,8 @@
117 117 const cell = deepCopy(cell_tmpl);
118 118 cell.type = 'prev-month';
119 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 122 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
129 123 cells.push(cell);
130 124 }
... ... @@ -132,9 +126,10 @@
132 126  
133 127 for (let i = 1; i <= dateCountOfMonth; i++) {
134 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 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 133 cell.selected = time === selectDay;
139 134 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
140 135 cell.range = time >= minDay && time <= maxDay;
... ... @@ -149,14 +144,8 @@
149 144 const cell = deepCopy(cell_tmpl);
150 145 cell.type = 'next-month';
151 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 149 cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
161 150 cells.push(cell);
162 151 }
... ... @@ -165,71 +154,39 @@
165 154 }
166 155 },
167 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 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 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 191 this.$emit('on-pick-click');
235 192 },
... ... @@ -246,7 +203,7 @@
246 203 if (target.tagName === 'EM') {
247 204 const cell = this.cells[parseInt(event.target.getAttribute('index'))];
248 205 // if (cell.disabled) return; // todo 待确定
249   - this.rangeState.endDate = this.getDateOfCell(cell);
  206 + this.rangeState.endDate = cell.date;
250 207 }
251 208 },
252 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 3 describe('DatePicker.vue', () => {
4 4 let vm;
... ... @@ -25,4 +25,112 @@ describe(&#39;DatePicker.vue&#39;, () =&gt; {
25 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 });
... ...
test/unit/util.js
... ... @@ -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 72 * mouseenter, mouseleave, mouseover, keyup, change, click 等
63 73 * @param {Element} elm
... ...