table.test.ts 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606
  1. // @ts-nocheck
  2. import { nextTick } from 'vue'
  3. import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
  4. import ElCheckbox from '@element-plus/components/checkbox'
  5. import triggerEvent from '@element-plus/test-utils/trigger-event'
  6. import { rAF } from '@element-plus/test-utils/tick'
  7. import ElTable from '../src/table.vue'
  8. import ElTableColumn from '../src/table-column'
  9. import { doubleWait, getTestData, mount } from './table-test-common'
  10. import type { VueWrapper } from '@vue/test-utils'
  11. import type { ComponentPublicInstance } from 'vue'
  12. const { CheckboxGroup: ElCheckboxGroup } = ElCheckbox
  13. vi.mock('lodash-unified', async () => {
  14. return {
  15. ...((await vi.importActual('lodash-unified')) as Record<string, any>),
  16. debounce: vi.fn((fn) => {
  17. fn.cancel = vi.fn()
  18. fn.flush = vi.fn()
  19. return fn
  20. }),
  21. }
  22. })
  23. describe('Table.vue', () => {
  24. describe('rendering data is correct', () => {
  25. const wrapper = mount({
  26. components: {
  27. ElTable,
  28. ElTableColumn,
  29. },
  30. template: `
  31. <el-table :data="testData">
  32. <el-table-column prop="id" />
  33. <el-table-column prop="name" label="片名" />
  34. <el-table-column prop="release" label="发行日期" />
  35. <el-table-column prop="director" label="导演" />
  36. <el-table-column prop="runtime" label="时长(分)" />
  37. </el-table>
  38. `,
  39. created() {
  40. this.testData = getTestData()
  41. },
  42. })
  43. it('head', async () => {
  44. await doubleWait()
  45. const ths = wrapper.findAll('thead th')
  46. expect(ths.map((node) => node.text()).filter((o) => o)).toEqual([
  47. '片名',
  48. '发行日期',
  49. '导演',
  50. '时长(分)',
  51. ])
  52. })
  53. it('row length', () => {
  54. expect(
  55. wrapper.findAll('.el-table__body-wrapper tbody tr').length
  56. ).toEqual(getTestData().length)
  57. })
  58. it('row data', () => {
  59. const cells = wrapper.findAll('td .cell').map((node) => node.text())
  60. const testDataArr = getTestData().flatMap((cur) => {
  61. return Object.values(cur).map(String)
  62. })
  63. expect(cells).toEqual(testDataArr)
  64. wrapper.unmount()
  65. })
  66. })
  67. it('custom template', async () => {
  68. const wrapper = mount({
  69. components: {
  70. ElTable,
  71. ElTableColumn,
  72. ElCheckboxGroup,
  73. ElCheckbox,
  74. },
  75. template: `
  76. <el-table :data="tableData">
  77. <el-table-column label="someLabel">
  78. <template #default="{ row }">
  79. <el-checkbox-group v-model="row.checkList">
  80. <el-checkbox label="复选框 A"></el-checkbox>
  81. <el-checkbox label="复选框 B"></el-checkbox>
  82. </el-checkbox-group>
  83. </template>
  84. </el-table-column>
  85. </el-table>
  86. `,
  87. data() {
  88. return {
  89. tableData: [
  90. {
  91. checkList: [],
  92. },
  93. {
  94. checkList: ['复选框 A'],
  95. },
  96. {
  97. checkList: ['复选框 A', '复选框 B'],
  98. },
  99. ],
  100. }
  101. },
  102. })
  103. const vm = wrapper.vm
  104. await doubleWait()
  105. const checkGroup = vm.$el.querySelectorAll(
  106. '.el-table__body-wrapper .el-checkbox-group'
  107. )
  108. expect(checkGroup.length).toBe(3)
  109. const checkbox = vm.$el.querySelectorAll(
  110. '.el-table__body-wrapper .el-checkbox'
  111. )
  112. expect(checkbox.length).toBe(6)
  113. const checkSelect = vm.$el.querySelectorAll(
  114. '.el-table__body-wrapper label.is-checked'
  115. )
  116. expect(checkSelect.length).toBe(3)
  117. })
  118. describe('attributes', () => {
  119. const createTable = function (props, opts?) {
  120. return mount(
  121. Object.assign(
  122. {
  123. components: {
  124. ElTable,
  125. ElTableColumn,
  126. },
  127. template: `
  128. <el-table :data="testData" ${props}>
  129. <el-table-column prop="name" label="片名" />
  130. <el-table-column prop="release" label="发行日期" />
  131. <el-table-column prop="director" label="导演" />
  132. <el-table-column prop="runtime" label="时长(分)" />
  133. </el-table>
  134. `,
  135. created() {
  136. this.testData = getTestData()
  137. },
  138. },
  139. opts
  140. )
  141. )
  142. }
  143. it('height', async () => {
  144. const wrapper = createTable('height="134"')
  145. await doubleWait()
  146. expect(wrapper.attributes('style')).toContain('height: 134px')
  147. wrapper.unmount()
  148. })
  149. it('height as string', async () => {
  150. const wrapper = createTable('height="100px"')
  151. await doubleWait()
  152. expect(wrapper.attributes('style')).toContain('height: 100px')
  153. wrapper.unmount()
  154. })
  155. it('maxHeight', async () => {
  156. const wrapper = createTable('max-height="134"')
  157. await doubleWait()
  158. expect(wrapper.attributes('style')).toContain('max-height: 134px')
  159. wrapper.unmount()
  160. })
  161. it('maxHeight uses special units', async () => {
  162. const wrapper = createTable('max-height="60vh"')
  163. await doubleWait()
  164. expect(wrapper.find('.el-scrollbar__wrap').attributes('style')).toContain(
  165. 'max-height: calc(60vh - 0px);'
  166. )
  167. wrapper.unmount()
  168. })
  169. it('stripe', async () => {
  170. const wrapper = createTable('stripe')
  171. await doubleWait()
  172. expect(wrapper.classes()).toContain('el-table--striped')
  173. wrapper.unmount()
  174. })
  175. it('border', async () => {
  176. const wrapper = createTable('border')
  177. await doubleWait()
  178. expect(wrapper.classes()).toContain('el-table--border')
  179. wrapper.unmount()
  180. })
  181. it('fit', async () => {
  182. const wrapper = createTable(':fit="false"')
  183. await doubleWait()
  184. expect(wrapper.classes()).not.toContain('el-table--fit')
  185. wrapper.unmount()
  186. })
  187. it('show-header', async () => {
  188. const wrapper = createTable(':show-header="false"')
  189. await doubleWait()
  190. expect(wrapper.findAll('.el-table__header-wrapper').length).toEqual(0)
  191. wrapper.unmount()
  192. })
  193. it('tableRowClassName', async () => {
  194. const wrapper = createTable(':row-class-name="tableRowClassName"', {
  195. methods: {
  196. tableRowClassName({ rowIndex }) {
  197. if (rowIndex === 1) {
  198. return 'info-row'
  199. } else if (rowIndex === 3) {
  200. return 'positive-row'
  201. }
  202. return ''
  203. },
  204. },
  205. })
  206. await doubleWait()
  207. expect(wrapper.findAll('.info-row').length).toEqual(1)
  208. expect(wrapper.findAll('.positive-row').length).toEqual(1)
  209. wrapper.unmount()
  210. })
  211. it('tableRowStyle[Object]', async () => {
  212. const wrapper = createTable(':row-style="{ height: \'60px\' }"', {})
  213. await doubleWait()
  214. expect(wrapper.find('.el-table__body tr').attributes('style')).toContain(
  215. 'height: 60px'
  216. )
  217. wrapper.unmount()
  218. })
  219. it('tableRowStyle[Function]', async () => {
  220. const wrapper = createTable(':row-style="tableRowStyle"', {
  221. methods: {
  222. tableRowStyle({ rowIndex }) {
  223. if (rowIndex === 1) {
  224. return { height: '60px', display: 'none' }
  225. }
  226. return null
  227. },
  228. },
  229. })
  230. await doubleWait()
  231. const child1 = wrapper.find('.el-table__body tr:nth-child(1)')
  232. const child2 = wrapper.find('.el-table__body tr:nth-child(2)')
  233. expect(child1.attributes('style')).toBeUndefined()
  234. expect(child2.attributes('style')).toContain('height: 60px')
  235. expect(child2.attributes('style')).toContain('display: none')
  236. wrapper.unmount()
  237. })
  238. it('current-row-key', async () => {
  239. const wrapper = mount({
  240. components: {
  241. ElTable,
  242. ElTableColumn,
  243. },
  244. template: `
  245. <el-table :data="testData" row-key="id" highlight-current-row :current-row-key="currentRowKey">
  246. <el-table-column prop="name" label="片名" />
  247. <el-table-column prop="release" label="发行日期" />
  248. <el-table-column prop="director" label="导演" />
  249. <el-table-column prop="runtime" label="时长(分)" />
  250. </el-table>
  251. `,
  252. created() {
  253. this.testData = getTestData()
  254. },
  255. data() {
  256. return { currentRowKey: null }
  257. },
  258. })
  259. await doubleWait()
  260. wrapper.vm.currentRowKey = 1
  261. const tr = wrapper.find('.el-table__body-wrapper tbody tr')
  262. await doubleWait()
  263. expect(tr.classes()).toContain('current-row')
  264. wrapper.vm.currentRowKey = 2
  265. const rows = wrapper.findAll('.el-table__body-wrapper tbody tr')
  266. await doubleWait()
  267. expect(tr.classes()).not.toContain('current-row')
  268. expect(rows[1].classes()).toContain('current-row')
  269. wrapper.unmount()
  270. })
  271. })
  272. describe('filter', () => {
  273. let wrapper: VueWrapper<ComponentPublicInstance>
  274. beforeEach(async () => {
  275. wrapper = mount({
  276. components: {
  277. ElTable,
  278. ElTableColumn,
  279. },
  280. template: `
  281. <el-table ref="table" :data="testData" @filter-change="handleFilterChange">
  282. <el-table-column prop="name" label="片名" />
  283. <el-table-column prop="release" label="发行日期" />
  284. <el-table-column
  285. prop="director"
  286. column-key="director"
  287. :filters="[
  288. { text: 'John Lasseter', value: 'John Lasseter' },
  289. { text: 'Peter Docter', value: 'Peter Docter' },
  290. { text: 'Andrew Stanton', value: 'Andrew Stanton' }
  291. ]"
  292. :filter-method="filterMethod"
  293. label="导演" />
  294. <el-table-column prop="runtime" label="时长(分)" />
  295. </el-table>
  296. `,
  297. created() {
  298. this.testData = getTestData()
  299. },
  300. methods: {
  301. filterMethod(value, row) {
  302. return value === row.director
  303. },
  304. handleFilterChange(filters) {
  305. this.filters = filters
  306. },
  307. },
  308. })
  309. await doubleWait()
  310. })
  311. afterEach(() => wrapper.unmount())
  312. it('render', () => {
  313. expect(
  314. wrapper.find('.el-table__column-filter-trigger')
  315. ).not.toBeUndefined()
  316. })
  317. it('click dropdown', async () => {
  318. const btn = wrapper.find('.el-table__column-filter-trigger')
  319. btn.trigger('click')
  320. await doubleWait()
  321. const filter = document.body.querySelector('.el-table-filter')
  322. expect(filter).not.toBeUndefined()
  323. filter.parentNode.removeChild(filter)
  324. })
  325. it('click filter', async () => {
  326. const btn = wrapper.find('.el-table__column-filter-trigger')
  327. btn.trigger('click')
  328. await doubleWait()
  329. const filter = document.body.querySelector('.el-table-filter')
  330. triggerEvent(filter.querySelector('.el-checkbox'), 'click', true, false)
  331. // confirm button
  332. await doubleWait()
  333. triggerEvent(
  334. filter.querySelector('.el-table-filter__bottom button'),
  335. 'click',
  336. true,
  337. false
  338. )
  339. await doubleWait()
  340. expect(
  341. (wrapper.vm as ComponentPublicInstance & { filters: any }).filters[
  342. 'director'
  343. ]
  344. ).toEqual(['John Lasseter'])
  345. expect(
  346. wrapper.findAll('.el-table__body-wrapper tbody tr').length
  347. ).toEqual(3)
  348. filter.parentNode.removeChild(filter)
  349. })
  350. it('clear filter', async () => {
  351. const btn = wrapper.find('.el-table__column-filter-trigger')
  352. btn.trigger('click')
  353. await doubleWait()
  354. const filter = document.body.querySelector('.el-table-filter')
  355. triggerEvent(filter.querySelector('.el-checkbox'), 'click', true, false)
  356. // confirm button
  357. await doubleWait()
  358. triggerEvent(
  359. filter.querySelector('.el-table-filter__bottom button'),
  360. 'click',
  361. true,
  362. false
  363. )
  364. await nextTick()
  365. expect(
  366. wrapper.findAll('.el-table__body-wrapper tbody tr').length
  367. ).toEqual(3)
  368. wrapper.vm.$refs.table.clearFilter()
  369. await nextTick()
  370. expect(
  371. wrapper.findAll('.el-table__body-wrapper tbody tr').length
  372. ).toEqual(5)
  373. filter.parentNode.removeChild(filter)
  374. })
  375. it('click reset', async () => {
  376. const btn = wrapper.find('.el-table__column-filter-trigger')
  377. btn.trigger('click')
  378. await doubleWait()
  379. const filter = document.body.querySelector('.el-table-filter')
  380. triggerEvent(filter.querySelector('.el-checkbox'), 'click', true, false)
  381. await doubleWait()
  382. triggerEvent(
  383. filter.querySelectorAll('.el-table-filter__bottom button')[1],
  384. 'click',
  385. true,
  386. false
  387. )
  388. await doubleWait()
  389. expect(
  390. (wrapper.vm as ComponentPublicInstance & { filters: any }).filters[
  391. 'director'
  392. ]
  393. ).toEqual([])
  394. expect([
  395. ...filter.querySelector('.el-table-filter__bottom button').classList,
  396. ]).toContain('is-disabled')
  397. filter.parentNode.removeChild(filter)
  398. wrapper.unmount()
  399. })
  400. })
  401. describe('events', () => {
  402. const createTable = function (prop = '') {
  403. return mount({
  404. components: {
  405. ElTable,
  406. ElTableColumn,
  407. },
  408. template: `
  409. <el-table :data="testData" @${prop}="handleEvent">
  410. <el-table-column type="selection" />
  411. <el-table-column prop="name" />
  412. <el-table-column prop="release" />
  413. <el-table-column prop="director" />
  414. <el-table-column prop="runtime"/>
  415. </el-table>
  416. `,
  417. methods: {
  418. handleEvent(...args) {
  419. this.result = args
  420. },
  421. },
  422. data() {
  423. return { result: '', testData: getTestData() }
  424. },
  425. })
  426. }
  427. it('select', async () => {
  428. const wrapper = createTable('select')
  429. await doubleWait()
  430. wrapper.findAll('.el-checkbox')[1].trigger('click')
  431. expect(wrapper.vm.result.length).toEqual(2)
  432. expect(wrapper.vm.result[1]).toHaveProperty('name')
  433. expect(wrapper.vm.result[1]['name']).toEqual(getTestData()[0].name)
  434. wrapper.unmount()
  435. })
  436. it('selection-change', async () => {
  437. const wrapper = createTable('selection-change')
  438. await doubleWait()
  439. wrapper.findAll('.el-checkbox')[1].trigger('click')
  440. expect(wrapper.vm.result.length).toEqual(1)
  441. wrapper.unmount()
  442. })
  443. it('cell-mouse-enter', async () => {
  444. const wrapper = createTable('cell-mouse-enter')
  445. await doubleWait()
  446. const cell = wrapper.findAll('.el-table__body .cell')[2] // first row
  447. triggerEvent(cell.element.parentElement, 'mouseenter')
  448. expect(wrapper.vm.result.length).toEqual(4) // row, column, cell, event
  449. expect(wrapper.vm.result[0]).toHaveProperty('name')
  450. expect(wrapper.vm.result[0]['name']).toEqual(getTestData()[0].name)
  451. wrapper.unmount()
  452. })
  453. it('cell-mouse-leave', async () => {
  454. const wrapper = createTable('cell-mouse-leave')
  455. await doubleWait()
  456. const cell = wrapper.findAll('.el-table__body .cell')[7] // second row
  457. const cell2 = wrapper.findAll('.el-table__body .cell')[2] // first row
  458. triggerEvent(cell2.element.parentElement, 'mouseenter')
  459. triggerEvent(cell.element.parentElement, 'mouseleave')
  460. expect(wrapper.vm.result.length).toEqual(4) // row, column, cell, event
  461. expect(wrapper.vm.result[0]).toHaveProperty('name')
  462. expect(wrapper.vm.result[0]['name']).toEqual(getTestData()[0].name)
  463. wrapper.unmount()
  464. })
  465. it('row-click', async () => {
  466. const wrapper = createTable('row-click')
  467. await doubleWait()
  468. const cell = wrapper.findAll('.el-table__body .cell')[2] // first row
  469. triggerEvent(cell.element.parentElement.parentElement, 'click')
  470. expect(wrapper.vm.result.length).toEqual(3) // row, event, column
  471. expect(wrapper.vm.result[0]).toHaveProperty('name')
  472. expect(wrapper.vm.result[0]['name']).toEqual(getTestData()[0].name)
  473. wrapper.unmount()
  474. })
  475. it('row-dblclick', async () => {
  476. const wrapper = createTable('row-dblclick')
  477. await doubleWait()
  478. const cell = wrapper.findAll('.el-table__body .cell')[2] // first row
  479. triggerEvent(cell.element.parentElement.parentElement, 'dblclick')
  480. expect(wrapper.vm.result.length).toEqual(3) // row, event, column
  481. expect(wrapper.vm.result[0]).toHaveProperty('name')
  482. expect(wrapper.vm.result[0]['name']).toEqual(getTestData()[0].name)
  483. wrapper.unmount()
  484. })
  485. it('header-click', async () => {
  486. const wrapper = createTable('header-click')
  487. await doubleWait()
  488. const cell = wrapper.findAll('.el-table__header th')[1] // header[prop='name']
  489. cell.trigger('click')
  490. expect(wrapper.vm.result.length).toEqual(2) // column, event
  491. expect(wrapper.vm.result[0]['name']).toBeUndefined()
  492. wrapper.unmount()
  493. })
  494. })
  495. describe('summary row', () => {
  496. it('should render', async () => {
  497. const wrapper = mount({
  498. components: {
  499. ElTable,
  500. ElTableColumn,
  501. },
  502. template: `
  503. <el-table :data="testData" show-summary>
  504. <el-table-column prop="name" />
  505. <el-table-column prop="release"/>
  506. <el-table-column prop="director"/>
  507. <el-table-column prop="runtime"/>
  508. </el-table>
  509. `,
  510. created() {
  511. this.testData = getTestData()
  512. },
  513. })
  514. await doubleWait()
  515. const footer = wrapper.find('.el-table__footer')
  516. expect(footer).not.toBeUndefined()
  517. const cells = footer.findAll('.cell')
  518. expect(cells[cells.length - 1].text()).toEqual('459')
  519. wrapper.unmount()
  520. })
  521. it('custom sum text', async () => {
  522. const wrapper = mount({
  523. components: {
  524. ElTable,
  525. ElTableColumn,
  526. },
  527. template: `
  528. <el-table :data="testData" show-summary sum-text="Time">
  529. <el-table-column prop="name" />
  530. <el-table-column prop="release"/>
  531. <el-table-column prop="director"/>
  532. <el-table-column prop="runtime"/>
  533. </el-table>
  534. `,
  535. created() {
  536. this.testData = getTestData()
  537. },
  538. })
  539. await doubleWait()
  540. const cells = wrapper.findAll('.el-table__footer .cell')
  541. expect(cells[0].text()).toEqual('Time')
  542. wrapper.unmount()
  543. })
  544. it('custom summary method', async () => {
  545. const wrapper = mount({
  546. components: {
  547. ElTable,
  548. ElTableColumn,
  549. },
  550. template: `
  551. <el-table :data="testData" show-summary :summary-method="getSummary">
  552. <el-table-column prop="name" />
  553. <el-table-column prop="release"/>
  554. <el-table-column prop="director"/>
  555. <el-table-column prop="runtime"/>
  556. </el-table>
  557. `,
  558. created() {
  559. this.testData = getTestData()
  560. },
  561. methods: {
  562. getSummary(param) {
  563. const { columns, data } = param
  564. const result = []
  565. columns.forEach((column) => {
  566. const prop = column.property
  567. if (prop === 'release') {
  568. const dates = data.map((item) => item[prop])
  569. const releaseYears = dates.map((date) =>
  570. Number(date.slice(0, 4))
  571. )
  572. result.push(
  573. releaseYears.reduce((prev, curr) => {
  574. return prev + curr
  575. })
  576. )
  577. } else {
  578. result.push('')
  579. }
  580. })
  581. return result
  582. },
  583. },
  584. })
  585. await doubleWait()
  586. const cells = wrapper.findAll('.el-table__footer .cell')
  587. expect(cells[1].text()).toEqual('9996')
  588. wrapper.unmount()
  589. })
  590. })
  591. describe('methods', () => {
  592. const createTable = function (prop = '') {
  593. return mount({
  594. components: {
  595. ElTableColumn,
  596. ElTable,
  597. },
  598. template: `
  599. <el-table ref="table" :data="testData" @${prop}="handleEvent">
  600. <el-table-column type="selection" />
  601. <el-table-column prop="name" />
  602. <el-table-column prop="release" />
  603. <el-table-column prop="director" />
  604. <el-table-column prop="runtime"/>
  605. </el-table>
  606. `,
  607. methods: {
  608. handleEvent(selection) {
  609. this.fireCount++
  610. this.selection = selection
  611. },
  612. },
  613. data() {
  614. return { selection: null, testData: getTestData(), fireCount: 0 }
  615. },
  616. })
  617. }
  618. it('toggleRowSelection', () => {
  619. const wrapper = createTable('selection-change')
  620. const vm = wrapper.vm
  621. vm.$refs.table.toggleRowSelection(vm.testData[0])
  622. expect(vm.selection.length).toEqual(1)
  623. expect(vm.fireCount).toEqual(1)
  624. // test use second parameter
  625. vm.$refs.table.toggleRowSelection(vm.testData[0])
  626. expect(vm.fireCount).toEqual(2)
  627. vm.$refs.table.toggleRowSelection(vm.testData[0], false)
  628. expect(vm.fireCount).toEqual(2)
  629. expect(vm.selection.length).toEqual(0)
  630. wrapper.unmount()
  631. })
  632. it('toggleAllSelection', async () => {
  633. const wrapper = createTable('selection-change')
  634. const vm = wrapper.vm
  635. vm.$refs.table.toggleAllSelection()
  636. await doubleWait()
  637. expect(vm.selection.length).toEqual(5)
  638. vm.$refs.table.toggleAllSelection()
  639. await doubleWait()
  640. expect(vm.selection.length).toEqual(0)
  641. wrapper.unmount()
  642. })
  643. it('clearSelection', () => {
  644. const wrapper = createTable('selection-change')
  645. const vm = wrapper.vm
  646. vm.$refs.table.toggleRowSelection(vm.testData[0])
  647. expect(vm.selection.length).toEqual(1)
  648. expect(vm.fireCount).toEqual(1)
  649. // clear selection
  650. vm.$refs.table.clearSelection()
  651. expect(vm.fireCount).toEqual(2)
  652. expect(vm.selection.length).toEqual(0)
  653. vm.$refs.table.clearSelection()
  654. expect(vm.fireCount).toEqual(2)
  655. wrapper.unmount()
  656. })
  657. it('sort', async () => {
  658. const wrapper = mount({
  659. components: {
  660. ElTableColumn,
  661. ElTable,
  662. },
  663. template: `
  664. <el-table ref="table" :data="testData" :default-sort = "{prop: 'runtime', order: 'ascending'}">
  665. <el-table-column prop="name" />
  666. <el-table-column prop="release" />
  667. <el-table-column prop="director" />
  668. <el-table-column prop="runtime"/>
  669. </el-table>
  670. `,
  671. data() {
  672. return { testData: getTestData() }
  673. },
  674. })
  675. const vm = wrapper.vm
  676. await doubleWait()
  677. const lastCells = wrapper.findAll(
  678. '.el-table__body-wrapper tbody tr td:last-child'
  679. )
  680. expect(lastCells.map((node) => node.text())).toEqual([
  681. '80',
  682. '92',
  683. '92',
  684. '95',
  685. '100',
  686. ])
  687. await doubleWait()
  688. vm.testData = vm.testData.map((data) =>
  689. Object.assign(data, { runtime: -data.runtime })
  690. )
  691. vm.$refs.table.sort('runtime', 'ascending')
  692. await doubleWait()
  693. expect(lastCells.map((node) => node.text())).toEqual([
  694. '-100',
  695. '-95',
  696. '-92',
  697. '-92',
  698. '-80',
  699. ])
  700. wrapper.unmount()
  701. })
  702. it('sort correct change icon', async () => {
  703. function assertSortIconCount($el, msg, count = 1) {
  704. const sortIconCount = $el.querySelectorAll(
  705. 'th.ascending, th.descending'
  706. ).length
  707. expect(sortIconCount).toEqual(count)
  708. }
  709. const wrapper = mount({
  710. components: {
  711. ElTable,
  712. ElTableColumn,
  713. },
  714. template: `
  715. <el-table ref="table" :data="testData" >
  716. <el-table-column prop="name" sortable />
  717. <el-table-column prop="release" sortable />
  718. <el-table-column prop="director" sortable />
  719. <el-table-column prop="runtime" sortable />
  720. </el-table>
  721. `,
  722. data() {
  723. return { testData: getTestData() }
  724. },
  725. })
  726. const vm = wrapper.vm
  727. await doubleWait()
  728. assertSortIconCount(
  729. wrapper.element,
  730. 'sorting icon is not empty after mount',
  731. 0
  732. )
  733. // manual click first column header
  734. const elm = wrapper.find('.caret-wrapper')
  735. elm.trigger('click')
  736. await doubleWait()
  737. assertSortIconCount(
  738. wrapper.element,
  739. 'sorting icon is not one after click header'
  740. )
  741. vm.$refs.table.sort('director', 'descending')
  742. await doubleWait()
  743. assertSortIconCount(
  744. wrapper.element,
  745. 'sorting icon is not one after call sort'
  746. )
  747. vm.$refs.table.sort('director', 'ascending')
  748. await doubleWait()
  749. assertSortIconCount(
  750. wrapper.element,
  751. 'sorting icon is not one after sort same column'
  752. )
  753. wrapper.unmount()
  754. })
  755. // https://github.com/element-plus/element-plus/issues/4589
  756. it('sort-change event', async () => {
  757. const handleSortChange = vi.fn()
  758. const wrapper = mount({
  759. components: {
  760. ElTable,
  761. ElTableColumn,
  762. },
  763. template: `
  764. <el-table :data="testData" @sort-change="handleSortChange">
  765. <el-table-column prop="name" />
  766. <el-table-column prop="release" />
  767. <el-table-column prop="director" />
  768. <el-table-column prop="runtime" sortable ref="runtime" />
  769. </el-table>
  770. `,
  771. data() {
  772. return { testData: getTestData() }
  773. },
  774. methods: {
  775. handleSortChange,
  776. },
  777. })
  778. await doubleWait()
  779. const elm = wrapper.find('.caret-wrapper')
  780. elm.trigger('click')
  781. expect(handleSortChange).toHaveBeenLastCalledWith({
  782. column: expect.any(Object),
  783. prop: 'runtime',
  784. order: 'ascending',
  785. })
  786. elm.trigger('click')
  787. expect(handleSortChange).toHaveBeenLastCalledWith({
  788. column: expect.any(Object),
  789. prop: 'runtime',
  790. order: 'descending',
  791. })
  792. elm.trigger('click')
  793. expect(handleSortChange).toHaveBeenLastCalledWith({
  794. column: expect.any(Object),
  795. prop: 'runtime',
  796. order: null,
  797. })
  798. })
  799. it('setCurrentRow', async () => {
  800. const wrapper = mount({
  801. components: {
  802. ElTable,
  803. ElTableColumn,
  804. },
  805. template: `
  806. <div>
  807. <el-table ref="table" :data="testData" highlight-current-row>
  808. <el-table-column prop="name" sortable />
  809. <el-table-column prop="release" sortable />
  810. <el-table-column prop="director" sortable />
  811. <el-table-column prop="runtime" sortable />
  812. </el-table>
  813. <button class="clear" @click="clear">clear</button>
  814. </div>
  815. `,
  816. data() {
  817. return { testData: getTestData() }
  818. },
  819. methods: {
  820. clear() {
  821. this.$refs.table.setCurrentRow()
  822. },
  823. },
  824. })
  825. const vm = wrapper.vm
  826. vm.$refs.table.setCurrentRow(vm.testData[1])
  827. await doubleWait()
  828. const secondRow = vm.$el.querySelectorAll('.el-table__row')[1]
  829. expect([...secondRow.classList]).toContain('current-row')
  830. vm.$el.querySelector('.clear').click()
  831. await doubleWait()
  832. expect([...secondRow.classList]).not.toContain('current-row')
  833. wrapper.unmount()
  834. })
  835. })
  836. it('hover', async () => {
  837. const wrapper = mount({
  838. components: {
  839. ElTable,
  840. ElTableColumn,
  841. },
  842. template: `
  843. <el-table :data="testData">
  844. <el-table-column prop="name" label="片名" fixed />
  845. <el-table-column prop="release" label="发行日期" />
  846. <el-table-column prop="director" label="导演" />
  847. <el-table-column prop="runtime" label="时长(分)" />
  848. </el-table>
  849. `,
  850. data() {
  851. return {
  852. testData: getTestData(),
  853. }
  854. },
  855. })
  856. await doubleWait()
  857. const tr = wrapper.find('.el-table__body-wrapper tbody tr')
  858. await tr.trigger('mouseenter')
  859. await doubleWait()
  860. await rAF()
  861. await doubleWait()
  862. expect(tr.classes()).toContain('hover-row')
  863. await tr.trigger('mouseleave')
  864. await doubleWait()
  865. await rAF()
  866. await doubleWait()
  867. expect(tr.classes()).not.toContain('hover-row')
  868. wrapper.unmount()
  869. })
  870. it('highlight-current-row', async () => {
  871. const wrapper = mount({
  872. components: {
  873. ElTable,
  874. ElTableColumn,
  875. },
  876. template: `
  877. <el-table :data="testData" highlight-current-row>
  878. <el-table-column prop="name" label="片名" />
  879. <el-table-column prop="release" label="发行日期" />
  880. <el-table-column prop="director" label="导演" />
  881. <el-table-column prop="runtime" label="时长(分)" sortable />
  882. </el-table>
  883. `,
  884. created() {
  885. this.testData = getTestData()
  886. },
  887. })
  888. const vm = wrapper.vm
  889. await doubleWait()
  890. const tr = vm.$el.querySelector('.el-table__body-wrapper tbody tr')
  891. triggerEvent(tr, 'click', true, false)
  892. await doubleWait()
  893. expect([...tr.classList]).toContain('current-row')
  894. let rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr')
  895. triggerEvent(rows[1], 'click', true, false)
  896. await doubleWait()
  897. expect([...tr.classList]).not.toContain('current-row')
  898. expect([...rows[1].classList]).toContain('current-row')
  899. const ths = vm.$el.querySelectorAll('.el-table__header-wrapper thead th')
  900. triggerEvent(ths[3], 'click', true, false)
  901. await doubleWait()
  902. rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr')
  903. expect([...rows[1].classList]).not.toContain('current-row')
  904. expect([...rows[3].classList]).toContain('current-row')
  905. wrapper.unmount()
  906. })
  907. it('keep highlight row when data change', async () => {
  908. const wrapper = mount({
  909. components: {
  910. ElTable,
  911. ElTableColumn,
  912. },
  913. template: `
  914. <el-table :data="testData" highlight-current-row row-key="release">
  915. <el-table-column prop="name" label="片名" />
  916. <el-table-column prop="release" label="发行日期" />
  917. <el-table-column prop="director" label="导演" />
  918. <el-table-column prop="runtime" label="时长(分)" sortable />
  919. </el-table>
  920. `,
  921. data() {
  922. return {
  923. testData: getTestData(),
  924. }
  925. },
  926. })
  927. const vm = wrapper.vm
  928. await doubleWait()
  929. let rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr')
  930. triggerEvent(rows[2], 'click', true, false)
  931. await doubleWait()
  932. expect([...rows[2].classList]).toContain('current-row')
  933. const data = getTestData()
  934. data.splice(0, 0, {
  935. id: 8,
  936. name: 'Monsters, Inc.',
  937. release: '2018-02-01',
  938. director: 'Peter Docter',
  939. runtime: 92,
  940. })
  941. data[2].name = 'Modified Name'
  942. vm.testData = data
  943. await doubleWait()
  944. rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr')
  945. expect([...rows[3].classList]).toContain('current-row')
  946. wrapper.unmount()
  947. })
  948. it('keep highlight row after sort', async () => {
  949. const wrapper = mount({
  950. components: {
  951. ElTable,
  952. ElTableColumn,
  953. },
  954. template: `
  955. <el-table :data="testData" row-key="release" highlight-current-row >
  956. <el-table-column prop="name" label="片名" />
  957. <el-table-column prop="release" label="发行日期" />
  958. <el-table-column prop="director" label="导演" />
  959. <el-table-column prop="runtime" label="时长(分)" sortable />
  960. </el-table>
  961. `,
  962. data() {
  963. return {
  964. testData: getTestData(),
  965. }
  966. },
  967. })
  968. const vm = wrapper.vm
  969. await doubleWait()
  970. const rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr')
  971. triggerEvent(rows[1], 'click', true, false)
  972. await doubleWait()
  973. expect([...rows[1].classList]).toContain('current-row')
  974. triggerEvent(rows[3], 'click', true, false)
  975. await doubleWait()
  976. expect([...rows[3].classList]).toContain('current-row')
  977. wrapper.unmount()
  978. })
  979. it('table append is visible in viewport if height is 100%', async () => {
  980. const wrapper = mount({
  981. components: {
  982. ElTable,
  983. ElTableColumn,
  984. },
  985. template: `
  986. <el-table :data="[]" height="100%">
  987. <el-table-column prop="name" label="片名" />
  988. <el-table-column prop="release" label="发行日期" />
  989. <el-table-column prop="director" label="导演" />
  990. <el-table-column prop="runtime" label="时长(分)" />
  991. <template #append>
  992. <div class="append-content" style="height: 48px;">
  993. append 区域始终出现在视图内
  994. </div>
  995. </template>
  996. </el-table>
  997. `,
  998. })
  999. await doubleWait()
  1000. const emptyBlockEl = wrapper.find('.el-table__empty-block')
  1001. expect(emptyBlockEl.attributes('style')).toContain('height: 100%')
  1002. wrapper.unmount()
  1003. })
  1004. describe('rowKey & index', () => {
  1005. it('key type is string', async () => {
  1006. const wrapper = mount({
  1007. components: {
  1008. ElTable,
  1009. ElTableColumn,
  1010. },
  1011. template: `
  1012. <el-table :data="testData" row-key="release" highlight-current-row >
  1013. <el-table-column type="index" />
  1014. <el-table-column prop="name" label="片名" />
  1015. <el-table-column prop="release" label="发行日期" />
  1016. <el-table-column prop="director" label="导演" />
  1017. <el-table-column prop="runtime" label="时长(分)" sortable />
  1018. </el-table>
  1019. `,
  1020. data() {
  1021. return {
  1022. testData: getTestData(),
  1023. }
  1024. },
  1025. })
  1026. await doubleWait()
  1027. const rows = wrapper.findAll('.el-table__row')
  1028. rows.forEach((row, index) => {
  1029. const cell = row.find('td')
  1030. expect(cell.text()).toMatch(`${index + 1}`)
  1031. })
  1032. })
  1033. it('with expand row', async () => {
  1034. const wrapper = mount({
  1035. components: {
  1036. ElTable,
  1037. ElTableColumn,
  1038. },
  1039. template: `
  1040. <el-table :data="testData" row-key="release" highlight-current-row >
  1041. <el-table-column type="index" />
  1042. <el-table-column type="expand">
  1043. <template #default="props">
  1044. <span class="index">{{ props.$index }}</span>
  1045. <span class="director">{{ props.row.director }}</span>
  1046. </template>
  1047. </el-table-column>
  1048. <el-table-column prop="name" label="片名" />
  1049. <el-table-column prop="release" label="发行日期" />
  1050. <el-table-column prop="director" label="导演" />
  1051. <el-table-column prop="runtime" label="时长(分)" sortable />
  1052. </el-table>
  1053. `,
  1054. data() {
  1055. return {
  1056. testData: getTestData(),
  1057. }
  1058. },
  1059. })
  1060. await doubleWait()
  1061. const rows = wrapper.findAll('.el-table__row')
  1062. rows.forEach((row, index) => {
  1063. const cell = row.find('td')
  1064. expect(cell.text()).toMatch(`${index + 1}`)
  1065. })
  1066. let index = 0
  1067. for (const row of rows) {
  1068. const expandCell = row.findAll('td')[1]
  1069. const triggerIcon = expandCell.find('.el-table__expand-icon')
  1070. triggerIcon.trigger('click')
  1071. await doubleWait()
  1072. const cell = row.find('td')
  1073. expect(cell.text()).toMatch(`${++index}`)
  1074. triggerIcon.trigger('click')
  1075. await doubleWait()
  1076. }
  1077. })
  1078. })
  1079. describe('tree', () => {
  1080. let wrapper: VueWrapper<ComponentPublicInstance>
  1081. afterEach(() => wrapper?.unmount())
  1082. it('render tree structural data', async () => {
  1083. wrapper = mount({
  1084. components: {
  1085. ElTableColumn,
  1086. ElTable,
  1087. },
  1088. template: `
  1089. <el-table :data="testData" row-key="release">
  1090. <el-table-column prop="name" label="片名" />
  1091. <el-table-column prop="release" label="发行日期" />
  1092. <el-table-column prop="director" label="导演" />
  1093. <el-table-column prop="runtime" label="时长(分)" />
  1094. </el-table>
  1095. `,
  1096. data() {
  1097. const testData = getTestData() as any
  1098. testData[1].children = [
  1099. {
  1100. name: "A Bug's Life copy 1",
  1101. release: '1998-11-25-1',
  1102. director: 'John Lasseter',
  1103. runtime: 95,
  1104. },
  1105. {
  1106. name: "A Bug's Life copy 2",
  1107. release: '1998-11-25-2',
  1108. director: 'John Lasseter',
  1109. runtime: 95,
  1110. },
  1111. ]
  1112. return {
  1113. testData,
  1114. }
  1115. },
  1116. })
  1117. await doubleWait()
  1118. const rows = wrapper.findAll('.el-table__row')
  1119. expect(rows.length).toEqual(7)
  1120. // validate placeholder
  1121. expect(wrapper.findAll('.el-table__placeholder').length).toBe(6)
  1122. const childRows = wrapper.findAll('.el-table__row--level-1')
  1123. expect(childRows.length).toEqual(2)
  1124. childRows.forEach((item) => {
  1125. expect(item.attributes('style')).toContain('display: none')
  1126. })
  1127. wrapper.find('.el-table__expand-icon').trigger('click')
  1128. await doubleWait()
  1129. childRows.forEach((item) => {
  1130. expect(item.attributes('style')).toEqual('')
  1131. })
  1132. })
  1133. it('load substree row data', async () => {
  1134. wrapper = mount({
  1135. components: {
  1136. ElTable,
  1137. ElTableColumn,
  1138. },
  1139. template: `
  1140. <el-table :data="testData" row-key="release" lazy :load="load">
  1141. <el-table-column prop="name" label="片名" />
  1142. <el-table-column prop="release" label="发行日期" />
  1143. <el-table-column prop="director" label="导演" />
  1144. <el-table-column prop="runtime" label="时长(分)" />
  1145. </el-table>
  1146. `,
  1147. data() {
  1148. const testData = getTestData() as any
  1149. testData[testData.length - 1].children = [
  1150. {
  1151. name: "A Bug's Life copy 1",
  1152. release: '2008-1-25-1',
  1153. director: 'John Lasseter',
  1154. runtime: 95,
  1155. },
  1156. ]
  1157. testData[1].hasChildren = true
  1158. return {
  1159. testData,
  1160. }
  1161. },
  1162. methods: {
  1163. load(row, treeNode, resolve) {
  1164. resolve([
  1165. {
  1166. name: "A Bug's Life copy 1",
  1167. release: '1998-11-25-1',
  1168. director: 'John Lasseter',
  1169. runtime: 95,
  1170. },
  1171. {
  1172. name: "A Bug's Life copy 2",
  1173. release: '1998-11-25-2',
  1174. director: 'John Lasseter',
  1175. runtime: 95,
  1176. },
  1177. ])
  1178. },
  1179. },
  1180. })
  1181. await doubleWait()
  1182. const expandIcon = wrapper.find('.el-table__expand-icon')
  1183. expandIcon.trigger('click')
  1184. await doubleWait()
  1185. expect(expandIcon.classes()).toContain('el-table__expand-icon--expanded')
  1186. expect(wrapper.findAll('.el-table__row').length).toEqual(8)
  1187. })
  1188. it('tree-props & default-expand-all & expand-change', async () => {
  1189. const spy = vi.fn()
  1190. wrapper = mount({
  1191. components: {
  1192. ElTable,
  1193. ElTableColumn,
  1194. },
  1195. template: `
  1196. <el-table
  1197. :data="testData" lazy default-expand-all row-key="release" :tree-props="{children: 'childrenTest', hasChildren: 'hasChildrenTest'}"
  1198. :load="load" @expand-change="change">
  1199. <el-table-column prop="name" label="片名" />
  1200. <el-table-column prop="release" label="发行日期" />
  1201. <el-table-column prop="director" label="导演" />
  1202. <el-table-column prop="runtime" label="时长(分)" />
  1203. </el-table>
  1204. `,
  1205. data() {
  1206. const testData = getTestData() as any
  1207. testData[testData.length - 1].childrenTest = [
  1208. {
  1209. name: "A Bug's Life copy 1",
  1210. release: '2008-1-25-1',
  1211. director: 'John Lasseter',
  1212. runtime: 95,
  1213. },
  1214. ]
  1215. testData[1].hasChildrenTest = true
  1216. return {
  1217. testData,
  1218. }
  1219. },
  1220. methods: {
  1221. load(row, treeNode, resolve) {
  1222. resolve([
  1223. {
  1224. name: "A Bug's Life copy 1",
  1225. release: '1998-11-25-1',
  1226. director: 'John Lasseter',
  1227. runtime: 95,
  1228. },
  1229. {
  1230. name: "A Bug's Life copy 2",
  1231. release: '1998-11-25-2',
  1232. director: 'John Lasseter',
  1233. runtime: 95,
  1234. },
  1235. ])
  1236. },
  1237. change: spy,
  1238. },
  1239. })
  1240. await doubleWait()
  1241. const childRows = wrapper.findAll('.el-table__row--level-1')
  1242. childRows.forEach((item) => {
  1243. expect(item.attributes('style')).toBeUndefined()
  1244. })
  1245. const expandIcon = wrapper.find('.el-table__expand-icon')
  1246. expandIcon.trigger('click')
  1247. await doubleWait()
  1248. expect(
  1249. expandIcon.classes().includes('el-table__expand-icon--expanded')
  1250. ).toBeTruthy()
  1251. expect(wrapper.findAll('.el-table__row').length).toEqual(8)
  1252. expect(spy.mock.calls[0][0]).toBeInstanceOf(Object)
  1253. expect(spy.mock.calls[0][1]).toBeTruthy()
  1254. })
  1255. it('expand-row-keys & toggleRowExpansion', async () => {
  1256. wrapper = mount({
  1257. components: {
  1258. ElTable,
  1259. ElTableColumn,
  1260. },
  1261. template: `
  1262. <el-table :data="testData" row-key="release" lazy :load="load" :expand-row-keys="['2003-5-30']" ref="table">
  1263. <el-table-column prop="name" label="片名" />
  1264. <el-table-column prop="release" label="发行日期" />
  1265. <el-table-column prop="director" label="导演" />
  1266. <el-table-column prop="runtime" label="时长(分)" />
  1267. </el-table>
  1268. `,
  1269. data() {
  1270. const testData = getTestData() as any
  1271. testData[testData.length - 1].children = [
  1272. {
  1273. name: "A Bug's Life copy 1",
  1274. release: '2003-5-30-1',
  1275. director: 'John Lasseter',
  1276. runtime: 95,
  1277. hasChildren: true,
  1278. },
  1279. ]
  1280. return {
  1281. testData,
  1282. }
  1283. },
  1284. methods: {
  1285. load(row, treeNode, resolve) {
  1286. resolve([
  1287. {
  1288. name: "A Bug's Life copy 1",
  1289. release: '2003-5-30-2',
  1290. director: 'John Lasseter',
  1291. runtime: 95,
  1292. },
  1293. ])
  1294. },
  1295. closeExpandRow() {
  1296. const testData = this.testData
  1297. const row = testData[testData.length - 1].children[0]
  1298. this.$refs.table.toggleRowExpansion(row)
  1299. },
  1300. },
  1301. })
  1302. await doubleWait()
  1303. const childRows = wrapper.findAll('.el-table__row--level-1')
  1304. childRows.forEach((item) => {
  1305. expect(item.attributes('style')).toBeUndefined()
  1306. })
  1307. const expandIcon = childRows[0].find('.el-table__expand-icon')
  1308. expandIcon.trigger('click')
  1309. await doubleWait()
  1310. expect(expandIcon.classes()).toContain('el-table__expand-icon--expanded')
  1311. ;(wrapper.vm as any).closeExpandRow()
  1312. await doubleWait()
  1313. expect(expandIcon.classes()).not.toContain(
  1314. 'el-table__expand-icon--expanded'
  1315. )
  1316. })
  1317. it('v-if on el-table-column should patch correctly', async () => {
  1318. wrapper = mount({
  1319. components: {
  1320. ElTable,
  1321. ElTableColumn,
  1322. },
  1323. template: `
  1324. <div>
  1325. <button @click="hideName">hide name column</button>
  1326. <el-table :data="testData">
  1327. <el-table-column key="name" label="片名" v-if="showName">
  1328. <template #default="{ row }"><span class="name">{{ row.name }}</span></template>
  1329. </el-table-column>
  1330. <el-table-column key="release" label="发行日期" >
  1331. <template #default="{ row }"><span class="release">{{ row.release }}</span></template>
  1332. </el-table-column>
  1333. </el-table>
  1334. </div>
  1335. `,
  1336. data() {
  1337. return {
  1338. testData: getTestData() as any,
  1339. showName: true,
  1340. }
  1341. },
  1342. methods: {
  1343. hideName() {
  1344. this.showName = false
  1345. },
  1346. },
  1347. })
  1348. await doubleWait()
  1349. const firstCellSpanBeforeHide = wrapper.find('.el-table__body tr td span')
  1350. expect(firstCellSpanBeforeHide.classes().includes('name')).toBeTruthy()
  1351. wrapper.find('button').trigger('click')
  1352. await doubleWait()
  1353. const firstCellSpanAfterHide = wrapper.find('.el-table__body tr td span')
  1354. expect(firstCellSpanAfterHide.classes().includes('release')).toBeTruthy()
  1355. })
  1356. })
  1357. it('when tableLayout is auto', async () => {
  1358. const wrapper = mount({
  1359. components: {
  1360. ElTable,
  1361. ElTableColumn,
  1362. },
  1363. template: `
  1364. <el-table :data="testData" table-layout="auto">
  1365. <el-table-column prop="id" />
  1366. <el-table-column prop="name" label="片名" />
  1367. <el-table-column prop="release" label="发行日期" />
  1368. <el-table-column prop="director" label="导演" />
  1369. <el-table-column prop="runtime" label="时长(分)" />
  1370. </el-table>
  1371. `,
  1372. created() {
  1373. this.testData = getTestData()
  1374. },
  1375. })
  1376. await doubleWait()
  1377. expect(wrapper.find('.el-table__body thead').exists()).toBeTruthy()
  1378. expect(wrapper.find('.el-table__body colgroup col').exists()).toBeFalsy()
  1379. expect(wrapper.find('.el-table__body tbody').exists()).toBeTruthy()
  1380. })
  1381. it('automatic minimum size of flex-items', async () => {
  1382. const wrapper = mount({
  1383. components: {
  1384. ElTable,
  1385. ElTableColumn,
  1386. },
  1387. template: `
  1388. <div class="right">
  1389. <el-table flexible :data="testData" table-layout="auto">
  1390. <el-table-column prop="id" />
  1391. <el-table-column prop="name" label="片名" />
  1392. <el-table-column prop="release" label="发行日期" />
  1393. <el-table-column prop="director" label="导演" />
  1394. <el-table-column prop="runtime" label="时长(分)" />
  1395. </el-table>
  1396. </div>
  1397. `,
  1398. created() {
  1399. this.testData = getTestData()
  1400. },
  1401. })
  1402. await nextTick()
  1403. expect(wrapper.find('.right').element.getAttribute('style')).toContain(
  1404. 'min-width: 0'
  1405. )
  1406. })
  1407. it('selectable tree', async () => {
  1408. const wrapper = mount({
  1409. components: {
  1410. ElTable,
  1411. ElTableColumn,
  1412. },
  1413. template: `
  1414. <el-table :data="testData" @selection-change="change">
  1415. <el-table-column type="selection" />
  1416. <el-table-column prop="name" label="name" />
  1417. <el-table-column prop="release" label="release" />
  1418. <el-table-column prop="director" label="director" />
  1419. <el-table-column prop="runtime" label="runtime" />
  1420. </el-table>
  1421. `,
  1422. data() {
  1423. const testData = getTestData() as any
  1424. testData[1].children = [
  1425. {
  1426. name: "A Bug's Life copy 1",
  1427. release: '1998-11-25-1',
  1428. director: 'John Lasseter',
  1429. runtime: 95,
  1430. },
  1431. {
  1432. name: "A Bug's Life copy 2",
  1433. release: '1998-11-25-2',
  1434. director: 'John Lasseter',
  1435. runtime: 95,
  1436. },
  1437. ]
  1438. return {
  1439. testData,
  1440. selected: [],
  1441. }
  1442. },
  1443. methods: {
  1444. change(rows) {
  1445. this.selected = rows
  1446. },
  1447. },
  1448. })
  1449. await doubleWait()
  1450. wrapper.findAll('.el-checkbox')[2].trigger('click')
  1451. await doubleWait()
  1452. expect(wrapper.vm.selected.length).toEqual(3)
  1453. })
  1454. it('change columns order when use v-for & key to render table', async () => {
  1455. const wrapper = mount({
  1456. components: {
  1457. ElTable,
  1458. ElTableColumn,
  1459. },
  1460. template: `
  1461. <button class="change-column" @click="changeColumnData"></button>
  1462. <el-table :data="testData">
  1463. <el-table-column
  1464. v-for="item in columnsData"
  1465. :prop="item.prop"
  1466. :label="item.label"
  1467. :key="item.prop" />
  1468. </el-table>
  1469. `,
  1470. data() {
  1471. const testData = getTestData() as any
  1472. return {
  1473. testData,
  1474. columnsData: [
  1475. { label: 'name', prop: 'name' },
  1476. { label: 'release', prop: 'release' },
  1477. { label: 'director', prop: 'director' },
  1478. { label: 'runtime', prop: 'runtime' },
  1479. ],
  1480. }
  1481. },
  1482. methods: {
  1483. changeColumnData() {
  1484. ;[this.columnsData[0], this.columnsData[1]] = [
  1485. this.columnsData[1],
  1486. this.columnsData[0],
  1487. ]
  1488. },
  1489. },
  1490. })
  1491. await doubleWait()
  1492. wrapper.find('.change-column').trigger('click')
  1493. await doubleWait()
  1494. expect(wrapper.find('.el-table__header').findAll('.cell')[0].text()).toBe(
  1495. 'release'
  1496. )
  1497. expect(wrapper.find('.el-table__header').findAll('.cell')[1].text()).toBe(
  1498. 'name'
  1499. )
  1500. })
  1501. })