tree.test.ts 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425
  1. // @ts-nocheck
  2. import { nextTick } from 'vue'
  3. import { mount } from '@vue/test-utils'
  4. import { describe, expect, test, vi } from 'vitest'
  5. import defineGetter from '@element-plus/test-utils/define-getter'
  6. import Tree from '../src/tree.vue'
  7. import type Node from '../src/model/node'
  8. const ALL_NODE_COUNT = 9
  9. const getTreeVm = (props = '', options = {}) => {
  10. const wrapper = mount(
  11. Object.assign(
  12. {
  13. components: {
  14. 'el-tree': Tree,
  15. },
  16. template: `
  17. <el-tree ref="tree" :data="data" ${props}></el-tree>
  18. `,
  19. data() {
  20. return {
  21. currentNode: null,
  22. nodeExpended: false,
  23. defaultExpandedKeys: [],
  24. defaultCheckedKeys: [],
  25. clickedNode: null,
  26. count: 1,
  27. data: [
  28. {
  29. id: 1,
  30. label: '一级 1',
  31. children: [
  32. {
  33. id: 11,
  34. label: '二级 1-1',
  35. children: [
  36. {
  37. id: 111,
  38. label: '三级 1-1',
  39. },
  40. ],
  41. },
  42. ],
  43. },
  44. {
  45. id: 2,
  46. label: '一级 2',
  47. children: [
  48. {
  49. id: 21,
  50. label: '二级 2-1',
  51. },
  52. {
  53. id: 22,
  54. label: '二级 2-2',
  55. },
  56. ],
  57. },
  58. {
  59. id: 3,
  60. label: '一级 3',
  61. children: [
  62. {
  63. id: 31,
  64. label: '二级 3-1',
  65. },
  66. {
  67. id: 32,
  68. label: '二级 3-2',
  69. },
  70. ],
  71. },
  72. ],
  73. defaultProps: {
  74. children: 'children',
  75. label: 'label',
  76. },
  77. }
  78. },
  79. },
  80. options
  81. )
  82. )
  83. return { wrapper, vm: wrapper.vm }
  84. }
  85. const getDisableTreeVm = (props = '', options = {}) => {
  86. const wrapper = mount(
  87. Object.assign(
  88. {
  89. components: {
  90. 'el-tree': Tree,
  91. },
  92. template: `
  93. <el-tree ref="tree" :data="data" ${props}></el-tree>
  94. `,
  95. data() {
  96. return {
  97. defaultExpandedKeys: [],
  98. defaultCheckedKeys: [],
  99. clickedNode: null,
  100. count: 1,
  101. data: [
  102. {
  103. id: 1,
  104. label: '一级 1',
  105. children: [
  106. {
  107. id: 11,
  108. label: '二级 1-1',
  109. children: [
  110. {
  111. id: 111,
  112. label: '三级 1-1',
  113. disabled: true,
  114. },
  115. ],
  116. },
  117. ],
  118. },
  119. {
  120. id: 2,
  121. label: '一级 2',
  122. children: [
  123. {
  124. id: 21,
  125. label: '二级 2-1',
  126. },
  127. {
  128. id: 22,
  129. label: '二级 2-2',
  130. },
  131. ],
  132. },
  133. {
  134. id: 3,
  135. label: '一级 3',
  136. children: [
  137. {
  138. id: 31,
  139. label: '二级 3-1',
  140. },
  141. {
  142. id: 32,
  143. label: '二级 3-2',
  144. },
  145. ],
  146. },
  147. ],
  148. defaultProps: {
  149. children: 'children',
  150. label: 'label',
  151. disabled: 'disabled',
  152. },
  153. }
  154. },
  155. },
  156. options
  157. )
  158. )
  159. return { wrapper, vm: wrapper.vm }
  160. }
  161. describe('Tree.vue', () => {
  162. test('create', async () => {
  163. const { wrapper, vm } = getTreeVm(
  164. `:props="defaultProps" default-expand-all`
  165. )
  166. expect(wrapper.find('.el-tree').exists()).toBeTruthy()
  167. expect(wrapper.findAll('.el-tree > .el-tree-node').length).toEqual(3)
  168. expect(wrapper.findAll('.el-tree .el-tree-node').length).toEqual(
  169. ALL_NODE_COUNT
  170. )
  171. vm.data[1].children = [{ label: '二级 2-1' }] as any
  172. await nextTick()
  173. expect(wrapper.findAll('.el-tree .el-tree-node').length).toEqual(
  174. ALL_NODE_COUNT - 1
  175. )
  176. })
  177. test('click node', async () => {
  178. const { wrapper, vm } = getTreeVm(
  179. `:props="defaultProps" @node-click="handleNodeClick"`,
  180. {
  181. methods: {
  182. handleNodeClick(data) {
  183. this.clickedNode = data
  184. },
  185. },
  186. }
  187. )
  188. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  189. const firstNodeWrapper = wrapper.find('.el-tree-node')
  190. await firstNodeContentWrapper.trigger('click')
  191. await nextTick() // because node click method to expaned is async
  192. expect(vm.clickedNode.label).toEqual('一级 1')
  193. expect(firstNodeWrapper.classes('is-expanded')).toBe(true)
  194. expect(firstNodeWrapper.classes('is-current')).toBe(true)
  195. await firstNodeContentWrapper.trigger('click')
  196. await nextTick() // because node click method to expaned is async
  197. expect(firstNodeWrapper.classes('is-expanded')).toBe(false)
  198. expect(firstNodeWrapper.classes('is-current')).toBe(true)
  199. })
  200. test('emptyText', async () => {
  201. const { wrapper, vm } = getTreeVm(`:props="defaultProps"`)
  202. vm.data = []
  203. await nextTick()
  204. expect(wrapper.findAll('.el-tree__empty-block').length).toEqual(1)
  205. })
  206. test('expandOnNodeClick', async () => {
  207. const { wrapper } = getTreeVm(
  208. `:props="defaultProps" :expand-on-click-node="false"`
  209. )
  210. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  211. const firstNodeWrapper = wrapper.find('.el-tree-node')
  212. await firstNodeContentWrapper.trigger('click')
  213. await nextTick() // because node click method to expaned is async
  214. expect(firstNodeWrapper.classes('is-expanded')).toBe(false)
  215. })
  216. test('checkOnNodeClick', async () => {
  217. const { wrapper } = getTreeVm(
  218. `:props="defaultProps" node-key="id" show-checkbox check-on-click-node`
  219. )
  220. const treeWrapper = wrapper.findComponent(Tree)
  221. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  222. await firstNodeContentWrapper.trigger('click')
  223. expect(
  224. (treeWrapper.vm as InstanceType<typeof Tree>).getCheckedKeys()
  225. ).toEqual([1, 11, 111])
  226. })
  227. test('current-node-key', async () => {
  228. const { wrapper } = getTreeVm(
  229. `:props="defaultProps" default-expand-all highlight-current node-key="id" :current-node-key="11"`
  230. )
  231. const currentNodeLabelWrapper = wrapper.find(
  232. '.is-current .el-tree-node__label'
  233. )
  234. expect(currentNodeLabelWrapper.text()).toEqual('二级 1-1')
  235. expect(wrapper.find('.el-tree--highlight-current').exists()).toBe(true)
  236. })
  237. test('defaultExpandAll', async () => {
  238. const { wrapper } = getTreeVm(`:props="defaultProps" default-expand-all`)
  239. const expanedNodeWrappers = wrapper.findAll('.el-tree-node.is-expanded')
  240. expect(expanedNodeWrappers.length).toEqual(ALL_NODE_COUNT)
  241. })
  242. test('defaultExpandedKeys', async () => {
  243. const { wrapper } = getTreeVm(
  244. `:props="defaultProps" :default-expanded-keys="defaultExpandedKeys" node-key="id"`,
  245. {
  246. created() {
  247. this.defaultExpandedKeys = [1, 3]
  248. },
  249. }
  250. )
  251. const expanedNodeWrappers = wrapper.findAll('.el-tree-node.is-expanded')
  252. expect(expanedNodeWrappers.length).toEqual(2)
  253. })
  254. test('defaultExpandedKeys set', async () => {
  255. const { wrapper, vm } = getTreeVm(
  256. `:props="defaultProps" :default-expanded-keys="defaultExpandedKeys" node-key="id"`,
  257. {
  258. created() {
  259. this.defaultExpandedKeys = [1, 3]
  260. },
  261. }
  262. )
  263. await nextTick()
  264. let expanedNodeWrappers = wrapper.findAll('.el-tree-node.is-expanded')
  265. expect(expanedNodeWrappers.length).toEqual(2)
  266. vm.defaultExpandedKeys = [2]
  267. await nextTick()
  268. await nextTick()
  269. vm.data = [
  270. {
  271. id: 4,
  272. label: 'L1 4',
  273. children: [],
  274. },
  275. ...JSON.parse(JSON.stringify(vm.data)),
  276. ]
  277. await nextTick()
  278. await nextTick()
  279. await nextTick()
  280. expanedNodeWrappers = wrapper.findAll('.el-tree-node.is-expanded')
  281. expect(expanedNodeWrappers.length).toEqual(1)
  282. })
  283. test('filter-node-method', async () => {
  284. const { wrapper } = getTreeVm(
  285. `:props="defaultProps" :filter-node-method="filterNode"`,
  286. {
  287. methods: {
  288. filterNode(value, data) {
  289. if (!value) return true
  290. return data.label.includes(value)
  291. },
  292. },
  293. }
  294. )
  295. const treeWrapper = wrapper.findComponent(Tree)
  296. ;(treeWrapper.vm as InstanceType<typeof Tree>).filter('2-1')
  297. await nextTick()
  298. expect(treeWrapper.findAll('.el-tree-node.is-hidden').length).toEqual(3)
  299. })
  300. test('autoExpandParent = true', async () => {
  301. const { wrapper } = getTreeVm(
  302. `:props="defaultProps" :default-expanded-keys="defaultExpandedKeys" node-key="id"`,
  303. {
  304. created() {
  305. this.defaultExpandedKeys = [111]
  306. },
  307. }
  308. )
  309. expect(wrapper.findAll('.el-tree-node.is-expanded').length).toEqual(3)
  310. })
  311. test('autoExpandParent = false', async () => {
  312. const { wrapper } = getTreeVm(
  313. `:props="defaultProps" :default-expanded-keys="defaultExpandedKeys" node-key="id" :auto-expand-parent="false"`,
  314. {
  315. created() {
  316. this.defaultExpandedKeys = [11]
  317. },
  318. }
  319. )
  320. expect(wrapper.findAll('.el-tree-node.is-expanded').length).toEqual(0)
  321. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  322. await firstNodeContentWrapper.trigger('click')
  323. await nextTick()
  324. expect(wrapper.findAll('.el-tree-node.is-expanded').length).toEqual(2)
  325. })
  326. test('defaultCheckedKeys & check-strictly = false', async () => {
  327. const { wrapper } = getTreeVm(
  328. `:props="defaultProps" default-expand-all show-checkbox :default-checked-keys="defaultCheckedKeys" node-key="id"`,
  329. {
  330. created() {
  331. this.defaultCheckedKeys = [1]
  332. },
  333. }
  334. )
  335. expect(wrapper.findAll('.el-checkbox .is-checked').length).toEqual(3)
  336. })
  337. test('defaultCheckedKeys & check-strictly', async () => {
  338. const { wrapper } = getTreeVm(
  339. `:props="defaultProps" default-expand-all show-checkbox :default-checked-keys="defaultCheckedKeys" node-key="id" check-strictly`,
  340. {
  341. created() {
  342. this.defaultCheckedKeys = [1]
  343. },
  344. }
  345. )
  346. expect(wrapper.findAll('.el-checkbox .is-checked').length).toEqual(1)
  347. })
  348. test('show checkbox', async () => {
  349. const { wrapper } = getTreeVm(`:props="defaultProps" show-checkbox`)
  350. const treeWrapper = wrapper.findComponent(Tree)
  351. const treeVm = treeWrapper.vm as InstanceType<typeof Tree>
  352. const secondNodeContentWrapper = treeWrapper.findAll(
  353. '.el-tree-node__content'
  354. )[1]
  355. const secondNodeCheckboxWrapper =
  356. secondNodeContentWrapper.find('.el-checkbox')
  357. const secondNodeExpandIconWrapper = secondNodeContentWrapper.find(
  358. '.el-tree-node__expand-icon'
  359. )
  360. expect(secondNodeCheckboxWrapper.exists()).toBe(true)
  361. await secondNodeCheckboxWrapper.trigger('click')
  362. expect(treeVm.getCheckedNodes().length).toEqual(3)
  363. expect(treeVm.getCheckedNodes(true).length).toEqual(2)
  364. await secondNodeExpandIconWrapper.trigger('click')
  365. await nextTick()
  366. const secondTreeNodeWrapper = treeWrapper.findAll('.el-tree-node')[1]
  367. const secondNodefirstLeafCheckboxWrapper = secondTreeNodeWrapper.find(
  368. '.el-tree-node__children .el-tree-node__content .el-checkbox'
  369. )
  370. await secondNodefirstLeafCheckboxWrapper.trigger('click')
  371. expect(treeVm.getCheckedNodes().length).toEqual(1)
  372. })
  373. test('check', async () => {
  374. const handleCheckMockFunction = vi.fn()
  375. const { wrapper } = getTreeVm(
  376. `:props="defaultProps" show-checkbox @check="handleCheck"`,
  377. {
  378. methods: {
  379. handleCheck: handleCheckMockFunction,
  380. },
  381. }
  382. )
  383. const secondNodeContentWrapper = wrapper.findAll(
  384. '.el-tree-node__content'
  385. )[1]
  386. const secondNodeCheckboxWrapper =
  387. secondNodeContentWrapper.find('.el-checkbox')
  388. expect(secondNodeCheckboxWrapper.exists()).toBe(true)
  389. await secondNodeCheckboxWrapper.trigger('click')
  390. await nextTick()
  391. expect(handleCheckMockFunction.mock.calls.length).toBe(1)
  392. const [data, args] = handleCheckMockFunction.mock.calls[0]
  393. expect(data.id).toEqual(2)
  394. expect(args.checkedNodes.length).toEqual(3)
  395. })
  396. test('setCheckedNodes', async () => {
  397. const { wrapper } = getTreeVm(
  398. `:props="defaultProps" show-checkbox node-key="id"`
  399. )
  400. const treeWrapper = wrapper.findComponent(Tree)
  401. const treeVm = treeWrapper.vm as InstanceType<typeof Tree>
  402. const secondNodeContentWrapper = wrapper.findAll(
  403. '.el-tree-node__content'
  404. )[1]
  405. const secondNodeCheckWrapper = secondNodeContentWrapper.find('.el-checkbox')
  406. await secondNodeCheckWrapper.trigger('click')
  407. expect(treeVm.getCheckedNodes().length).toEqual(3)
  408. expect(treeVm.getCheckedNodes(true).length).toEqual(2)
  409. treeVm.setCheckedNodes([])
  410. expect(treeVm.getCheckedNodes().length).toEqual(0)
  411. })
  412. test('setCheckedKeys', async () => {
  413. const { wrapper } = getTreeVm(
  414. `:props="defaultProps" show-checkbox node-key="id"`
  415. )
  416. const treeWrapper = wrapper.findComponent(Tree)
  417. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  418. tree.setCheckedKeys([111])
  419. expect(tree.getCheckedNodes().length).toEqual(3)
  420. expect(tree.getCheckedKeys().length).toEqual(3)
  421. tree.setCheckedKeys([1])
  422. expect(tree.getCheckedNodes().length).toEqual(3)
  423. expect(tree.getCheckedKeys().length).toEqual(3)
  424. tree.setCheckedKeys([2])
  425. expect(tree.getCheckedNodes().length).toEqual(3)
  426. expect(tree.getCheckedKeys().length).toEqual(3)
  427. tree.setCheckedKeys([21])
  428. expect(tree.getCheckedNodes().length).toEqual(1)
  429. expect(tree.getCheckedKeys().length).toEqual(1)
  430. })
  431. test('setCheckedKeys with checkStrictly', async () => {
  432. const { wrapper } = getTreeVm(
  433. `:props="defaultProps" checkStrictly show-checkbox node-key="id"`
  434. )
  435. const treeWrapper = wrapper.findComponent(Tree)
  436. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  437. tree.setCheckedKeys([111])
  438. expect(tree.getCheckedNodes().length).toEqual(1)
  439. expect(tree.getCheckedKeys().length).toEqual(1)
  440. tree.setCheckedKeys([1])
  441. expect(tree.getCheckedNodes().length).toEqual(1)
  442. expect(tree.getCheckedKeys().length).toEqual(1)
  443. tree.setCheckedKeys([2])
  444. expect(tree.getCheckedNodes().length).toEqual(1)
  445. expect(tree.getCheckedKeys().length).toEqual(1)
  446. tree.setCheckedKeys([21, 22])
  447. expect(tree.getCheckedNodes().length).toEqual(2)
  448. expect(tree.getCheckedKeys().length).toEqual(2)
  449. })
  450. test('method setChecked', async () => {
  451. const { wrapper } = getTreeVm(
  452. `:props="defaultProps" show-checkbox node-key="id"`
  453. )
  454. const treeWrapper = wrapper.findComponent(Tree)
  455. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  456. tree.setChecked(111, true, true)
  457. expect(tree.getCheckedNodes().length).toEqual(3)
  458. expect(tree.getCheckedKeys().length).toEqual(3)
  459. tree.setChecked(tree.data[0], false, true)
  460. expect(tree.getCheckedNodes().length).toEqual(0)
  461. expect(tree.getCheckedKeys().length).toEqual(0)
  462. })
  463. 69
  464. test('setCheckedKeys with leafOnly=false', async () => {
  465. const { wrapper } = getTreeVm(
  466. `:props="defaultProps" show-checkbox node-key="id"`
  467. )
  468. const treeWrapper = wrapper.findComponent(Tree)
  469. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  470. tree.setCheckedKeys([1, 11, 111, 2], false)
  471. expect(tree.getCheckedNodes().length).toEqual(6)
  472. expect(tree.getCheckedKeys().length).toEqual(6)
  473. })
  474. test('setCheckedKeys with leafOnly=true', async () => {
  475. const { wrapper } = getTreeVm(
  476. `:props="defaultProps" show-checkbox node-key="id"`
  477. )
  478. const treeWrapper = wrapper.findComponent(Tree)
  479. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  480. tree.setCheckedKeys([2], true)
  481. expect(tree.getCheckedNodes().length).toEqual(2)
  482. expect(tree.getCheckedKeys().length).toEqual(2)
  483. })
  484. test('setCurrentKey', async () => {
  485. const { wrapper } = getTreeVm(
  486. `:props="defaultProps" show-checkbox node-key="id"`
  487. )
  488. const treeWrapper = wrapper.findComponent(Tree)
  489. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  490. tree.setCurrentKey(111)
  491. expect(tree.store.currentNode.data.id).toEqual(111)
  492. tree.setCurrentKey(null)
  493. expect(tree.store.currentNode).toEqual(null)
  494. })
  495. test('setCurrentKey should also auto expand parent', async () => {
  496. const { wrapper } = getTreeVm(
  497. `:props="defaultProps" show-checkbox node-key="id"`
  498. )
  499. const treeWrapper = wrapper.findComponent(Tree)
  500. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  501. tree.setCurrentKey(111)
  502. await nextTick()
  503. expect(wrapper.find('.is-current').exists()).toBeTruthy()
  504. tree.setCurrentKey(null)
  505. await nextTick()
  506. expect(wrapper.find('.is-current').exists()).toBeFalsy()
  507. })
  508. test('setCurrentKey should not expand self', async () => {
  509. const { wrapper } = getTreeVm(
  510. `:props="defaultProps" show-checkbox node-key="id"`
  511. )
  512. const treeWrapper = wrapper.findComponent(Tree)
  513. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  514. tree.setCurrentKey(1)
  515. await nextTick()
  516. await nextTick()
  517. await nextTick()
  518. expect(wrapper.text()).toBe('一级 1一级 2一级 3')
  519. expect(wrapper.findAll('.is-expanded')).toHaveLength(0)
  520. tree.setCurrentKey(11)
  521. await nextTick()
  522. await nextTick()
  523. await nextTick()
  524. expect(wrapper.text()).toBe('一级 1二级 1-1一级 2一级 3')
  525. expect(wrapper.findAll('.is-expanded')).toHaveLength(1)
  526. tree.setCurrentKey(111)
  527. await nextTick()
  528. await nextTick()
  529. await nextTick()
  530. expect(wrapper.text()).toBe('一级 1二级 1-1三级 1-1一级 2一级 3')
  531. expect(wrapper.findAll('.is-expanded')).toHaveLength(2)
  532. })
  533. test('setCurrentNode', async () => {
  534. const { wrapper } = getTreeVm(
  535. `:props="defaultProps" show-checkbox node-key="id"`
  536. )
  537. const treeWrapper = wrapper.findComponent(Tree)
  538. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  539. tree.setCurrentNode({
  540. id: 111,
  541. label: '三级 1-1',
  542. } as Node)
  543. expect(tree.store.currentNode.data.id).toEqual(111)
  544. tree.setCurrentKey(null)
  545. expect(tree.store.currentNode).toEqual(null)
  546. })
  547. test('setCurrentNode should also auto expand parent', async () => {
  548. const { wrapper } = getTreeVm(
  549. `:props="defaultProps" show-checkbox node-key="id"`
  550. )
  551. const treeWrapper = wrapper.findComponent(Tree)
  552. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  553. tree.setCurrentNode({
  554. id: 111,
  555. label: '三级 1-1',
  556. } as Node)
  557. await nextTick()
  558. expect(wrapper.find('.is-current').exists()).toBeTruthy()
  559. tree.setCurrentKey(null)
  560. await nextTick()
  561. expect(wrapper.find('.is-current').exists()).toBeFalsy()
  562. })
  563. test('setCurrentNode should not expand self', async () => {
  564. const { wrapper } = getTreeVm(
  565. `:props="defaultProps" show-checkbox node-key="id"`
  566. )
  567. await nextTick()
  568. const treeWrapper = wrapper.findComponent(Tree)
  569. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  570. tree.setCurrentNode({
  571. id: 1,
  572. label: '一级 1-1',
  573. } as Node)
  574. await nextTick()
  575. await nextTick()
  576. await nextTick()
  577. expect(wrapper.text()).toBe('一级 1一级 2一级 3')
  578. expect(wrapper.findAll('.is-expanded')).toHaveLength(0)
  579. tree.setCurrentNode({
  580. id: 11,
  581. label: '二级 1-1',
  582. } as Node)
  583. await nextTick()
  584. await nextTick()
  585. await nextTick()
  586. expect(wrapper.text()).toBe('一级 1二级 1-1一级 2一级 3')
  587. expect(wrapper.findAll('.is-expanded')).toHaveLength(1)
  588. tree.setCurrentNode({
  589. id: 111,
  590. label: '三级 1-1',
  591. } as Node)
  592. await nextTick()
  593. await nextTick()
  594. await nextTick()
  595. expect(wrapper.text()).toBe('一级 1二级 1-1三级 1-1一级 2一级 3')
  596. expect(wrapper.findAll('.is-expanded')).toHaveLength(2)
  597. })
  598. test('getCurrentKey', async () => {
  599. const { wrapper } = getTreeVm(
  600. `:props="defaultProps" show-checkbox node-key="id"`
  601. )
  602. const treeWrapper = wrapper.findComponent(Tree)
  603. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  604. tree.setCurrentKey(111)
  605. expect(tree.getCurrentKey()).toEqual(111)
  606. tree.setCurrentKey(null)
  607. expect(tree.getCurrentKey()).toEqual(null)
  608. })
  609. test('getCurrentNode', async () => {
  610. const { wrapper } = getTreeVm(
  611. `:props="defaultProps" show-checkbox node-key="id"`
  612. )
  613. const treeWrapper = wrapper.findComponent(Tree)
  614. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  615. tree.setCurrentKey(111)
  616. expect(tree.getCurrentNode().id).toEqual(111)
  617. })
  618. test('getNode', async () => {
  619. const { wrapper } = getTreeVm(`:props="defaultProps" node-key="id"`)
  620. const treeWrapper = wrapper.findComponent(Tree)
  621. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  622. const node = tree.getNode(111)
  623. expect(node.data.id).toEqual(111)
  624. })
  625. test('remove', async () => {
  626. const { wrapper } = getTreeVm(`:props="defaultProps" node-key="id"`)
  627. const treeWrapper = wrapper.findComponent(Tree)
  628. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  629. tree.setCurrentKey(1)
  630. expect(tree.getCurrentNode().id).toEqual(1)
  631. tree.remove(1)
  632. expect(tree.data[0].id).toEqual(2)
  633. expect(tree.getNode(1)).toEqual(null)
  634. expect(tree.getCurrentNode()).toEqual(null)
  635. })
  636. test('append', async () => {
  637. const { wrapper } = getTreeVm(`:props="defaultProps" node-key="id"`)
  638. const treeWrapper = wrapper.findComponent(Tree)
  639. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  640. const nodeData = { id: 88, label: '88' }
  641. tree.append(nodeData, tree.getNode(1))
  642. expect(tree.data[0].children.length).toEqual(2)
  643. expect(tree.getNode(88).data).toEqual(nodeData)
  644. })
  645. test('insertBefore', async () => {
  646. const { wrapper } = getTreeVm(`:props="defaultProps" node-key="id"`)
  647. const treeWrapper = wrapper.findComponent(Tree)
  648. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  649. const nodeData = { id: 88, label: '88' }
  650. tree.insertBefore(nodeData, tree.getNode(11))
  651. expect(tree.data[0].children.length).toEqual(2)
  652. expect(tree.data[0].children[0]).toEqual(nodeData)
  653. expect(tree.getNode(88).data).toEqual(nodeData)
  654. })
  655. test('insertAfter', async () => {
  656. const { wrapper } = getTreeVm(`:props="defaultProps" node-key="id"`)
  657. const treeWrapper = wrapper.findComponent(Tree)
  658. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  659. const nodeData = { id: 88, label: '88' }
  660. tree.insertAfter(nodeData, tree.getNode(11))
  661. expect(tree.data[0].children.length).toEqual(2)
  662. expect(tree.data[0].children[1]).toEqual(nodeData)
  663. expect(tree.getNode(88).data).toEqual(nodeData)
  664. })
  665. test('set disabled checkbox', async () => {
  666. const { wrapper } = getDisableTreeVm(
  667. `:props="defaultProps" show-checkbox node-key="id" default-expand-all`
  668. )
  669. const nodeWrapper = wrapper.findAll('.el-tree-node__content')[2]
  670. const checkboxWrapper = nodeWrapper.find('.el-checkbox input')
  671. expect((checkboxWrapper.element as HTMLInputElement).disabled).toEqual(true)
  672. })
  673. test('check strictly', async () => {
  674. const { wrapper } = getTreeVm(
  675. `:props="defaultProps" show-checkbox check-strictly default-expand-all`
  676. )
  677. const treeWrapper = wrapper.findComponent(Tree)
  678. const secondNodeContentWrapper = wrapper.findAll(
  679. '.el-tree-node__content'
  680. )[3]
  681. const secondNodeCheckboxWrapper =
  682. secondNodeContentWrapper.find('.el-checkbox')
  683. await secondNodeCheckboxWrapper.trigger('click')
  684. expect(
  685. (treeWrapper.vm as InstanceType<typeof Tree>).getCheckedNodes().length
  686. ).toEqual(1)
  687. expect(
  688. (treeWrapper.vm as InstanceType<typeof Tree>).getCheckedNodes(true).length
  689. ).toEqual(0)
  690. const secondTreeNodeWrapper = treeWrapper.findAll('.el-tree-node')[3]
  691. const secondNodefirstLeafCheckboxWrapper = secondTreeNodeWrapper.find(
  692. '.el-tree-node__children .el-tree-node__content .el-checkbox'
  693. )
  694. await secondNodefirstLeafCheckboxWrapper.trigger('click')
  695. expect(
  696. (treeWrapper.vm as InstanceType<typeof Tree>).getCheckedNodes().length
  697. ).toEqual(2)
  698. })
  699. test('render content', async () => {
  700. const { wrapper } = getTreeVm(
  701. `:props="defaultProps" :render-content="renderContent"`,
  702. {
  703. methods: {
  704. renderContent(h, node) {
  705. return h('div', { class: 'custom-content' }, [
  706. h('button', { class: 'el-button' }, [node.node.label]),
  707. ])
  708. },
  709. },
  710. }
  711. )
  712. const firstNodeWrapper = wrapper.find('.el-tree-node__content')
  713. expect(firstNodeWrapper.find('.custom-content').exists()).toBe(true)
  714. const buttonWrapper = firstNodeWrapper.find('.custom-content button')
  715. expect(buttonWrapper.exists()).toBe(true)
  716. expect(buttonWrapper.text()).toEqual('一级 1')
  717. })
  718. test('custom-node-class', async () => {
  719. const { wrapper } = getTreeVm(
  720. `:props="{class:(data)=>{return data.id===11?'is-test':null}}" default-expand-all highlight-current node-key="id" :current-node-key="11"`
  721. )
  722. const currentNodeLabelWrapper = wrapper.find(
  723. '.is-test .el-tree-node__label'
  724. )
  725. expect(currentNodeLabelWrapper.text()).toEqual('二级 1-1')
  726. })
  727. test('scoped slot', async () => {
  728. const { wrapper } = getTreeVm('', {
  729. template: `
  730. <el-tree ref="tree" :data="data">
  731. <template #default="scope">
  732. <div class="custom-tree-template">
  733. <span>{{ scope.node.label }}</span>
  734. <button></button>
  735. </div>
  736. </template>
  737. </el-tree>
  738. `,
  739. methods: {
  740. renderContent(h, node) {
  741. return h('div', { class: 'custom-content' }, [
  742. h('button', { class: 'el-button' }, [node.node.label]),
  743. ])
  744. },
  745. },
  746. })
  747. const firstNodeWrapper = wrapper.find('.custom-tree-template')
  748. expect(firstNodeWrapper.exists()).toBe(true)
  749. const spanWrapper = firstNodeWrapper.find('span')
  750. const buttonWrapper = firstNodeWrapper.find('button')
  751. expect(spanWrapper.exists()).toBe(true)
  752. expect(spanWrapper.text()).toEqual('一级 1')
  753. expect(buttonWrapper.exists()).toBe(true)
  754. })
  755. test('load node', async () => {
  756. const { wrapper } = getTreeVm(
  757. `:props="defaultProps" lazy :load="loadNode" show-checkbox`,
  758. {
  759. methods: {
  760. loadNode(node, resolve) {
  761. if (node.level === 0) {
  762. return resolve([{ label: 'region1' }, { label: 'region2' }])
  763. }
  764. if (node.level > 4) return resolve([])
  765. setTimeout(() => {
  766. resolve([
  767. {
  768. label: `zone${this.count++}`,
  769. },
  770. {
  771. label: `zone${this.count++}`,
  772. },
  773. ])
  774. }, 50)
  775. },
  776. },
  777. }
  778. )
  779. let nodeWrappers = wrapper.findAll('.el-tree-node__content')
  780. expect(nodeWrappers.length).toEqual(2)
  781. vi.useFakeTimers()
  782. await nodeWrappers[0].trigger('click')
  783. vi.runAllTimers()
  784. vi.useRealTimers()
  785. await nextTick() // wait load finish
  786. nodeWrappers = wrapper.findAll('.el-tree-node__content')
  787. expect(nodeWrappers.length).toEqual(4)
  788. })
  789. test('lazy defaultChecked', async () => {
  790. const { wrapper } = getTreeVm(
  791. `:props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox`,
  792. {
  793. methods: {
  794. loadNode(node, resolve) {
  795. if (node.level === 0) {
  796. return resolve([
  797. { label: 'region1', id: this.count++ },
  798. { label: 'region2', id: this.count++ },
  799. ])
  800. }
  801. if (node.level > 4) return resolve([])
  802. setTimeout(() => {
  803. resolve([
  804. {
  805. label: `zone${this.count}`,
  806. id: this.count++,
  807. },
  808. {
  809. label: `zone${this.count}`,
  810. id: this.count++,
  811. },
  812. ])
  813. }, 50)
  814. },
  815. },
  816. }
  817. )
  818. const treeWrapper = wrapper.findComponent(Tree)
  819. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  820. const firstNodeWrapper = treeWrapper.find('.el-tree-node__content')
  821. expect(firstNodeWrapper.find('.is-indeterminate').exists()).toEqual(false)
  822. tree.store.setCheckedKeys([3])
  823. vi.useFakeTimers()
  824. await firstNodeWrapper.find('.el-tree-node__expand-icon').trigger('click')
  825. vi.runAllTimers()
  826. vi.useRealTimers()
  827. await nextTick()
  828. expect(firstNodeWrapper.find('.is-indeterminate').exists()).toEqual(true)
  829. const childWrapper = treeWrapper.findAll('.el-tree-node__content')[1]
  830. expect(childWrapper.find('input').element.checked).toEqual(true)
  831. })
  832. test('lazy expandOnChecked', async () => {
  833. const { wrapper } = getTreeVm(
  834. `:props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox check-descendants`,
  835. {
  836. methods: {
  837. loadNode(node, resolve) {
  838. if (node.level === 0) {
  839. return resolve([
  840. { label: 'region1', id: this.count++ },
  841. { label: 'region2', id: this.count++ },
  842. ])
  843. }
  844. if (node.level > 2) return resolve([])
  845. setTimeout(() => {
  846. resolve([
  847. {
  848. label: `zone${this.count}`,
  849. id: this.count++,
  850. },
  851. {
  852. label: `zone${this.count}`,
  853. id: this.count++,
  854. },
  855. ])
  856. }, 10)
  857. },
  858. },
  859. }
  860. )
  861. const treeWrapper = wrapper.findComponent(Tree)
  862. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  863. vi.useFakeTimers()
  864. tree.store.setCheckedKeys([1])
  865. vi.runAllTimers()
  866. vi.useRealTimers()
  867. await nextTick()
  868. expect(tree.getCheckedKeys().length).toEqual(7)
  869. })
  870. test('lazy without expandOnChecked', async () => {
  871. const { wrapper } = getTreeVm(
  872. `:props="defaultProps" node-key="id" lazy :load="loadNode" show-checkbox`,
  873. {
  874. methods: {
  875. loadNode(node, resolve) {
  876. if (node.level === 0) {
  877. return resolve([
  878. { label: 'region1', id: this.count++ },
  879. { label: 'region2', id: this.count++ },
  880. ])
  881. }
  882. if (node.level > 4) return resolve([])
  883. setTimeout(() => {
  884. resolve([
  885. {
  886. label: `zone${this.count}`,
  887. id: this.count++,
  888. },
  889. {
  890. label: `zone${this.count}`,
  891. id: this.count++,
  892. },
  893. ])
  894. }, 50)
  895. },
  896. },
  897. }
  898. )
  899. const treeWrapper = wrapper.findComponent(Tree)
  900. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  901. tree.store.setCheckedKeys([1])
  902. await nextTick()
  903. const nodeWrappers = treeWrapper.findAll('.el-tree-node__content')
  904. expect(nodeWrappers[0].find('input').element.checked).toEqual(true)
  905. expect(nodeWrappers.length).toEqual(2)
  906. })
  907. test('accordion', async () => {
  908. const { wrapper } = getTreeVm(`:props="defaultProps" accordion`)
  909. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  910. const secondNodeContentWrapper = wrapper.find(
  911. '.el-tree-node:nth-child(2) .el-tree-node__content'
  912. )
  913. await firstNodeContentWrapper.trigger('click')
  914. expect(wrapper.find('.el-tree-node').classes('is-expanded')).toBe(true)
  915. await secondNodeContentWrapper.trigger('click')
  916. expect(wrapper.find('.el-tree-node').classes('is-expanded')).toBe(false)
  917. })
  918. test('handleNodeOpen & handleNodeClose', async () => {
  919. const { wrapper, vm } = getTreeVm(
  920. `:props="defaultProps" lazy :load="loadNode" @node-expand="handleNodeOpen" @node-collapse="handleNodeClose"`,
  921. {
  922. methods: {
  923. loadNode(node, resolve) {
  924. if (node.level === 0) {
  925. return resolve([{ label: 'region1' }, { label: 'region2' }])
  926. }
  927. if (node.level > 4) return resolve([])
  928. nextTick(() => {
  929. resolve([
  930. {
  931. label: `zone${this.count++}`,
  932. },
  933. {
  934. label: `zone${this.count++}`,
  935. },
  936. ])
  937. })
  938. },
  939. handleNodeOpen(data) {
  940. this.currentNode = data
  941. this.nodeExpended = true
  942. },
  943. handleNodeClose(data) {
  944. this.currentNode = data
  945. this.nodeExpended = false
  946. },
  947. },
  948. }
  949. )
  950. const firstNodeContentWrapper = wrapper.find('.el-tree-node__content')
  951. const firstNodeWrapper = wrapper.find('.el-tree-node')
  952. expect(firstNodeWrapper.find('.el-tree-node__children').exists()).toBe(
  953. false
  954. )
  955. await firstNodeContentWrapper.trigger('click')
  956. await nextTick() // first next tick for UI update
  957. await nextTick() // second next tick for triggering loadNode
  958. await nextTick() // third next tick for updating props.node.expanded
  959. expect(vm.nodeExpended).toEqual(true)
  960. expect(vm.currentNode.label).toEqual('region1')
  961. await firstNodeContentWrapper.trigger('click')
  962. await nextTick()
  963. await nextTick()
  964. await nextTick()
  965. expect(vm.nodeExpended).toEqual(false)
  966. expect(vm.currentNode.label).toEqual('region1')
  967. })
  968. test('updateKeyChildren', async () => {
  969. const { wrapper } = getTreeVm(
  970. `:props="defaultProps" show-checkbox node-key="id" default-expand-all`
  971. )
  972. const treeWrapper = wrapper.findComponent(Tree)
  973. const tree = treeWrapper.vm as InstanceType<typeof Tree>
  974. tree.updateKeyChildren(1, [
  975. {
  976. id: 111,
  977. label: '三级 1-1',
  978. },
  979. ])
  980. await nextTick()
  981. const nodeContentWrapper = wrapper.findAll('.el-tree-node__content')[1]
  982. const nodeLabelWrapper = nodeContentWrapper.find('.el-tree-node__label')
  983. expect(tree.store.nodesMap['11']).toEqual(undefined)
  984. expect(tree.store.nodesMap['1'].childNodes[0].data.id).toEqual(111)
  985. expect(nodeLabelWrapper.text()).toEqual('三级 1-1')
  986. })
  987. test('update multi tree data', async () => {
  988. const { wrapper, vm } = getTreeVm(``, {
  989. template: `
  990. <div>
  991. <el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps"></el-tree>
  992. <el-tree ref="tree2" :data="data" node-key="id" :props="defaultProps"></el-tree>
  993. </div>
  994. `,
  995. })
  996. const nodeData = { label: '新增 1', id: 4, children: [] }
  997. vm.data.push(nodeData)
  998. vm.data = [...vm.data]
  999. await nextTick()
  1000. const treeWrappers: any = wrapper.findAllComponents(Tree)
  1001. expect(treeWrappers[0].vm.getNode(4).data).toEqual(nodeData)
  1002. expect(treeWrappers[1].vm.getNode(4).data).toEqual(nodeData)
  1003. })
  1004. test('navigate with defaultExpandAll', () => {
  1005. const { wrapper } = getTreeVm(``, {
  1006. template: `
  1007. <div>
  1008. <el-tree default-expand-all ref="tree1" :data="data" node-key="id" :props="defaultProps"></el-tree>
  1009. </div>
  1010. `,
  1011. })
  1012. const tree = wrapper.findComponent({ name: 'ElTree' })
  1013. expect(
  1014. Object.values(
  1015. (tree.vm as InstanceType<typeof Tree>).store.nodesMap
  1016. ).filter((item) => item.canFocus).length
  1017. ).toBe(9)
  1018. })
  1019. test('navigate up', async () => {
  1020. const { wrapper } = getTreeVm(``, {
  1021. template: `
  1022. <div>
  1023. <el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps"></el-tree>
  1024. </div>
  1025. `,
  1026. })
  1027. let flag = false
  1028. function handleFocus() {
  1029. return () => (flag = true)
  1030. }
  1031. await nextTick()
  1032. const tree = wrapper.findComponent({ name: 'ElTree' })
  1033. const targetElement = wrapper.find('div[data-key="3"]').element
  1034. const fromElement = wrapper.find('div[data-key="1"]').element
  1035. defineGetter(targetElement, 'focus', handleFocus)
  1036. ;(tree.vm as InstanceType<typeof Tree>).setCurrentKey(1)
  1037. expect(fromElement.classList.contains('is-focusable')).toBeTruthy()
  1038. fromElement.dispatchEvent(
  1039. new KeyboardEvent('keydown', {
  1040. code: 'ArrowUp',
  1041. bubbles: true,
  1042. cancelable: false,
  1043. })
  1044. )
  1045. expect(flag).toBe(true)
  1046. })
  1047. test('navigate down', async () => {
  1048. const { wrapper } = getTreeVm(``, {
  1049. template: `
  1050. <div>
  1051. <el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps"></el-tree>
  1052. </div>
  1053. `,
  1054. })
  1055. let flag = false
  1056. function handleFocus() {
  1057. return () => (flag = true)
  1058. }
  1059. await nextTick()
  1060. const tree = wrapper.findComponent({ name: 'ElTree' })
  1061. const targetElement = wrapper.find('div[data-key="2"]').element
  1062. const fromElement = wrapper.find('div[data-key="1"]').element
  1063. defineGetter(targetElement, 'focus', handleFocus)
  1064. ;(tree.vm as InstanceType<typeof Tree>).setCurrentKey(1)
  1065. expect(fromElement.classList.contains('is-focusable')).toBeTruthy()
  1066. fromElement.dispatchEvent(
  1067. new KeyboardEvent('keydown', {
  1068. code: 'ArrowDown',
  1069. bubbles: true,
  1070. cancelable: false,
  1071. })
  1072. )
  1073. expect(flag).toBe(true)
  1074. })
  1075. test('navigate with disabled', async () => {
  1076. const wrapper = mount({
  1077. template: `
  1078. <div>
  1079. <el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps"></el-tree>
  1080. </div>
  1081. `,
  1082. components: {
  1083. 'el-tree': Tree,
  1084. },
  1085. data() {
  1086. return {
  1087. data: [
  1088. {
  1089. id: 1,
  1090. label: '一级 1',
  1091. children: [
  1092. {
  1093. id: 11,
  1094. label: '二级 1-1',
  1095. children: [
  1096. {
  1097. id: 111,
  1098. label: '三级 1-1',
  1099. disabled: true,
  1100. },
  1101. ],
  1102. },
  1103. ],
  1104. },
  1105. {
  1106. id: 2,
  1107. label: '一级 2',
  1108. disabled: true,
  1109. children: [
  1110. {
  1111. id: 21,
  1112. label: '二级 2-1',
  1113. },
  1114. {
  1115. id: 22,
  1116. label: '二级 2-2',
  1117. },
  1118. ],
  1119. },
  1120. {
  1121. id: 3,
  1122. label: '一级 3',
  1123. children: [
  1124. {
  1125. id: 31,
  1126. label: '二级 3-1',
  1127. },
  1128. {
  1129. id: 32,
  1130. label: '二级 3-2',
  1131. },
  1132. ],
  1133. },
  1134. ],
  1135. defaultProps: {
  1136. children: 'children',
  1137. label: 'label',
  1138. disabled: 'disabled',
  1139. },
  1140. }
  1141. },
  1142. })
  1143. let flag = false
  1144. function handleFocus() {
  1145. return () => (flag = true)
  1146. }
  1147. await nextTick()
  1148. const tree = wrapper.findComponent({ name: 'ElTree' })
  1149. const targetElement = wrapper.find('div[data-key="3"]').element
  1150. const fromElement = wrapper.find('div[data-key="1"]').element
  1151. defineGetter(targetElement, 'focus', handleFocus)
  1152. ;(tree.vm as InstanceType<typeof Tree>).setCurrentKey(1)
  1153. expect(fromElement.classList.contains('is-focusable')).toBeTruthy()
  1154. fromElement.dispatchEvent(
  1155. new KeyboardEvent('keydown', {
  1156. code: 'ArrowDown',
  1157. bubbles: true,
  1158. cancelable: false,
  1159. })
  1160. )
  1161. expect(flag).toBe(true)
  1162. })
  1163. test('navigate with lazy and without node-key', async () => {
  1164. const wrapper = mount({
  1165. template: `
  1166. <div>
  1167. <el-tree
  1168. :props="defaultProps"
  1169. :load="loadNode"
  1170. lazy
  1171. show-checkbox>
  1172. </el-tree>
  1173. </div>
  1174. `,
  1175. components: {
  1176. 'el-tree': Tree,
  1177. },
  1178. data() {
  1179. return {
  1180. defaultProps: {
  1181. children: 'children',
  1182. label: 'label',
  1183. disabled: 'disabled',
  1184. },
  1185. count: 0,
  1186. }
  1187. },
  1188. methods: {
  1189. loadNode(node: Node, resolve: typeof Promise.resolve) {
  1190. if (node.level === 0) {
  1191. return resolve([{ name: 'region1' }, { name: 'region2' }])
  1192. }
  1193. if (node.level > 3) return resolve([])
  1194. let hasChild: boolean
  1195. if (node.data.name === 'region1') {
  1196. hasChild = true
  1197. } else if (node.data.name === 'region2') {
  1198. hasChild = false
  1199. } else {
  1200. hasChild = false
  1201. }
  1202. let data: { name: string }[]
  1203. if (hasChild) {
  1204. data = [
  1205. {
  1206. name: `zone${++this.count}`,
  1207. },
  1208. {
  1209. name: `zone${++this.count}`,
  1210. },
  1211. ]
  1212. } else {
  1213. data = []
  1214. }
  1215. resolve(data)
  1216. },
  1217. },
  1218. })
  1219. let flag = false
  1220. function handleFocus() {
  1221. return () => (flag = !flag)
  1222. }
  1223. await nextTick()
  1224. const tree = wrapper.findComponent({ name: 'ElTree' })
  1225. const originElements = wrapper.findAll('div[data-key]')
  1226. const region1 = originElements[0].element
  1227. const region2 = originElements[1].element
  1228. defineGetter(region2, 'focus', handleFocus)
  1229. // expand
  1230. region1.dispatchEvent(new MouseEvent('click'))
  1231. expect(region1.classList.contains('is-focusable')).toBeTruthy()
  1232. await nextTick()
  1233. await nextTick()
  1234. expect(
  1235. Object.values((tree.vm as InstanceType<typeof Tree>).store.nodesMap)
  1236. ).toHaveLength(5) // The root node (void node) + 4 child nodes (region1, region2, zone1, zone2)
  1237. expect(
  1238. Object.values(
  1239. Object.values(
  1240. (tree.vm as InstanceType<typeof Tree>).store.nodesMap
  1241. ).filter((item) => item.canFocus).length === 4
  1242. )
  1243. ).toBeTruthy()
  1244. // collapse
  1245. region1.dispatchEvent(new MouseEvent('click'))
  1246. expect(
  1247. Object.values(
  1248. Object.values(
  1249. (tree.vm as InstanceType<typeof Tree>).store.nodesMap
  1250. ).filter((item) => item.canFocus).length === 2
  1251. )
  1252. ).toBeTruthy()
  1253. // ArrowDown, region2 focus
  1254. region1.dispatchEvent(
  1255. new KeyboardEvent('keydown', {
  1256. code: 'ArrowDown',
  1257. bubbles: true,
  1258. cancelable: false,
  1259. })
  1260. )
  1261. expect(flag).toBe(true)
  1262. defineGetter(region1, 'focus', handleFocus)
  1263. // ArrowDown, region1 focus
  1264. region2.dispatchEvent(
  1265. new KeyboardEvent('keydown', {
  1266. code: 'ArrowDown',
  1267. bubbles: true,
  1268. cancelable: false,
  1269. })
  1270. )
  1271. expect(flag).toBe(false)
  1272. })
  1273. })