date-picker.test.ts 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. // @ts-nocheck
  2. import { nextTick } from 'vue'
  3. import { mount } from '@vue/test-utils'
  4. import { afterEach, describe, expect, it, vi } from 'vitest'
  5. import dayjs from 'dayjs'
  6. import { rAF } from '@element-plus/test-utils/tick'
  7. import ConfigProvider from '@element-plus/components/config-provider'
  8. import { CommonPicker } from '@element-plus/components/time-picker'
  9. import Input from '@element-plus/components/input'
  10. import zhCn from '@element-plus/locale/lang/zh-cn'
  11. import enUs from '@element-plus/locale/lang/en'
  12. import 'dayjs/locale/zh-cn'
  13. import { EVENT_CODE } from '@element-plus/constants'
  14. import { ElFormItem } from '@element-plus/components/form'
  15. import DatePicker from '../src/date-picker'
  16. const _mount = (template: string, data = () => ({}), otherObj?) =>
  17. mount(
  18. {
  19. components: {
  20. 'el-date-picker': DatePicker,
  21. 'el-form-item': ElFormItem,
  22. },
  23. template,
  24. data,
  25. ...otherObj,
  26. },
  27. {
  28. attachTo: 'body',
  29. }
  30. )
  31. afterEach(() => {
  32. document.documentElement.innerHTML = ''
  33. })
  34. const testDatePickerPanelChange = async (type: 'date' | 'daterange') => {
  35. let mode
  36. const wrapper = _mount(
  37. `<el-date-picker
  38. type="${type}"
  39. v-model="value"
  40. @panel-change="onPanelChange"
  41. />`,
  42. () => ({ value: type === 'daterange' ? [] : '' }),
  43. {
  44. methods: {
  45. onPanelChange(value, _mode) {
  46. mode = _mode
  47. },
  48. },
  49. }
  50. )
  51. const reset = () => {
  52. mode = undefined
  53. }
  54. const input = wrapper.find('input')
  55. input.trigger('blur')
  56. input.trigger('focus')
  57. await nextTick()
  58. const prevMonth = document.querySelector<HTMLElement>('button.arrow-left')
  59. const prevYear = document.querySelector<HTMLElement>('button.d-arrow-left')
  60. const nextMonth = document.querySelector<HTMLElement>('button.arrow-right')
  61. const nextYear = document.querySelector<HTMLElement>('button.d-arrow-right')
  62. prevMonth.click()
  63. await nextTick()
  64. expect(mode).toBe('month')
  65. reset()
  66. nextMonth.click()
  67. await nextTick()
  68. expect(mode).toBe('month')
  69. reset()
  70. prevYear.click()
  71. await nextTick()
  72. expect(mode).toBe('year')
  73. reset()
  74. nextYear.click()
  75. await nextTick()
  76. expect(mode).toBe('year')
  77. }
  78. describe('DatePicker', () => {
  79. it('create & custom class & style', async () => {
  80. const popperClassName = 'popper-class-test'
  81. const customClassName = 'custom-class-test'
  82. const wrapper = _mount(
  83. `<el-date-picker
  84. :readonly="true"
  85. placeholder='test_'
  86. format='HH-mm-ss'
  87. :style="{color:'red'}"
  88. :class="customClassName"
  89. :popperClass="popperClassName"
  90. />`,
  91. () => ({ popperClassName, customClassName })
  92. )
  93. const input = wrapper.find('input')
  94. expect(input.attributes('placeholder')).toBe('test_')
  95. expect(input.attributes('readonly')).not.toBeUndefined()
  96. const outterInput = wrapper.find('.el-input')
  97. expect(outterInput.classes()).toContain(customClassName)
  98. expect(outterInput.attributes().style).toBeDefined()
  99. input.trigger('blur')
  100. input.trigger('focus')
  101. await nextTick()
  102. expect(
  103. document
  104. .querySelector('.el-picker__popper')
  105. .classList.contains(popperClassName)
  106. ).toBe(true)
  107. })
  108. it('select date', async () => {
  109. const wrapper = _mount(
  110. `<el-date-picker
  111. v-model="value"
  112. />`,
  113. () => ({ value: '' })
  114. )
  115. const date = dayjs()
  116. const input = wrapper.find('input')
  117. input.trigger('blur')
  118. input.trigger('focus')
  119. await nextTick()
  120. const spans = document.querySelectorAll('.el-date-picker__header-label')
  121. const arrowLeftElm = document.querySelector(
  122. '.el-date-picker__prev-btn .arrow-left'
  123. ) as HTMLElement
  124. const arrowRightElm = document.querySelector(
  125. '.el-date-picker__next-btn .arrow-right'
  126. ) as HTMLElement
  127. expect(spans[0].textContent).toContain(date.year())
  128. expect(spans[1].textContent).toContain(date.format('MMMM'))
  129. const arrowLeftYeayElm = document.querySelector(
  130. '.el-date-picker__prev-btn .d-arrow-left'
  131. ) as HTMLElement
  132. arrowLeftYeayElm.click()
  133. let count = 20
  134. while (--count) {
  135. arrowLeftElm.click()
  136. }
  137. count = 20
  138. while (--count) {
  139. arrowRightElm.click()
  140. }
  141. await nextTick()
  142. expect(spans[0].textContent).toContain(date.add(-1, 'year').year())
  143. expect(spans[1].textContent).toContain(date.format('MMMM'))
  144. ;(document.querySelector('td.available') as HTMLElement).click()
  145. await nextTick()
  146. const vm = wrapper.vm as any
  147. expect(vm.value).toBeDefined()
  148. })
  149. it('defaultTime and clear value', async () => {
  150. const wrapper = _mount(
  151. `<el-date-picker
  152. v-model="value"
  153. :default-time="new Date(2011,1,1,12,0,1)"
  154. />`,
  155. () => ({ value: '' })
  156. )
  157. const input = wrapper.find('input')
  158. input.trigger('blur')
  159. input.trigger('focus')
  160. await nextTick()
  161. ;(document.querySelector('td.available') as HTMLElement).click()
  162. await nextTick()
  163. const vm = wrapper.vm as any
  164. expect(vm.value).toBeDefined()
  165. expect(vm.value.getHours()).toBe(12)
  166. expect(vm.value.getMinutes()).toBe(0)
  167. expect(vm.value.getSeconds()).toBe(1)
  168. const picker = wrapper.findComponent(CommonPicker)
  169. ;(picker.vm as any).showClose = true
  170. await nextTick()
  171. ;(document.querySelector('.clear-icon') as HTMLElement).click()
  172. expect(vm.value).toBeNull()
  173. })
  174. it('defaultValue', async () => {
  175. const wrapper = _mount(
  176. `<el-date-picker
  177. v-model="value"
  178. :default-value="defaultValue"
  179. />`,
  180. () => ({
  181. value: '',
  182. defaultValue: new Date(2011, 10, 1),
  183. })
  184. )
  185. const input = wrapper.find('input')
  186. input.trigger('blur')
  187. input.trigger('focus')
  188. await nextTick()
  189. document.querySelector<HTMLElement>('td.available').click()
  190. await nextTick()
  191. const vm = wrapper.vm as any
  192. expect(vm.value).toBeDefined()
  193. expect(vm.value.getFullYear()).toBe(2011)
  194. expect(vm.value.getMonth()).toBe(10)
  195. expect(vm.value.getDate()).toBe(1)
  196. const picker = wrapper.findComponent(CommonPicker)
  197. ;(picker.vm as any).showClose = true
  198. await nextTick()
  199. document.querySelector<HTMLElement>('.clear-icon').click()
  200. expect(vm.value).toBeNull()
  201. vm.defaultValue = new Date(2031, 5, 1)
  202. input.trigger('blur')
  203. input.trigger('focus')
  204. await nextTick()
  205. document.querySelector<HTMLElement>('td.available').click()
  206. await nextTick()
  207. expect(vm.value).toBeDefined()
  208. expect(vm.value.getFullYear()).toBe(2031)
  209. expect(vm.value.getMonth()).toBe(5)
  210. expect(vm.value.getDate()).toBe(1)
  211. })
  212. it('event change, focus, blur, keydown', async () => {
  213. const changeHandler = vi.fn()
  214. const focusHandler = vi.fn()
  215. const blurHandler = vi.fn()
  216. const keydownHandler = vi.fn()
  217. let onChangeValue: Date | undefined
  218. const wrapper = _mount(
  219. `<el-date-picker
  220. v-model="value"
  221. @change="onChange"
  222. @focus="onFocus"
  223. @blur="onBlur"
  224. @keydown="onKeydown"
  225. />`,
  226. () => ({ value: new Date(2016, 9, 10, 18, 40) }),
  227. {
  228. methods: {
  229. onChange(e) {
  230. onChangeValue = e
  231. return changeHandler(e)
  232. },
  233. onFocus(e) {
  234. return focusHandler(e)
  235. },
  236. onBlur(e) {
  237. return blurHandler(e)
  238. },
  239. onKeydown(e) {
  240. return keydownHandler(e)
  241. },
  242. },
  243. }
  244. )
  245. const input = wrapper.find('input')
  246. input.trigger('focus')
  247. input.trigger('blur')
  248. input.trigger('keydown')
  249. await nextTick()
  250. await rAF()
  251. expect(focusHandler).toHaveBeenCalledTimes(1)
  252. expect(blurHandler).toHaveBeenCalledTimes(1)
  253. expect(keydownHandler).toHaveBeenCalledTimes(1)
  254. input.trigger('focus')
  255. await nextTick()
  256. ;(document.querySelector('td.available') as HTMLElement).click()
  257. await nextTick()
  258. await rAF()
  259. expect(changeHandler).toHaveBeenCalledTimes(1)
  260. expect(onChangeValue?.getTime()).toBe(new Date(2016, 9, 1).getTime())
  261. })
  262. it('emits focus on click when not currently focused', async () => {
  263. const focusHandler = vi.fn()
  264. const wrapper = _mount(
  265. `<el-date-picker
  266. v-model="value"
  267. @focus="onFocus"
  268. />`,
  269. () => ({ value: new Date(2016, 9, 10, 18, 40) }),
  270. {
  271. methods: {
  272. onFocus(e: Event) {
  273. return focusHandler(e)
  274. },
  275. },
  276. }
  277. )
  278. const input = wrapper.find('input')
  279. input.trigger('mousedown')
  280. input.trigger('focus')
  281. await nextTick()
  282. await rAF()
  283. expect(focusHandler).toHaveBeenCalledTimes(1)
  284. })
  285. it('opens popper on click when input is focused', async () => {
  286. const wrapper = _mount(`<el-date-picker v-model="value" />`, () => ({
  287. value: new Date(2016, 9, 10, 18, 40),
  288. }))
  289. const popperEl = document.querySelector('.el-picker__popper') as HTMLElement
  290. expect(popperEl.style.display).toBe('none')
  291. const input = wrapper.find('input')
  292. input.element.focus()
  293. input.trigger('mousedown')
  294. await nextTick()
  295. await rAF()
  296. expect(popperEl.style.display).not.toBe('none')
  297. })
  298. it('shortcuts', async () => {
  299. const text = 'Yesterday'
  300. const value = new Date(Date.now() - 86400000)
  301. value.setHours(0, 0, 0, 0)
  302. const wrapper = _mount(
  303. `<el-date-picker
  304. v-model="value"
  305. :shortcuts="shortcuts"
  306. />`,
  307. () => ({
  308. value: '',
  309. shortcuts: [
  310. {
  311. text,
  312. value,
  313. },
  314. ],
  315. })
  316. )
  317. const input = wrapper.find('input')
  318. input.trigger('blur')
  319. input.trigger('focus')
  320. await nextTick()
  321. const shortcut = document.querySelector('.el-picker-panel__shortcut')
  322. expect(shortcut.textContent).toBe(text)
  323. expect(document.querySelector('.el-picker-panel__sidebar')).not.toBeNull()
  324. ;(shortcut as HTMLElement).click()
  325. await nextTick()
  326. const vm = wrapper.vm as any
  327. expect(vm.value.valueOf()).toBe(value.valueOf())
  328. })
  329. it('disabledDate', async () => {
  330. const wrapper = _mount(
  331. `<el-date-picker
  332. v-model="value"
  333. :disabledDate="disabledDate"
  334. />`,
  335. () => ({
  336. value: '',
  337. disabledDate(time) {
  338. return time.getTime() < Date.now() - 8.64e7
  339. },
  340. })
  341. )
  342. const input = wrapper.find('input')
  343. input.trigger('blur')
  344. input.trigger('focus')
  345. await nextTick()
  346. expect(document.querySelector('.disabled')).not.toBeNull()
  347. })
  348. it('ref focus', async () => {
  349. _mount(
  350. `<el-date-picker
  351. v-model="value"
  352. ref="input"
  353. />`,
  354. () => ({ value: '' }),
  355. {
  356. mounted() {
  357. this.$refs.input.focus()
  358. },
  359. }
  360. )
  361. await nextTick()
  362. await rAF()
  363. const popperEl = document.querySelector('.el-picker__popper')
  364. const attr = popperEl.getAttribute('aria-hidden')
  365. expect(attr).toEqual('false')
  366. })
  367. it('ref handleOpen', async () => {
  368. _mount(
  369. `<el-date-picker
  370. v-model="value"
  371. ref="input"
  372. />`,
  373. () => ({ value: '' }),
  374. {
  375. mounted() {
  376. this.$refs.input.handleOpen()
  377. },
  378. }
  379. )
  380. await nextTick()
  381. const popperEl = document.querySelector('.el-picker__popper')
  382. const attr = popperEl.getAttribute('aria-hidden')
  383. expect(attr).toEqual('false')
  384. })
  385. it('ref handleClose', async () => {
  386. vi.useFakeTimers()
  387. _mount(
  388. `<el-date-picker
  389. v-model="value"
  390. ref="input"
  391. />`,
  392. () => ({ value: '' }),
  393. {
  394. mounted() {
  395. this.$refs.input.handleOpen()
  396. setTimeout(() => {
  397. this.$refs.input.handleClose()
  398. }, 1000000)
  399. },
  400. }
  401. )
  402. vi.runAllTimers()
  403. await nextTick()
  404. const popperEl = document.querySelector('.el-picker__popper')
  405. const attr = popperEl.getAttribute('aria-hidden')
  406. expect(attr).toEqual('true')
  407. vi.useRealTimers()
  408. })
  409. it('custom content', async () => {
  410. const wrapper = _mount(
  411. `<el-date-picker
  412. v-model="value"
  413. ref="input">
  414. <template #default="{ isCurrent, text }">
  415. <div class="cell" :class="{ current: isCurrent }">
  416. <div>{{ text }}</div>
  417. </div>
  418. </template>
  419. </el-date-picker>`,
  420. () => ({ value: '' }),
  421. {
  422. mounted() {
  423. this.$refs.input.focus()
  424. },
  425. }
  426. )
  427. await nextTick()
  428. const input = wrapper.find('input')
  429. input.trigger('blur')
  430. input.trigger('focus')
  431. await nextTick()
  432. {
  433. ;(document.querySelector('td.available .cell') as HTMLElement).click()
  434. }
  435. input.trigger('focus')
  436. await nextTick()
  437. expect(
  438. document.querySelector('td.available .cell').classList.contains('current')
  439. ).toBeTruthy()
  440. })
  441. it('custom content comment', async () => {
  442. _mount(
  443. `<el-date-picker
  444. v-model="value"
  445. ref="input">
  446. <template #default="{ isCurrent, text }">
  447. <!-- <div class="cell" :class="{ current: isCurrent }">
  448. <div>{{ text + "csw" }}</div>
  449. </div> -->
  450. </template>
  451. </el-date-picker>`,
  452. () => ({ value: '' }),
  453. {
  454. mounted() {
  455. this.$refs.input.focus()
  456. },
  457. }
  458. )
  459. await nextTick()
  460. const el = document.querySelector('td.available .el-date-table-cell')
  461. const text = el.textContent
  462. expect(text.includes('csw')).toBeFalsy()
  463. })
  464. it('custom content value validate', async () => {
  465. _mount(
  466. `<el-date-picker
  467. v-model="value"
  468. ref="input">
  469. <template #default="{ isCurrent, text }">
  470. <div class="cell" :class="{ current: isCurrent }">
  471. <div>{{ text + "csw" }}</div>
  472. </div>
  473. </template>
  474. </el-date-picker>`,
  475. () => ({ value: '' }),
  476. {
  477. mounted() {
  478. this.$refs.input.focus()
  479. },
  480. }
  481. )
  482. await nextTick()
  483. const el = document.querySelector('td.available .cell')
  484. const text = el.textContent
  485. expect(text.includes('csw')).toBeTruthy()
  486. })
  487. it('custom content bail out slot compoent', async () => {
  488. _mount(
  489. `<el-date-picker
  490. v-model="value"
  491. ref="input">
  492. <slot name="testest"></slot>
  493. </el-date-picker>`,
  494. () => ({ value: '' }),
  495. {
  496. mounted() {
  497. this.$refs.input.focus()
  498. },
  499. }
  500. )
  501. await nextTick()
  502. const el = document.querySelector<HTMLElement>('td.available')
  503. const text = el.textContent
  504. expect(!!text).toBeTruthy()
  505. })
  506. describe('value-format', () => {
  507. it('with literal string', async () => {
  508. const day = dayjs()
  509. const format = 'YYYY-MM-DD'
  510. const valueFormat = '[Element-Plus] DD/MM YYYY'
  511. const value = day.format(valueFormat)
  512. const wrapper = _mount(
  513. `
  514. <el-date-picker
  515. ref="compo"
  516. v-model="value"
  517. type="date"
  518. format="${format}"
  519. value-format="${valueFormat}" />
  520. <button @click="changeValue">click</button>
  521. `,
  522. () => {
  523. return {
  524. value,
  525. }
  526. },
  527. {
  528. methods: {
  529. changeValue() {
  530. this.value = '[Element-Plus] 31/05 2021'
  531. },
  532. },
  533. }
  534. )
  535. const vm = wrapper.vm as any
  536. const input = wrapper.find('input')
  537. await input.trigger('blur')
  538. await input.trigger('focus')
  539. await nextTick()
  540. {
  541. ;(document.querySelector('td.available') as HTMLElement).click()
  542. }
  543. await nextTick()
  544. expect(vm.value).toBe(
  545. dayjs(
  546. `[Element-Plus] 01/${`0${day.month() + 1}`.slice(-2)} ${day.year()}`,
  547. valueFormat
  548. ).format(valueFormat)
  549. )
  550. await wrapper.find('button').trigger('click')
  551. await nextTick()
  552. expect(wrapper.findComponent(Input).vm.modelValue).toBe('2021-05-31')
  553. })
  554. it('with "x"', async () => {
  555. const format = 'YYYY/MM/DD'
  556. const dateStr = '2021/05/31'
  557. const valueFormat = 'x'
  558. const value = Date.now()
  559. const wrapper = _mount(
  560. `
  561. <el-date-picker
  562. ref="compo"
  563. v-model="value"
  564. type="date"
  565. format="${format}"
  566. value-format="${valueFormat}" />
  567. <button @click="changeValue">click</button>
  568. `,
  569. () => {
  570. return {
  571. value,
  572. }
  573. },
  574. {
  575. methods: {
  576. changeValue() {
  577. this.value = +new Date(dateStr)
  578. },
  579. },
  580. }
  581. )
  582. const vm = wrapper.vm as any
  583. const input = wrapper.find('input')
  584. await input.trigger('blur')
  585. await input.trigger('focus')
  586. await nextTick()
  587. ;(document.querySelector('td.available') as HTMLElement).click()
  588. await nextTick()
  589. expect(vm.value).toBe(+dayjs().startOf('M'))
  590. await wrapper.find('button').trigger('click')
  591. await nextTick()
  592. expect(wrapper.findComponent(Input).vm.modelValue).toBe(dateStr)
  593. })
  594. })
  595. })
  596. describe('DatePicker Navigation', () => {
  597. let prevMonth, prevYear, nextMonth, nextYear, getYearLabel, getMonthLabel
  598. const initNavigationTest = async (value) => {
  599. const wrapper = _mount(
  600. `<el-date-picker
  601. v-model="value"
  602. />`,
  603. () => ({ value })
  604. )
  605. const input = wrapper.find('input')
  606. input.trigger('blur')
  607. input.trigger('focus')
  608. await nextTick()
  609. prevMonth = document.querySelector('button.arrow-left')
  610. prevYear = document.querySelector('button.d-arrow-left')
  611. nextMonth = document.querySelector('button.arrow-right')
  612. nextYear = document.querySelector('button.d-arrow-right')
  613. getYearLabel = () =>
  614. document.querySelectorAll('.el-date-picker__header-label')[0].textContent
  615. getMonthLabel = () =>
  616. document.querySelectorAll('.el-date-picker__header-label')[1].textContent
  617. }
  618. it('month, year', async () => {
  619. await initNavigationTest(new Date(2000, 0, 1))
  620. expect(getYearLabel()).toContain('2000')
  621. expect(getMonthLabel()).toContain('January')
  622. prevMonth.click()
  623. await nextTick()
  624. expect(getYearLabel()).toContain('1999')
  625. expect(getMonthLabel()).toContain('December')
  626. prevYear.click()
  627. await nextTick()
  628. expect(getYearLabel()).toContain('1998')
  629. expect(getMonthLabel()).toContain('December')
  630. nextMonth.click()
  631. await nextTick()
  632. expect(getYearLabel()).toContain('1999')
  633. expect(getMonthLabel()).toContain('January')
  634. nextYear.click()
  635. await nextTick()
  636. expect(getYearLabel()).toContain('2000')
  637. expect(getMonthLabel()).toContain('January')
  638. })
  639. it('month with fewer dates', async () => {
  640. // July has 31 days, June has 30
  641. await initNavigationTest(new Date(2000, 6, 31))
  642. prevMonth.click()
  643. await nextTick()
  644. expect(getYearLabel()).toContain('2000')
  645. expect(getMonthLabel()).toContain('June')
  646. })
  647. it('year with fewer Feburary dates', async () => {
  648. // Feburary 2008 has 29 days, Feburary 2007 has 28
  649. await initNavigationTest(new Date(2008, 1, 29))
  650. prevYear.click()
  651. await nextTick()
  652. expect(getYearLabel()).toContain('2007')
  653. expect(getMonthLabel()).toContain('February')
  654. })
  655. it('month label with fewer dates', async () => {
  656. await initNavigationTest(new Date(2000, 6, 31))
  657. const yearLabel = document.querySelectorAll(
  658. '.el-date-picker__header-label'
  659. )[0]
  660. ;(yearLabel as HTMLElement).click()
  661. await nextTick()
  662. const year1999Label = document.querySelectorAll('.el-year-table td')[1]
  663. ;(year1999Label as HTMLElement).click()
  664. await nextTick()
  665. const juneLabel = document.querySelectorAll('.el-month-table td')[5]
  666. ;(juneLabel as HTMLElement).click()
  667. await nextTick()
  668. expect(getYearLabel()).toContain('2001')
  669. expect(getMonthLabel()).toContain('June')
  670. const monthLabel = document.querySelectorAll(
  671. '.el-date-picker__header-label'
  672. )[1]
  673. ;(monthLabel as HTMLElement).click()
  674. await nextTick()
  675. const janLabel = document.querySelectorAll('.el-month-table td')[0]
  676. ;(janLabel as HTMLElement).click()
  677. await nextTick()
  678. expect(getYearLabel()).toContain('2001')
  679. expect(getMonthLabel()).toContain('January')
  680. })
  681. it('panel change event', async () => {
  682. await testDatePickerPanelChange('date')
  683. })
  684. })
  685. describe('MonthPicker', () => {
  686. it('basic', async () => {
  687. const wrapper = _mount(
  688. `<el-date-picker
  689. type='month'
  690. v-model="value"
  691. />`,
  692. () => ({ value: new Date(2020, 7, 1) })
  693. )
  694. const input = wrapper.find('input')
  695. input.trigger('blur')
  696. input.trigger('focus')
  697. await nextTick()
  698. expect(
  699. (document.querySelector('.el-month-table') as HTMLElement).style.display
  700. ).toBe('')
  701. expect(document.querySelector('.el-year-table')).toBeNull()
  702. ;(document.querySelector('.el-month-table .cell') as HTMLElement).click()
  703. await nextTick()
  704. const vm = wrapper.vm as any
  705. expect(vm.value.getMonth()).toBe(0)
  706. })
  707. it('value-format', async () => {
  708. const valueFormat = '[Element-Plus] YYYY.MM'
  709. const wrapper = _mount(
  710. `
  711. <el-date-picker
  712. type="month"
  713. v-model="value"
  714. value-format="${valueFormat}"
  715. ></el-date-picker>
  716. `,
  717. () => ({ value: dayjs(new Date(2020, 7, 1)).format(valueFormat) })
  718. )
  719. await nextTick()
  720. expect(wrapper.findComponent(Input).vm.modelValue).toBe('2020-08')
  721. const input = wrapper.find('input')
  722. input.trigger('blur')
  723. input.trigger('focus')
  724. await nextTick()
  725. {
  726. ;(document.querySelector('.el-month-table .cell') as HTMLElement).click()
  727. }
  728. await nextTick()
  729. expect(wrapper.findComponent(Input).vm.modelValue).toBe('2020-01')
  730. expect((wrapper.vm as any).value).toBe(
  731. dayjs(new Date(2020, 0, 1)).format(valueFormat)
  732. )
  733. })
  734. })
  735. describe('YearPicker', () => {
  736. it('basic', async () => {
  737. const wrapper = _mount(
  738. `<el-date-picker
  739. type='year'
  740. v-model="value"
  741. />`,
  742. () => ({ value: new Date(2020, 7, 1) })
  743. )
  744. const input = wrapper.find('input')
  745. input.trigger('blur')
  746. input.trigger('focus')
  747. await nextTick()
  748. expect(
  749. (document.querySelector('.el-year-table') as HTMLElement).style.display
  750. ).toBe('')
  751. expect(document.querySelector('.el-month-table')).toBeNull()
  752. const leftBtn = document.querySelector('.d-arrow-left') as HTMLElement
  753. const rightBtn = document.querySelector('.d-arrow-right') as HTMLElement
  754. let count = 2
  755. while (--count) {
  756. leftBtn.click()
  757. }
  758. count = 3
  759. while (--count) {
  760. rightBtn.click()
  761. }
  762. await nextTick()
  763. ;(document.querySelector('.el-year-table .cell') as HTMLElement).click()
  764. await nextTick()
  765. const vm = wrapper.vm as any
  766. expect(vm.value.getFullYear()).toBe(2030)
  767. })
  768. it('value-format', async () => {
  769. const valueFormat = '[Element-Plus] YYYY'
  770. const wrapper = _mount(
  771. `
  772. <el-date-picker
  773. type="year"
  774. v-model="value"
  775. value-format="${valueFormat}"
  776. ></el-date-picker>
  777. `,
  778. () => ({ value: dayjs(new Date(2005, 7, 1)).format(valueFormat) })
  779. )
  780. await nextTick()
  781. expect(wrapper.findComponent(Input).vm.modelValue).toBe('2005')
  782. const input = wrapper.find('input')
  783. input.trigger('blur')
  784. input.trigger('focus')
  785. await nextTick()
  786. const cell = document.querySelector('.el-year-table .cell') as HTMLElement
  787. cell.click()
  788. await nextTick()
  789. expect((wrapper.vm as any).value).toBe(
  790. dayjs(new Date(Number.parseInt(cell.innerHTML.trim()), 0, 1)).format(
  791. valueFormat
  792. )
  793. )
  794. })
  795. })
  796. describe('WeekPicker', () => {
  797. it('create', async () => {
  798. const wrapper = _mount(
  799. `<el-date-picker
  800. type='week'
  801. v-model="value"
  802. />`,
  803. () => ({ value: new Date(2020, 7, 15) })
  804. )
  805. const input = wrapper.find('input')
  806. input.trigger('blur')
  807. input.trigger('focus')
  808. await nextTick()
  809. expect(document.querySelector('.is-week-mode')).not.toBeNull()
  810. // select month still is in week-mode
  811. ;(
  812. document.querySelectorAll(
  813. '.el-date-picker__header-label'
  814. )[1] as HTMLElement
  815. ).click()
  816. await nextTick()
  817. ;(
  818. document.querySelectorAll('.el-month-table .cell')[7] as HTMLElement
  819. ).click()
  820. await nextTick()
  821. expect(document.querySelector('.is-week-mode')).not.toBeNull()
  822. const numberOfHighlightRows = () =>
  823. document.querySelectorAll('.el-date-table__row.current').length
  824. ;(
  825. document.querySelector(
  826. '.el-date-table__row ~ .el-date-table__row td.available'
  827. ) as HTMLElement
  828. ).click()
  829. await nextTick()
  830. const vm = wrapper.vm as any
  831. expect(vm.value).not.toBeNull()
  832. input.trigger('blur')
  833. input.trigger('focus')
  834. await nextTick()
  835. expect(numberOfHighlightRows()).toBe(1)
  836. // test: next month should not have highlight
  837. ;(document.querySelector('.arrow-right') as HTMLElement).click()
  838. await nextTick()
  839. expect(numberOfHighlightRows()).toBe(0)
  840. // test: next year should not have highlight
  841. ;(document.querySelector('.arrow-left') as HTMLElement).click()
  842. await nextTick()
  843. ;(document.querySelector('.d-arrow-right') as HTMLElement).click()
  844. await nextTick()
  845. expect(numberOfHighlightRows()).toBe(0)
  846. })
  847. ;[
  848. { locale: enUs, name: 'Sunday', value: 0 },
  849. { locale: zhCn, name: 'Monday', value: 1 },
  850. ].forEach((loObj) => {
  851. it(`emit first day of the week, ${loObj.locale.name} locale, ${loObj.name}`, async () => {
  852. const wrapper = mount(
  853. {
  854. components: {
  855. 'el-date-picker': DatePicker,
  856. 'el-config-provider': ConfigProvider,
  857. },
  858. template: `
  859. <el-config-provider :locale="locale">
  860. <el-date-picker
  861. type='week'
  862. v-model="value"
  863. />
  864. </el-config-provider>
  865. `,
  866. data() {
  867. return {
  868. locale: loObj.locale,
  869. value: '',
  870. }
  871. },
  872. },
  873. {
  874. attachTo: 'body',
  875. }
  876. )
  877. const input = wrapper.find('input')
  878. input.trigger('blur')
  879. input.trigger('focus')
  880. await nextTick()
  881. // click Wednesday
  882. ;(
  883. document.querySelectorAll(
  884. '.el-date-table__row ~ .el-date-table__row td'
  885. )[3] as HTMLElement
  886. ).click()
  887. await nextTick()
  888. const vm = wrapper.vm as any
  889. expect(vm.value).not.toBeNull()
  890. expect(+dayjs(vm.value).locale(loObj.locale.name)).toBe(
  891. +dayjs(vm.value).locale(loObj.locale.name).startOf('week')
  892. )
  893. expect(dayjs(vm.value).locale(loObj.locale.name).day()).toBe(loObj.value) // Sunday or Monday
  894. })
  895. })
  896. })
  897. describe('DatePicker dates', () => {
  898. it('create', async () => {
  899. const wrapper = _mount(
  900. `<el-date-picker
  901. type='dates'
  902. v-model="value"
  903. />`,
  904. () => ({ value: '' })
  905. )
  906. const input = wrapper.find('input')
  907. input.trigger('blur')
  908. input.trigger('focus')
  909. await nextTick()
  910. const td = document.querySelectorAll(
  911. '.el-date-table__row .available'
  912. ) as NodeListOf<HTMLElement>
  913. const vm = wrapper.vm as any
  914. td[0].click()
  915. await nextTick()
  916. expect(vm.value.length).toBe(1)
  917. td[1].click()
  918. await nextTick()
  919. expect(vm.value.length).toBe(2)
  920. expect(
  921. document.querySelectorAll('.el-date-table__row .selected').length
  922. ).toBe(2)
  923. td[0].click()
  924. await nextTick()
  925. expect(vm.value.length).toBe(1)
  926. td[1].click()
  927. await nextTick()
  928. expect(vm.value.length).toBe(0)
  929. })
  930. })
  931. describe('DatePicker keyboard events', () => {
  932. it('enter', async () => {
  933. const wrapper = _mount(
  934. `<el-date-picker
  935. type='date'
  936. v-model="value"
  937. />`,
  938. () => ({ value: '' })
  939. )
  940. const input = wrapper.find('.el-input__inner')
  941. await input.trigger('focus')
  942. await input.trigger('click')
  943. await nextTick()
  944. const popperEl = document.querySelectorAll('.el-picker__popper')[0]
  945. const attr = popperEl.getAttribute('aria-hidden')
  946. expect(attr).toEqual('false')
  947. await input.trigger('keydown', {
  948. code: EVENT_CODE.enter,
  949. })
  950. const popperEl2 = document.querySelectorAll('.el-picker__popper')[0]
  951. const attr2 = popperEl2.getAttribute('aria-hidden')
  952. expect(attr2).toEqual('true')
  953. })
  954. it('numpadEnter', async () => {
  955. const wrapper = _mount(
  956. `<el-date-picker
  957. type='date'
  958. v-model="value"
  959. />`,
  960. () => ({ value: '' })
  961. )
  962. const input = wrapper.find('.el-input__inner')
  963. await input.trigger('focus')
  964. await input.trigger('click')
  965. await nextTick()
  966. const popperEl = document.querySelectorAll('.el-picker__popper')[0]
  967. const attr = popperEl.getAttribute('aria-hidden')
  968. expect(attr).toEqual('false')
  969. await input.trigger('keydown', {
  970. code: EVENT_CODE.numpadEnter,
  971. })
  972. const popperEl2 = document.querySelectorAll('.el-picker__popper')[0]
  973. const attr2 = popperEl2.getAttribute('aria-hidden')
  974. expect(attr2).toEqual('true')
  975. })
  976. })
  977. describe('DateRangePicker', () => {
  978. it('create & custom class & style', async () => {
  979. let calendarChangeValue = null
  980. const changeHandler = vi.fn()
  981. const popperClassName = 'popper-class-test'
  982. const customClassName = 'custom-class-test'
  983. const wrapper = _mount(
  984. `<el-date-picker
  985. type='daterange'
  986. v-model="value"
  987. @calendarChange="onCalendarChange"
  988. :style="{color:'red'}"
  989. :class="customClassName"
  990. :popperClass="popperClassName"
  991. />`,
  992. () => ({ value: '', popperClassName, customClassName }),
  993. {
  994. methods: {
  995. onCalendarChange(e) {
  996. calendarChangeValue = e
  997. changeHandler(e)
  998. },
  999. },
  1000. }
  1001. )
  1002. const inputs = wrapper.findAll('input')
  1003. inputs[0].trigger('blur')
  1004. inputs[0].trigger('focus')
  1005. await nextTick()
  1006. const outterInput = wrapper.find('.el-range-editor.el-input__wrapper')
  1007. expect(outterInput.classes()).toContain(customClassName)
  1008. expect(outterInput.attributes().style).toBeDefined()
  1009. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1010. expect(panels.length).toBe(2)
  1011. ;(panels[0].querySelector('td.available') as HTMLElement).click()
  1012. await nextTick()
  1013. ;(panels[1].querySelector('td.available') as HTMLElement).click()
  1014. await nextTick()
  1015. inputs[0].trigger('blur')
  1016. inputs[0].trigger('focus')
  1017. await nextTick()
  1018. // popperClassName
  1019. expect(
  1020. document
  1021. .querySelector('.el-picker__popper')
  1022. .classList.contains(popperClassName)
  1023. ).toBe(true)
  1024. // correct highlight
  1025. const startDate = document.querySelectorAll('.start-date')
  1026. const endDate = document.querySelectorAll('.end-date')
  1027. const inRangeDate = document.querySelectorAll('.in-range')
  1028. expect(startDate.length).toBe(1)
  1029. expect(endDate.length).toBe(1)
  1030. expect(inRangeDate.length).toBeGreaterThan(28)
  1031. // value is array
  1032. const vm = wrapper.vm as any
  1033. expect(Array.isArray(vm.value)).toBeTruthy()
  1034. // input text is something like date string
  1035. expect(inputs[0].element.value.length).toBe(10)
  1036. expect(inputs[1].element.value.length).toBe(10)
  1037. // calendar-change event
  1038. expect(changeHandler).toHaveBeenCalledTimes(2)
  1039. expect(calendarChangeValue.length).toBe(2)
  1040. expect(calendarChangeValue[0]).toBeInstanceOf(Date)
  1041. expect(calendarChangeValue[1]).toBeInstanceOf(Date)
  1042. })
  1043. it('reverse selection', async () => {
  1044. const wrapper = _mount(
  1045. `<el-date-picker
  1046. type='daterange'
  1047. v-model="value"
  1048. />`,
  1049. () => ({ value: '' })
  1050. )
  1051. const inputs = wrapper.findAll('input')
  1052. inputs[0].trigger('blur')
  1053. inputs[0].trigger('focus')
  1054. await nextTick()
  1055. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1056. ;(panels[1].querySelector('td.available') as HTMLElement).click()
  1057. await nextTick()
  1058. ;(panels[0].querySelector('td.available') as HTMLElement).click()
  1059. await nextTick()
  1060. inputs[0].trigger('blur')
  1061. inputs[0].trigger('focus')
  1062. await nextTick()
  1063. // correct highlight
  1064. const startDate = document.querySelectorAll('.start-date')
  1065. const endDate = document.querySelectorAll('.end-date')
  1066. const inRangeDate = document.querySelectorAll('.in-range')
  1067. expect(startDate.length).toBe(1)
  1068. expect(endDate.length).toBe(1)
  1069. expect(inRangeDate.length).toBeGreaterThan(28)
  1070. const vm = wrapper.vm as any
  1071. expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy()
  1072. })
  1073. it('reset selection', async () => {
  1074. const wrapper = _mount(
  1075. `<el-date-picker
  1076. type='daterange'
  1077. v-model="value"
  1078. />`,
  1079. () => ({ value: '' })
  1080. )
  1081. const inputs = wrapper.findAll('input')
  1082. inputs[0].trigger('blur')
  1083. inputs[0].trigger('focus')
  1084. await nextTick()
  1085. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1086. ;(panels[1].querySelector('td.available') as HTMLElement).click()
  1087. await nextTick()
  1088. ;(panels[0].querySelector('td.available') as HTMLElement).click()
  1089. await nextTick()
  1090. ;(wrapper.vm as any).value = ''
  1091. inputs[0].trigger('blur')
  1092. inputs[0].trigger('focus')
  1093. await nextTick()
  1094. const inRangeDate = document.querySelectorAll('.in-range')
  1095. expect(inRangeDate.length).toBe(0)
  1096. })
  1097. it('range, start-date and end-date', async () => {
  1098. _mount(
  1099. `<el-date-picker
  1100. type='daterange'
  1101. v-model="value"
  1102. />`,
  1103. () => ({ value: '' })
  1104. )
  1105. const table = document.querySelector('.el-date-table')
  1106. const availableTds = (table as HTMLTableElement).querySelectorAll(
  1107. 'td.available'
  1108. )
  1109. ;(availableTds[0] as HTMLElement).click()
  1110. await nextTick()
  1111. ;(availableTds[1] as HTMLElement).click()
  1112. await nextTick()
  1113. expect(availableTds[0].classList.contains('in-range')).toBeTruthy()
  1114. expect(availableTds[0].classList.contains('start-date')).toBeTruthy()
  1115. expect(availableTds[1].classList.contains('in-range')).toBeTruthy()
  1116. expect(availableTds[1].classList.contains('end-date')).toBeTruthy()
  1117. ;(availableTds[1] as HTMLElement).click()
  1118. await nextTick()
  1119. ;(availableTds[0] as HTMLElement).click()
  1120. await nextTick()
  1121. expect(availableTds[0].classList.contains('in-range')).toBeTruthy()
  1122. expect(availableTds[0].classList.contains('start-date')).toBeTruthy()
  1123. expect(availableTds[1].classList.contains('in-range')).toBeTruthy()
  1124. expect(availableTds[1].classList.contains('end-date')).toBeTruthy()
  1125. const startDate = document.querySelectorAll('.start-date')
  1126. const endDate = document.querySelectorAll('.end-date')
  1127. const inRangeDate = document.querySelectorAll('.in-range')
  1128. expect(startDate.length).toBe(1)
  1129. expect(endDate.length).toBe(1)
  1130. expect(inRangeDate.length).toBe(2)
  1131. })
  1132. it('unlink:true', async () => {
  1133. const wrapper = _mount(
  1134. `<el-date-picker
  1135. type='daterange'
  1136. v-model="value"
  1137. unlink-panels
  1138. />`,
  1139. () => ({ value: [new Date(2000, 9, 1), new Date(2000, 11, 2)] })
  1140. )
  1141. const inputs = wrapper.findAll('input')
  1142. inputs[0].trigger('blur')
  1143. inputs[0].trigger('focus')
  1144. await nextTick()
  1145. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1146. const left = panels[0].querySelector('.el-date-range-picker__header')
  1147. const right = panels[1].querySelector(
  1148. '.is-right .el-date-range-picker__header'
  1149. )
  1150. expect(left.textContent).toBe('2000 October')
  1151. expect(right.textContent).toBe('2000 December')
  1152. ;(panels[1].querySelector('.d-arrow-right') as HTMLElement).click()
  1153. await nextTick()
  1154. ;(panels[1].querySelector('.arrow-right') as HTMLElement).click()
  1155. await nextTick()
  1156. expect(left.textContent).toBe('2000 October')
  1157. expect(right.textContent).toBe('2002 January')
  1158. })
  1159. it('daylight saving time highlight', async () => {
  1160. // Run test with environment variable TZ=Australia/Sydney
  1161. // The following test uses Australian Eastern Daylight Time (AEDT)
  1162. // AEST -> AEDT shift happened on 2016-10-02 02:00:00
  1163. const wrapper = _mount(
  1164. `<el-date-picker
  1165. type='daterange'
  1166. v-model="value"
  1167. unlink-panels
  1168. />`,
  1169. () => ({ value: [new Date(2016, 9, 1), new Date(2016, 9, 3)] })
  1170. )
  1171. const inputs = wrapper.findAll('input')
  1172. inputs[0].trigger('blur')
  1173. inputs[0].trigger('focus')
  1174. await nextTick()
  1175. const startDate = document.querySelectorAll('.start-date')
  1176. const endDate = document.querySelectorAll('.end-date')
  1177. expect(startDate.length).toBe(1)
  1178. expect(endDate.length).toBe(1)
  1179. })
  1180. it('value-format', async () => {
  1181. const valueFormat = 'DD/MM YYYY'
  1182. const wrapper = _mount(
  1183. `
  1184. <el-date-picker
  1185. v-model="value"
  1186. type="daterange"
  1187. format="YYYY-MM-DD"
  1188. value-format="${valueFormat}"
  1189. />`,
  1190. () => ({
  1191. value: [
  1192. dayjs(new Date(2021, 4, 2)).format(valueFormat),
  1193. dayjs(new Date(2021, 4, 12)).format(valueFormat),
  1194. ],
  1195. })
  1196. )
  1197. await nextTick()
  1198. const [startInput, endInput] = wrapper.findAll('input')
  1199. expect(startInput.element.value).toBe('2021-05-02')
  1200. expect(endInput.element.value).toBe('2021-05-12')
  1201. startInput.trigger('blur')
  1202. startInput.trigger('focus')
  1203. await nextTick()
  1204. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1205. expect(panels.length).toBe(2)
  1206. ;(panels[0].querySelector('td.available') as HTMLElement).click()
  1207. await nextTick()
  1208. ;(panels[1].querySelector('td.available') as HTMLElement).click()
  1209. await nextTick()
  1210. expect((wrapper.vm as any).value.toString()).toBe(
  1211. ['01/05 2021', '01/06 2021'].toString()
  1212. )
  1213. })
  1214. it('panel change event', async () => {
  1215. await testDatePickerPanelChange('daterange')
  1216. })
  1217. it('display value', async () => {
  1218. const wrapper = _mount(
  1219. `
  1220. <el-date-picker
  1221. v-model="value"
  1222. type="daterange"
  1223. />`,
  1224. () => ({
  1225. value: [undefined, undefined],
  1226. })
  1227. )
  1228. await nextTick()
  1229. const [startInput, endInput] = wrapper.findAll('input')
  1230. expect(startInput.element.value).toBe('')
  1231. expect(endInput.element.value).toBe('')
  1232. })
  1233. })
  1234. describe('MonthRange', () => {
  1235. it('works', async () => {
  1236. const wrapper = _mount(
  1237. `<el-date-picker
  1238. type='monthrange'
  1239. v-model="value"
  1240. />`,
  1241. () => ({ value: '' })
  1242. )
  1243. const inputs = wrapper.findAll('input')
  1244. inputs[0].trigger('blur')
  1245. inputs[0].trigger('focus')
  1246. await nextTick()
  1247. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1248. expect(panels.length).toBe(2)
  1249. const p0 = <HTMLElement>panels[0].querySelector('td:not(.disabled)')
  1250. p0.click()
  1251. await nextTick()
  1252. const p1 = <HTMLElement>panels[1].querySelector('td:not(.disabled)')
  1253. p1.click()
  1254. await nextTick()
  1255. inputs[0].trigger('blur')
  1256. inputs[0].trigger('focus')
  1257. // correct highlight
  1258. const startDate = document.querySelectorAll('.start-date')
  1259. const endDate = document.querySelectorAll('.end-date')
  1260. const inRangeDate = document.querySelectorAll('.in-range')
  1261. expect(startDate.length).toBe(1)
  1262. expect(endDate.length).toBe(1)
  1263. expect(inRangeDate.length).toBeGreaterThan(0)
  1264. // value is array
  1265. const vm = wrapper.vm as any
  1266. expect(Array.isArray(vm.value)).toBeTruthy()
  1267. // input text is something like date string
  1268. expect(inputs[0].element.value.length).toBe(7)
  1269. expect(inputs[1].element.value.length).toBe(7)
  1270. // reverse selection
  1271. p1.click()
  1272. await nextTick()
  1273. p0.click()
  1274. await nextTick()
  1275. expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy()
  1276. })
  1277. it('range, start-date and end-date', async () => {
  1278. _mount(
  1279. `<el-date-picker
  1280. type='monthrange'
  1281. v-model="value"
  1282. />`,
  1283. () => ({ value: '' })
  1284. )
  1285. const table = document.querySelector('.el-month-table')
  1286. const tds = (table as HTMLTableElement).querySelectorAll('td')
  1287. ;(tds[0] as HTMLElement).click()
  1288. await nextTick()
  1289. ;(tds[1] as HTMLElement).click()
  1290. await nextTick()
  1291. expect(tds[0].classList.contains('in-range')).toBeTruthy()
  1292. expect(tds[0].classList.contains('start-date')).toBeTruthy()
  1293. expect(tds[1].classList.contains('in-range')).toBeTruthy()
  1294. expect(tds[1].classList.contains('end-date')).toBeTruthy()
  1295. ;(tds[1] as HTMLElement).click()
  1296. await nextTick()
  1297. ;(tds[0] as HTMLElement).click()
  1298. await nextTick()
  1299. expect(tds[0].classList.contains('in-range')).toBeTruthy()
  1300. expect(tds[0].classList.contains('start-date')).toBeTruthy()
  1301. expect(tds[1].classList.contains('in-range')).toBeTruthy()
  1302. expect(tds[1].classList.contains('end-date')).toBeTruthy()
  1303. const startDate = document.querySelectorAll('.start-date')
  1304. const endDate = document.querySelectorAll('.end-date')
  1305. const inRangeDate = document.querySelectorAll('.in-range')
  1306. expect(startDate.length).toBe(1)
  1307. expect(endDate.length).toBe(1)
  1308. expect(inRangeDate.length).toBe(2)
  1309. })
  1310. it('type:monthrange unlink:true', async () => {
  1311. const wrapper = _mount(
  1312. `<el-date-picker
  1313. type='monthrange'
  1314. v-model="value"
  1315. unlink-panels
  1316. />`,
  1317. () => ({ value: [new Date(2000, 9), new Date(2002, 11)] })
  1318. )
  1319. const inputs = wrapper.findAll('input')
  1320. inputs[0].trigger('blur')
  1321. inputs[0].trigger('focus')
  1322. await nextTick()
  1323. const panels = document.querySelectorAll('.el-date-range-picker__content')
  1324. const left = panels[0].querySelector('.el-date-range-picker__header')
  1325. const right = panels[1].querySelector(
  1326. '.is-right .el-date-range-picker__header'
  1327. )
  1328. expect(left.textContent).toContain(2000)
  1329. expect(right.textContent).toContain(2002)
  1330. ;(panels[1].querySelector('.d-arrow-right') as HTMLElement).click()
  1331. await nextTick()
  1332. expect(left.textContent).toContain(2000)
  1333. expect(right.textContent).toContain(2003)
  1334. })
  1335. it('daylight saving time highlight', async () => {
  1336. const wrapper = _mount(
  1337. `<el-date-picker
  1338. type='monthrange'
  1339. v-model="value"
  1340. unlink-panels
  1341. />`,
  1342. () => ({ value: [new Date(2016, 6), new Date(2016, 12)] })
  1343. )
  1344. const inputs = wrapper.findAll('input')
  1345. inputs[0].trigger('blur')
  1346. inputs[0].trigger('focus')
  1347. await nextTick()
  1348. const startDate = document.querySelectorAll('.start-date')
  1349. const endDate = document.querySelectorAll('.end-date')
  1350. expect(startDate.length).toBe(1)
  1351. expect(endDate.length).toBe(1)
  1352. })
  1353. it('should accept popper options and pass down', async () => {
  1354. const ElPopperOptions = {
  1355. strategy: 'fixed',
  1356. }
  1357. const wrapper = _mount(
  1358. `<el-date-picker
  1359. type='monthrange'
  1360. v-model="value"
  1361. :popper-options="options"
  1362. unlink-panels
  1363. />`,
  1364. () => ({
  1365. value: [new Date(2016, 6), new Date(2016, 12)],
  1366. options: ElPopperOptions,
  1367. }),
  1368. {
  1369. provide() {
  1370. return {
  1371. ElPopperOptions,
  1372. }
  1373. },
  1374. }
  1375. )
  1376. await nextTick()
  1377. expect(
  1378. (wrapper.findComponent(CommonPicker).vm as any).elPopperOptions
  1379. ).toEqual(ElPopperOptions)
  1380. })
  1381. describe('form item accessibility integration', () => {
  1382. it('automatic id attachment', async () => {
  1383. const wrapper = _mount(
  1384. `<el-form-item label="Foobar" data-test-ref="item">
  1385. <el-date-picker />
  1386. </el-form-item>`,
  1387. () => ({})
  1388. )
  1389. await nextTick()
  1390. const formItem = wrapper.find('[data-test-ref="item"]')
  1391. const formItemLabel = formItem.find('.el-form-item__label')
  1392. const datePickerInput = wrapper.find('.el-input__inner')
  1393. expect(formItem.attributes().role).toBeFalsy()
  1394. expect(formItemLabel.attributes().for).toBe(
  1395. datePickerInput.attributes().id
  1396. )
  1397. })
  1398. it('specified id attachment', async () => {
  1399. const wrapper = _mount(
  1400. `<el-form-item label="Foobar" data-test-ref="item">
  1401. <el-date-picker id="foobar" />
  1402. </el-form-item>`,
  1403. () => ({})
  1404. )
  1405. await nextTick()
  1406. const formItem = wrapper.find('[data-test-ref="item"]')
  1407. const formItemLabel = formItem.find('.el-form-item__label')
  1408. const datePickerInput = wrapper.find('.el-input__inner')
  1409. expect(formItem.attributes().role).toBeFalsy()
  1410. expect(datePickerInput.attributes().id).toBe('foobar')
  1411. expect(formItemLabel.attributes().for).toBe(
  1412. datePickerInput.attributes().id
  1413. )
  1414. })
  1415. it('form item role is group when multiple inputs', async () => {
  1416. const wrapper = _mount(
  1417. `<el-form-item label="Foobar" data-test-ref="item">
  1418. <el-date-picker />
  1419. <el-date-picker />
  1420. </el-form-item>`,
  1421. () => ({})
  1422. )
  1423. await nextTick()
  1424. const formItem = wrapper.find('[data-test-ref="item"]')
  1425. expect(formItem.attributes().role).toBe('group')
  1426. })
  1427. })
  1428. it('The year which is disabled should not be selectable', async () => {
  1429. const pickHandler = vi.fn()
  1430. const wrapper = _mount(
  1431. `<el-date-picker
  1432. v-model="yearValue"
  1433. type="year"
  1434. :disabled-date="validateYear"
  1435. @panel-change="onPick"
  1436. />`,
  1437. () => ({
  1438. yearValue: '2022',
  1439. validateYear: (date) => {
  1440. if (date.getFullYear() > 2022) {
  1441. return true
  1442. } else {
  1443. return false
  1444. }
  1445. },
  1446. onPick(e) {
  1447. return pickHandler(e)
  1448. },
  1449. })
  1450. )
  1451. const input = wrapper.find('input')
  1452. input.trigger('focus')
  1453. await nextTick()
  1454. ;(document.querySelector('td.disabled') as HTMLElement).click()
  1455. await nextTick()
  1456. expect(pickHandler).toHaveBeenCalledTimes(0)
  1457. ;(document.querySelector('td.available') as HTMLElement).click()
  1458. await nextTick()
  1459. expect(pickHandler).toHaveBeenCalledTimes(1)
  1460. })
  1461. })