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)
})
})