import { CommonPicker } from '@present-ui/time-picker' import { mount } from '@vue/test-utils' import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' import { nextTick } from 'vue' import DatePicker from '../src/date-picker' const _mount = (template: string, data = () => ({}), otherObj?) => mount({ components: { 'ps-date-picker': DatePicker, }, template, data, ...otherObj, }, { attachTo: 'body', }) afterEach(() => { document.documentElement.innerHTML = '' }) describe('DatePicker', () => { it('create & custom class & style', async () => { const popperClassName = 'popper-class-test' const customClassName = 'custom-class-test' const wrapper = _mount(``, () => ({ popperClassName, customClassName })) const input = wrapper.find('input') expect(input.attributes('placeholder')).toBe('test_') expect(input.attributes('readonly')).not.toBeUndefined() const outterInput = wrapper.find('.ps-input') expect(outterInput.classes()).toContain(customClassName) expect(outterInput.attributes().style).toBeDefined() input.trigger('blur') input.trigger('focus') await nextTick() expect(document.querySelector('.ps-picker__popper').classList.contains(popperClassName)).toBe(true) }) it('select date', async () => { const wrapper = _mount(``, () => ({ value: '' })) const date = dayjs().locale('zh-cn') const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() const spans = document.querySelectorAll('.ps-date-picker__header-label') const arrowLeftElm = document.querySelector('.ps-date-picker__prev-btn.ps-icon-arrow-left') as HTMLElement const arrowRightElm = document.querySelector('.ps-date-picker__next-btn.ps-icon-arrow-right') as HTMLElement expect(spans[0].textContent).toContain(date.year()) expect(spans[1].textContent).toContain(date.format('M 月')) const arrowLeftYeayElm = document.querySelector('.ps-date-picker__prev-btn.ps-icon-d-arrow-left') as HTMLElement arrowLeftYeayElm.click() let count = 20 while (--count) { arrowLeftElm.click() } count = 20 while (--count) { arrowRightElm.click() } await nextTick() expect(spans[0].textContent).toContain(date.add(-1, 'year').year()) expect(spans[1].textContent).toContain(date.format('M 月')); (document.querySelector('td.available') as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value).toBeDefined() }) it('defaultTime and clear value', async () => { const wrapper = _mount(``, () => ({ value: '' })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick(); (document.querySelector('td.available') as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value).toBeDefined() expect(vm.value.getHours()).toBe(12) expect(vm.value.getMinutes()).toBe(0) expect(vm.value.getSeconds()).toBe(1) const picker = wrapper.findComponent(CommonPicker); (picker.vm as any).showClose = true await nextTick(); (document.querySelector('.ps-icon-circle-close') as HTMLElement).click() expect(vm.value).toBeNull() }) it('event change, focus, blur', async () => { const changeHandler = jest.fn() const focusHandler = jest.fn() const blurHandler = jest.fn() let onChangeValue const wrapper = _mount(``, () => ({ value: new Date(2016, 9, 10, 18, 40) }), { methods: { onChange(e) { onChangeValue = e return changeHandler(e) }, onFocus(e) { return focusHandler(e) }, onBlur(e) { return blurHandler(e) }, }, }) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() expect(focusHandler).toHaveBeenCalledTimes(1); (document.querySelector('td.available') as HTMLElement).click() await nextTick() expect(changeHandler).toHaveBeenCalledTimes(1) expect(blurHandler).toHaveBeenCalledTimes(1) expect(onChangeValue.getTime()).toBe(new Date(2016, 9, 1).getTime()) }) it('shortcuts', async () => { const text = 'Yesterday' const value = new Date(Date.now() - 86400000) value.setHours(0,0,0,0) const wrapper = _mount(``, () => ({ value: '', shortcuts: [{ text, value, }] })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() const shortcut = document.querySelector('.ps-picker-panel__shortcut') expect(shortcut.textContent).toBe(text) expect(document.querySelector('.ps-picker-panel__sidebar')).not.toBeNull(); (shortcut as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value.valueOf()).toBe(value.valueOf()) }) it('disabledDate', async () => { const wrapper = _mount(``, () => ({ value: '', disabledDate(time) { return time.getTime() < Date.now() - 8.64e7 } })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() expect(document.querySelector('.disabled')).not.toBeNull() }) }) describe('DatePicker Navigation', () => { let prevMonth, prevYear, nextMonth, nextYear, getYearLabel, getMonthLabel const initNavigationTest = async value => { const wrapper = _mount(``, () => ({ value })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() prevMonth = document.querySelector('button.ps-icon-arrow-left') prevYear = document.querySelector('button.ps-icon-d-arrow-left') nextMonth = document.querySelector('button.ps-icon-arrow-right') nextYear = document.querySelector('button.ps-icon-d-arrow-right') getYearLabel = () => document.querySelectorAll('.ps-date-picker__header-label')[0].textContent getMonthLabel = () => document.querySelectorAll('.ps-date-picker__header-label')[1].textContent } it('month, year', async() => { await initNavigationTest(new Date(2000, 0, 1)) expect(getYearLabel()).toContain('2000') expect(getMonthLabel()).toContain('1 月') prevMonth.click() await nextTick() expect(getYearLabel()).toContain('1999') expect(getMonthLabel()).toContain('12 月') prevYear.click() await nextTick() expect(getYearLabel()).toContain('1998') expect(getMonthLabel()).toContain('12 月') nextMonth.click() await nextTick() expect(getYearLabel()).toContain('1999') expect(getMonthLabel()).toContain('1 月') nextYear.click() await nextTick() expect(getYearLabel()).toContain('2000') expect(getMonthLabel()).toContain('1 月') }) it('month with fewer dates', async() => { // July has 31 days, June has 30 await initNavigationTest(new Date(2000, 6, 31)) prevMonth.click() await nextTick() expect(getYearLabel()).toContain('2000') expect(getMonthLabel()).toContain('6 月') }) it('year with fewer Feburary dates', async() => { // Feburary 2008 has 29 days, Feburary 2007 has 28 await initNavigationTest(new Date(2008, 1, 29)) prevYear.click() await nextTick() expect(getYearLabel()).toContain('2007') expect(getMonthLabel()).toContain('2 月') }) it('month label with fewer dates', async() => { await initNavigationTest(new Date(2000, 6, 31)) const yearLabel = document.querySelectorAll('.ps-date-picker__header-label')[0]; (yearLabel as HTMLElement).click() await nextTick() const year1999Label = document.querySelectorAll('.ps-year-table td a')[1]; (year1999Label as HTMLElement).click() await nextTick() const juneLabel = document.querySelectorAll('.ps-month-table td a')[5]; (juneLabel as HTMLElement).click() await nextTick() expect(getYearLabel()).toContain('2001') expect(getMonthLabel()).toContain('6 月') const monthLabel = document.querySelectorAll('.ps-date-picker__header-label')[1]; (monthLabel as HTMLElement).click() await nextTick() const janLabel = document.querySelectorAll('.ps-month-table td a')[0]; (janLabel as HTMLElement).click() await nextTick() expect(getYearLabel()).toContain('2001') expect(getMonthLabel()).toContain('1 月') }) }) describe('MonthPicker', () => { it('basic', async () => { const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 1) })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() expect((document.querySelector('.ps-month-table') as HTMLElement).style.display).toBe('') expect(document.querySelector('.ps-year-table')).toBeNull(); (document.querySelector('.ps-month-table a.cell') as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value.getMonth()).toBe(0) }) }) describe('YearPicker', () => { it('basic', async () => { const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 1) })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() expect((document.querySelector('.ps-year-table') as HTMLElement).style.display).toBe('') expect(document.querySelector('.ps-month-table')).toBeNull() const leftBtn = document.querySelector('.ps-icon-d-arrow-left') as HTMLElement const rightBtn = document.querySelector('.ps-icon-d-arrow-right') as HTMLElement let count = 2 while (--count) { leftBtn.click() } count = 3 while (--count) { rightBtn.click() } await nextTick(); (document.querySelector('.ps-year-table a.cell') as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value.getFullYear()).toBe(2030) }) }) describe('WeekPicker', () => { it('create', async () => { const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 15) })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() expect(document.querySelector('.is-week-mode')).not.toBeNull(); // select month still is in week-mode (document.querySelectorAll('.ps-date-picker__header-label')[1] as HTMLElement).click() await nextTick(); (document.querySelectorAll('.ps-month-table .cell')[7] as HTMLElement).click() await nextTick() expect(document.querySelector('.is-week-mode')).not.toBeNull() const numberOfHighlightRows = () => document.querySelectorAll('.ps-date-table__row.current').length; (document.querySelector('.ps-date-table__row ~ .ps-date-table__row td.available') as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value).not.toBeNull() input.trigger('blur') input.trigger('focus') await nextTick() expect(numberOfHighlightRows()).toBe(1); // test: next month should not have highlight (document.querySelector('.ps-icon-arrow-right') as HTMLElement).click() await nextTick() expect(numberOfHighlightRows()).toBe(0); // test: next year should not have highlight (document.querySelector('.ps-icon-arrow-left') as HTMLElement).click() await nextTick(); (document.querySelector('.ps-icon-d-arrow-right') as HTMLElement).click() await nextTick() expect(numberOfHighlightRows()).toBe(0) }) ;[ { locale: 'zh-cn', name: 'Monday', value: 1 }, { locale: 'en', name: 'Sunday', value: 0 }, ].forEach(loObj => { it(`emit first day of the week, ${loObj.locale} locale, ${loObj.name}`, async () => { dayjs.locale(loObj.locale) const wrapper = _mount(``, () => ({ value: '' })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick(); // click Wednesday (document.querySelectorAll('.ps-date-table__row ~ .ps-date-table__row td')[3] as HTMLElement).click() await nextTick() const vm = wrapper.vm as any expect(vm.value).not.toBeNull() expect(+dayjs(vm.value)).toBe(+dayjs(vm.value).startOf('week')) expect(dayjs(vm.value).day()).toBe(loObj.value) // Sunday or Monday }) }) }) describe('DatePicker dates', () => { it('create', async () => { const wrapper = _mount(``, () => ({ value: '' })) const input = wrapper.find('input') input.trigger('blur') input.trigger('focus') await nextTick() const td = (document.querySelectorAll('.ps-date-table__row .available') as NodeListOf) const vm = wrapper.vm as any td[0].click() await nextTick() expect(vm.value.length).toBe(1) td[1].click() await nextTick() expect(vm.value.length).toBe(2) expect(document.querySelectorAll('.ps-date-table__row .selected').length).toBe(2) td[0].click() await nextTick() expect(vm.value.length).toBe(1) td[1].click() await nextTick() expect(vm.value.length).toBe(0) }) }) describe('DateRangePicker', () => { it('create', async () => { const wrapper = _mount(``, () => ({ value: '' })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const panels = document.querySelectorAll('.ps-date-range-picker__content') expect(panels.length).toBe(2); (panels[0].querySelector('td.available') as HTMLElement).click() await nextTick(); (panels[1].querySelector('td.available') as HTMLElement).click() await nextTick() inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() // correct highlight const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') const inRangeDate = document.querySelectorAll('.in-range') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) expect(inRangeDate.length).toBeGreaterThan(28) // value is array const vm = wrapper.vm as any expect(Array.isArray(vm.value)).toBeTruthy() // input text is something like date string expect(inputs[0].element.value.length).toBe(10) expect(inputs[1].element.value.length).toBe(10) }) it('reverse selection', async () => { const wrapper = _mount(``, () => ({ value: '' })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const panels = document.querySelectorAll('.ps-date-range-picker__content'); (panels[1].querySelector('td.available') as HTMLElement).click() await nextTick(); (panels[0].querySelector('td.available') as HTMLElement).click() await nextTick() inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() // correct highlight const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') const inRangeDate = document.querySelectorAll('.in-range') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) expect(inRangeDate.length).toBeGreaterThan(28) const vm = wrapper.vm as any expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy() }) it('range, start-date and end-date', async () => { _mount(``, () => ({ value: '' })) const table = document.querySelector('.ps-date-table') const availableTds = (table as HTMLTableElement).querySelectorAll('td.available'); (availableTds[0] as HTMLElement).click() await nextTick(); (availableTds[1] as HTMLElement).click() await nextTick() expect(availableTds[0].classList.contains('in-range')).toBeTruthy() expect(availableTds[0].classList.contains('start-date')).toBeTruthy() expect(availableTds[1].classList.contains('in-range')).toBeTruthy() expect(availableTds[1].classList.contains('end-date')).toBeTruthy(); (availableTds[1] as HTMLElement).click() await nextTick(); (availableTds[0] as HTMLElement).click() await nextTick() expect(availableTds[0].classList.contains('in-range')).toBeTruthy() expect(availableTds[0].classList.contains('start-date')).toBeTruthy() expect(availableTds[1].classList.contains('in-range')).toBeTruthy() expect(availableTds[1].classList.contains('end-date')).toBeTruthy() const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') const inRangeDate = document.querySelectorAll('.in-range') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) expect(inRangeDate.length).toBe(2) }) it('unlink:true', async () => { const wrapper = _mount(``, () => ({ value: [new Date(2000, 9, 1), new Date(2000, 11, 2)] })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const panels = document.querySelectorAll('.ps-date-range-picker__content') const left = panels[0].querySelector('.ps-date-range-picker__header') const right = panels[1].querySelector('.is-right .ps-date-range-picker__header') expect(left.textContent).toBe('2000 年 10 月') expect(right.textContent).toBe('2000 年 12 月'); (panels[1].querySelector('.ps-icon-d-arrow-right') as HTMLElement).click() await nextTick(); (panels[1].querySelector('.ps-icon-arrow-right') as HTMLElement).click() await nextTick() expect(left.textContent).toBe('2000 年 10 月') expect(right.textContent).toBe('2002 年 1 月') }) it('daylight saving time highlight', async() => { // Run test with environment variable TZ=Australia/Sydney // The following test uses Australian Eastern Daylight Time (AEDT) // AEST -> AEDT shift happened on 2016-10-02 02:00:00 const wrapper = _mount(``, () => ({ value: [new Date(2016, 9, 1), new Date(2016, 9, 3)] })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) }) }) describe('MonthRange', () => { it('works', async () => { const wrapper = _mount(``, () => ({ value: '' })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const panels = document.querySelectorAll('.ps-date-range-picker__content') expect(panels.length).toBe(2) const p0 = panels[0].querySelector('td:not(.disabled)') p0.click() await nextTick() const p1 = (panels[1].querySelector('td:not(.disabled)')) p1.click() await nextTick() inputs[0].trigger('blur') inputs[0].trigger('focus') // correct highlight const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') const inRangeDate = document.querySelectorAll('.in-range') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) expect(inRangeDate.length).toBeGreaterThan(0) // value is array const vm = wrapper.vm as any expect(Array.isArray(vm.value)).toBeTruthy() // input text is something like date string expect(inputs[0].element.value.length).toBe(7) expect(inputs[1].element.value.length).toBe(7) // reverse selection p1.click() await nextTick() p0.click() await nextTick() expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy() }) it('range, start-date and end-date', async () => { _mount(``, () => ({ value: '' })) const table = document.querySelector('.ps-month-table') const tds = (table as HTMLTableElement).querySelectorAll('td'); (tds[0] as HTMLElement).click() await nextTick(); (tds[1] as HTMLElement).click() await nextTick() expect(tds[0].classList.contains('in-range')).toBeTruthy() expect(tds[0].classList.contains('start-date')).toBeTruthy() expect(tds[1].classList.contains('in-range')).toBeTruthy() expect(tds[1].classList.contains('end-date')).toBeTruthy(); (tds[1] as HTMLElement).click() await nextTick(); (tds[0] as HTMLElement).click() await nextTick() expect(tds[0].classList.contains('in-range')).toBeTruthy() expect(tds[0].classList.contains('start-date')).toBeTruthy() expect(tds[1].classList.contains('in-range')).toBeTruthy() expect(tds[1].classList.contains('end-date')).toBeTruthy() const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') const inRangeDate = document.querySelectorAll('.in-range') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) expect(inRangeDate.length).toBe(2) }) it('type:monthrange unlink:true', async () => { const wrapper = _mount(``, () => ({ value: [new Date(2000, 9), new Date(2002, 11)] })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const panels = document.querySelectorAll('.ps-date-range-picker__content') const left = panels[0].querySelector('.ps-date-range-picker__header') const right = panels[1].querySelector('.is-right .ps-date-range-picker__header') expect(left.textContent).toContain(2000) expect(right.textContent).toContain(2002); (panels[1].querySelector('.ps-icon-d-arrow-right') as HTMLElement).click() await nextTick() expect(left.textContent).toContain(2000) expect(right.textContent).toContain(2003) }) it('daylight saving time highlight', async () => { const wrapper = _mount(``, () => ({ value: [new Date(2016, 6), new Date(2016, 12)] })) const inputs = wrapper.findAll('input') inputs[0].trigger('blur') inputs[0].trigger('focus') await nextTick() const startDate = document.querySelectorAll('.start-date') const endDate = document.querySelectorAll('.end-date') expect(startDate.length).toBe(1) expect(endDate.length).toBe(1) }) })