1
0

tree.test.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. import { isEqual } from 'lodash';
  2. import { IconMapPin } from '@douyinfe/semi-icons';
  3. import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
  4. import { Tree, Button } from '../../index';
  5. const treeChildren = [
  6. {
  7. label: '北京',
  8. value: 'Beijing',
  9. key: 'beijing',
  10. },
  11. {
  12. label: '上海',
  13. value: 'Shanghai',
  14. key: 'shanghai',
  15. },
  16. ];
  17. const treeData = [
  18. {
  19. label: '亚洲',
  20. value: 'Yazhou',
  21. key: 'yazhou',
  22. children: [
  23. {
  24. label: '中国',
  25. value: 'Zhongguo',
  26. key: 'zhongguo',
  27. children: treeChildren,
  28. },
  29. {
  30. label: '日本',
  31. value: 'Riben',
  32. key: 'riben',
  33. children: [
  34. {
  35. label: '东京',
  36. value: 'Dongjing',
  37. key: 'dongjing'
  38. },
  39. {
  40. label: '大阪',
  41. value: 'Daban',
  42. key: 'daban'
  43. }
  44. ]
  45. },
  46. ],
  47. },
  48. {
  49. label: '北美洲',
  50. value: 'Beimeizhou',
  51. key: 'beimeizhou',
  52. children: [
  53. {
  54. label: '美国',
  55. value: 'Meiguo',
  56. key: 'meiguo'
  57. },
  58. {
  59. label: '加拿大',
  60. value: 'Jianada',
  61. key: 'jianada'
  62. }
  63. ]
  64. },
  65. ];
  66. const treeData2 = [
  67. {
  68. label: '亚洲',
  69. value: 'Asia',
  70. key: '0',
  71. children: [
  72. {
  73. label: '中国',
  74. value: 'China',
  75. key: '0-0',
  76. children: [
  77. {
  78. label: '北京',
  79. value: 'Beijing',
  80. key: '0-0-0',
  81. },
  82. {
  83. label: '上海',
  84. value: 'Shanghai',
  85. key: '0-0-1',
  86. },
  87. ],
  88. },
  89. ],
  90. },
  91. {
  92. label: '北美洲',
  93. value: 'North America',
  94. key: '1',
  95. }
  96. ];
  97. const treeData3 = [
  98. {
  99. label: '亚洲',
  100. value: 'Asia',
  101. key: '0',
  102. newLabel: '亚洲#1#yazhou',
  103. children: [
  104. {
  105. label: '中国',
  106. value: 'China',
  107. key: '0-0',
  108. newLabel: '中国#2#zhongguo',
  109. children: [
  110. {
  111. label: '北京',
  112. value: 'Beijing',
  113. key: '0-0-0',
  114. newLabel: '北京#3#beijing',
  115. },
  116. {
  117. label: '上海',
  118. value: 'Shanghai',
  119. key: '0-0-1',
  120. newLabel: '上海#4#shanghai',
  121. },
  122. ],
  123. },
  124. ],
  125. },
  126. {
  127. label: '北美洲',
  128. value: 'North America',
  129. newLabel: '北美洲#5#beimeizhou',
  130. key: '1',
  131. }
  132. ];
  133. const dragNodeData = {"label":"亚洲","value":"Yazhou","key":"yazhou","children":[{"label":"中国","value":"Zhongguo","key":"zhongguo","children":[{"label":"北京","value":"Beijing","key":"beijing"},{"label":"上海","value":"Shanghai","key":"shanghai"}]},{"label":"日本","value":"Riben","key":"riben","children":[{"label":"东京","value":"Dongjing","key":"dongjing"},{"label":"大阪","value":"Daban","key":"daban"}]}],"expanded":false,"pos":"0-0"}
  134. const dropNodeData = {"label":"北美洲","value":"Beimeizhou","key":"beimeizhou","children":[{"label":"美国","value":"Meiguo","key":"meiguo"},{"label":"加拿大","value":"Jianada","key":"jianada"}],"expanded":false,"pos":"0-1"}
  135. function getTree(props) {
  136. props = { treeData: treeData, ...props }
  137. return mount(
  138. <Tree
  139. {...props}
  140. motion={true}
  141. />,
  142. {
  143. attachTo: document.getElementById('container')
  144. }
  145. );
  146. }
  147. describe('Tree', () => {
  148. beforeEach(() => {
  149. // Avoid `attachTo: document.body` Warning
  150. const div = document.createElement('div');
  151. div.setAttribute('id', 'container');
  152. document.body.appendChild(div);
  153. });
  154. afterEach(() => {
  155. const div = document.getElementById('container');
  156. if (div) {
  157. document.body.removeChild(div);
  158. }
  159. document.body.innerHTML = '';
  160. });
  161. it('className / style', () => {
  162. let props = {
  163. className: 'test',
  164. style: { height: 420 },
  165. };
  166. let tree = getTree(props);
  167. expect(tree.hasClass('test')).toEqual(true);
  168. expect(tree.find('div.test')).toHaveStyle('height', 420);
  169. });
  170. it('blockNode', () => {
  171. let tree = getTree({
  172. defaultValue: 'Beijing'
  173. });
  174. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-list-block`).exists()).toEqual(true);
  175. tree.setProps({ blockNode: false });
  176. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-list-block`).exists()).toEqual(false);
  177. });
  178. it('empty data', () => {
  179. let tree = getTree({
  180. treeData: []
  181. });
  182. let node = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  183. expect(node.length).toEqual(1);
  184. expect(node.hasClass(`${BASE_CLASS_PREFIX}-tree-option-empty`)).toEqual(true);
  185. });
  186. it('defaultValue', () => {
  187. // auto expand parent, if node exist means parent is open
  188. let tree = getTree({
  189. defaultValue: 'Beijing'
  190. });
  191. let selectedNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`);
  192. expect(selectedNode.instance().textContent).toEqual('北京');
  193. tree.unmount();
  194. // array case only select first item
  195. let tree2 = getTree({
  196. defaultValue: ['Riben', 'Beijing']
  197. });
  198. let selectedNode2 = tree2.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`);
  199. expect(selectedNode2.instance().textContent).toEqual('日本');
  200. expect(tree2.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  201. })
  202. it('defaultExpandedKeys', () => {
  203. // auto expand parent
  204. let tree = getTree({
  205. defaultExpandedKeys: ['zhongguo', 'beimeizhou']
  206. });
  207. // yazhou beimeizhou
  208. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  209. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  210. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  211. // zhongguo riben
  212. let children = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`);
  213. expect(children.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  214. expect(children.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  215. })
  216. it('defaultExpandAll', () => {
  217. let tree = getTree({
  218. defaultExpandAll: true
  219. });
  220. let nodes = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  221. let collapsed = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-collapsed`);
  222. expect(nodes.length).toEqual(10);
  223. expect(collapsed.length).toEqual(0);
  224. tree.setProps({ treeData: treeData2});
  225. tree.update();
  226. const nodes2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  227. const collapsed2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-collapsed`);
  228. expect(nodes2.length).toEqual(2);
  229. expect(collapsed2.length).toEqual(2);
  230. })
  231. it('expandAll', () => {
  232. const tree = getTree({
  233. expandAll: true
  234. });
  235. const nodes = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  236. const collapsed = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-collapsed`);
  237. expect(nodes.length).toEqual(10);
  238. expect(collapsed.length).toEqual(0);
  239. tree.setProps({ treeData: treeData2});
  240. tree.update();
  241. const nodes2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  242. const collapsed2 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-collapsed`);
  243. expect(nodes2.length).toEqual(5);
  244. expect(collapsed2.length).toEqual(0);
  245. })
  246. it('directory mode', () => {
  247. let props = {
  248. defaultExpandedKeys: ['beimeizhou'],
  249. directory: true,
  250. };
  251. let tree = getTree(props);
  252. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  253. expect(topNode.at(1).find(`.${BASE_CLASS_PREFIX}-icon-folder_open`).exists()).toEqual(true);
  254. expect(topNode.at(0).find(`.${BASE_CLASS_PREFIX}-icon-folder`).exists()).toEqual(true);
  255. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0).find(`.${BASE_CLASS_PREFIX}-icon-file`).exists()).toEqual(true);
  256. });
  257. it('custom icon', () => {
  258. let props = {
  259. defaultExpandAll: true,
  260. icon: (<IconMapPin />)
  261. };
  262. let tree = getTree(props);
  263. expect(tree.find(`.${BASE_CLASS_PREFIX}-icon-map_pin`).length).toEqual(10);
  264. });
  265. it('if expandedKeys values work', () => {
  266. // auto expand parent
  267. let tree = getTree({
  268. expandedKeys: ['beimeizhou']
  269. });
  270. // yazhou beimeizhou
  271. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  272. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  273. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  274. tree.setProps({ expandedKeys: ['yazhou', 'zhongguo', 'beimeizhou'] });
  275. tree.update();
  276. // zhongguo riben
  277. let children = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`);
  278. expect(children.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  279. expect(children.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  280. });
  281. it('expandedKeys + autoExpandParent', () => {
  282. // auto expand parent is always true when mounted
  283. let tree = getTree({
  284. expandedKeys: ['beimeizhou']
  285. });
  286. // yazhou beimeizhou
  287. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  288. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  289. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  290. tree.setProps({ expandedKeys: ['riben'] });
  291. tree.update();
  292. topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  293. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  294. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  295. // autoExpandParent
  296. tree.setProps({ autoExpandParent: true });
  297. tree.update();
  298. topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  299. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  300. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  301. });
  302. it('if expand behavior works / onExpand', () => {
  303. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  304. let spyOnExpand = sinon.spy(() => { });
  305. let tree = getTree({
  306. onExpand: spyOnExpand,
  307. });
  308. // yazhou
  309. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  310. let expandIcon = topNodeAsia.find(`.${BASE_CLASS_PREFIX}-tree-option-expand-icon`).at(0);
  311. // expand yazhou
  312. expandIcon.simulate('click', nativeEvent);
  313. expect(spyOnExpand.calledOnce).toBe(true);
  314. expect(spyOnExpand.calledWithMatch(["yazhou"], { expanded: true, node: { key: 'yazhou' } })).toEqual(true);
  315. // yazhou beimeizhou
  316. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  317. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  318. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  319. // collapse yazhou
  320. expandIcon.simulate('click', nativeEvent);
  321. expect(spyOnExpand.calledWithMatch([], { expanded: false, node: { key: 'yazhou' } })).toEqual(true);
  322. topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  323. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  324. });
  325. it('if expandedKeys controlled work / onExpand', () => {
  326. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  327. let spyOnExpand = sinon.spy(() => { });
  328. let tree = getTree({
  329. expandedKeys: ['beimeizhou'],
  330. onExpand: spyOnExpand,
  331. });
  332. // yazhou
  333. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  334. let expandIcon = topNodeAsia.find(`.${BASE_CLASS_PREFIX}-tree-option-expand-icon`).at(0);
  335. // expand yazhou
  336. expandIcon.simulate('click', nativeEvent);
  337. expect(spyOnExpand.calledWithMatch(["beimeizhou", "yazhou"], { expanded: true, node: { key: 'yazhou' } })).toEqual(true);
  338. // zhongguo riben
  339. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  340. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  341. });
  342. it('select item / onSelect / onChange', () => {
  343. let spyOnSelect = sinon.spy(() => { });
  344. let spyOnChange = sinon.spy(() => { });
  345. let tree = getTree({
  346. defaultExpandAll: true,
  347. onSelect: spyOnSelect,
  348. onChange: spyOnChange,
  349. });
  350. let nodeBeijing = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`).at(0);
  351. // select beijing
  352. nodeBeijing.simulate('click');
  353. // onSelect & onChange
  354. expect(spyOnSelect.calledOnce).toBe(true);
  355. expect(spyOnChange.calledOnce).toBe(true);
  356. expect(spyOnSelect.calledWithMatch('beijing', true, { key: "beijing" })).toEqual(true);
  357. expect(spyOnChange.calledWithMatch('Beijing')).toEqual(true);
  358. // classname
  359. nodeBeijing = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`).at(0);
  360. expect(nodeBeijing.hasClass(`${BASE_CLASS_PREFIX}-tree-option-selected`)).toEqual(true);
  361. // change
  362. let nodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  363. // select asia
  364. nodeAsia.simulate('click');
  365. // onSelect & onChange
  366. expect(spyOnSelect.calledWithMatch('yazhou', true, { key: "yazhou" })).toEqual(true);
  367. expect(spyOnChange.calledWithMatch('Yazhou')).toEqual(true);
  368. // classname
  369. nodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  370. expect(nodeAsia.hasClass(`${BASE_CLASS_PREFIX}-tree-option-selected`)).toEqual(true);
  371. });
  372. it('onChange + onChangeWithObject', () => {
  373. let spyOnChange = sinon.spy(() => { });
  374. let tree = getTree({
  375. defaultExpandAll: true,
  376. onChangeWithObject: true,
  377. onChange: spyOnChange,
  378. });
  379. let nodeBeijing = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`).at(0);
  380. // select beijing
  381. nodeBeijing.simulate('click');
  382. // onSelect & onChange
  383. expect(spyOnChange.calledOnce).toBe(true);
  384. expect(spyOnChange.calledWithMatch({ key: "beijing" })).toEqual(true);
  385. });
  386. it('filterTreeNode = true shows input box', () => {
  387. let tree = getTree({});
  388. let searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`)
  389. expect(searchWrapper.exists()).toEqual(false);
  390. tree.setProps({ filterTreeNode: true });
  391. tree.update();
  392. searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`)
  393. expect(searchWrapper.exists()).toEqual(true);
  394. });
  395. it('onSearch', () => {
  396. let onSearch = value => { };
  397. let spyOnSearch = sinon.spy(onSearch);
  398. let tree = getTree({
  399. filterTreeNode: true,
  400. onSearch: spyOnSearch,
  401. });
  402. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  403. let searchValue = 'semi';
  404. let event = { target: { value: searchValue } };
  405. searchWrapper.find('input').simulate('change', event);
  406. expect(spyOnSearch.calledOnce).toBe(true);
  407. expect(spyOnSearch.calledWithMatch(searchValue)).toBe(true);
  408. });
  409. it('emptyContent', () => {
  410. let onSearch = value => { };
  411. let spyOnSearch = sinon.spy(onSearch);
  412. let tree = getTree({
  413. filterTreeNode: true,
  414. onSearch: spyOnSearch,
  415. emptyContent: 'diy empty',
  416. showFilteredOnly: true,
  417. });
  418. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  419. let searchValue = 'asd';
  420. let event = { target: { value: searchValue } };
  421. searchWrapper.find('input').simulate('change', event);
  422. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-label-empty`).getDOMNode().textContent).toEqual('diy empty');
  423. });
  424. it('searchClassName / searchPlaceholder / searchStyle', () => {
  425. let tree = getTree({
  426. filterTreeNode: true,
  427. searchClassName: 'search',
  428. searchPlaceholder: 'placeholder',
  429. searchStyle: { padding: 16 },
  430. showClear: true,
  431. });
  432. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`)
  433. expect(searchWrapper.hasClass('search')).toEqual(true);
  434. expect(searchWrapper).toHaveStyle('padding', 16);
  435. expect(searchWrapper.find('input').instance().getAttribute('placeholder')).toEqual('placeholder');
  436. });
  437. it('filterTreeNode shows correct result', () => {
  438. let tree1 = getTree({
  439. filterTreeNode: true,
  440. });
  441. const searchWrapper = tree1.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  442. let searchValue = '北';
  443. let event = { target: { value: searchValue } };
  444. searchWrapper.find('input').simulate('change', event);
  445. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(6);
  446. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(2);
  447. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).at(0).instance().textContent).toEqual('北');
  448. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).at(1).instance().textContent).toEqual('北');
  449. tree1.unmount();
  450. let tree2 = getTree({
  451. filterTreeNode: true,
  452. treeNodeFilterProp: 'value',
  453. });
  454. const searchWrapper2 = tree2.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  455. let searchValue2 = 'an';
  456. let event2 = { target: { value: searchValue2 } };
  457. searchWrapper2.find('input').simulate('change', event2);
  458. expect(tree2.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(10);
  459. });
  460. it('filterTreeNode + no result', () => {
  461. let tree1 = getTree({
  462. filterTreeNode: true,
  463. });
  464. const searchWrapper = tree1.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  465. let searchValue = 'Bei';
  466. let event = { target: { value: searchValue } };
  467. searchWrapper.find('input').simulate('change', event);
  468. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(2);
  469. expect(tree1.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(0);
  470. tree1.unmount();
  471. let tree2 = getTree({
  472. filterTreeNode: true,
  473. treeNodeFilterProp: 'value',
  474. });
  475. const searchWrapper2 = tree2.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  476. let searchValue2 = '北京';
  477. let event2 = { target: { value: searchValue2 } };
  478. searchWrapper2.find('input').simulate('change', event2);
  479. expect(tree2.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(2);
  480. });
  481. if('filterTreeNode + treeNodeFilterProp + hightLight right') {
  482. let tree = getTree({
  483. treeData: treeData3,
  484. filterTreeNode: true,
  485. treeNodeFilterProp: 'newLabel'
  486. });
  487. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  488. let searchValue = '中';
  489. let event = { target: { value: searchValue } };
  490. searchWrapper.find('input').simulate('change', event);
  491. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(3);
  492. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(1);
  493. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).instance().textContent).toEqual("中");
  494. tree.unmount();
  495. }
  496. it('filterTreeNode + showFilteredOnly + no result', () => {
  497. let tree = getTree({
  498. filterTreeNode: true,
  499. showFilteredOnly: true,
  500. });
  501. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  502. let searchValue = 'Bei';
  503. let event = { target: { value: searchValue } };
  504. searchWrapper.find('input').simulate('change', event);
  505. let node = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  506. expect(node.length).toEqual(1);
  507. expect(node.hasClass(`${BASE_CLASS_PREFIX}-tree-option-empty`)).toEqual(true);
  508. });
  509. it('filterTreeNode + showFilteredOnly shows correct result', () => {
  510. let tree = getTree({
  511. filterTreeNode: true,
  512. showFilteredOnly: true,
  513. });
  514. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  515. let searchValue = '北';
  516. let event = { target: { value: searchValue } };
  517. searchWrapper.find('input').simulate('change', event);
  518. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option`).length).toEqual(4);
  519. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(2);
  520. });
  521. it('filterTreeNode as a func', () => {
  522. let tree = getTree({
  523. filterTreeNode: (inputValue, treeNode) => treeNode === inputValue,
  524. });
  525. const searchWrapper = tree.find(`.${BASE_CLASS_PREFIX}-tree-search-wrapper`);
  526. searchWrapper.find('input').simulate('change', { target: { value: '北' } });
  527. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(0);
  528. // update
  529. searchWrapper.find('input').simulate('change', { target: { value: '北京' } });
  530. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).length).toEqual(1);
  531. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-highlight`).instance().textContent).toEqual('北京');
  532. });
  533. it('controlled: value shows correct', () => {
  534. let tree = getTree({
  535. value: 'Beijing'
  536. });
  537. let selectedNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`);
  538. expect(selectedNode.instance().textContent).toEqual('北京');
  539. tree.unmount();
  540. // array case only select first item
  541. let tree2 = getTree({
  542. value: ['Riben', 'Beijing']
  543. });
  544. let selectedNode2 = tree2.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`);
  545. expect(selectedNode2.instance().textContent).toEqual('日本');
  546. expect(tree2.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  547. });
  548. it('controlled: fire onChange and ui not update', () => {
  549. let spyOnChange = sinon.spy(() => { });
  550. let tree = getTree({
  551. value: '',
  552. defaultExpandAll: true,
  553. onChange: spyOnChange,
  554. });
  555. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`).exists()).toEqual(false);
  556. let nodeBeijing = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`).at(0);
  557. // select beijing
  558. nodeBeijing.simulate('click');
  559. // onSelect & onChange
  560. expect(spyOnChange.calledOnce).toBe(true);
  561. expect(spyOnChange.calledWithMatch("Beijing")).toEqual(true);
  562. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`).exists()).toEqual(false);
  563. });
  564. it('controlled: value + onChangeWithObject', () => {
  565. let spyOnChange = sinon.spy(() => { });
  566. let tree = getTree({
  567. value: {
  568. label: '北京',
  569. value: 'Beijing',
  570. key: 'beijing',
  571. },
  572. defaultExpandAll: true,
  573. onChange: spyOnChange,
  574. onChangeWithObject: true,
  575. });
  576. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`).exists()).toEqual(true);
  577. });
  578. it('virtualized: fixed height', () => {
  579. let tree = getTree({
  580. defaultExpandAll: true,
  581. virtualize: {
  582. itemSize: 28,
  583. height: 84,
  584. },
  585. });
  586. // virtual list
  587. debugger
  588. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-virtual-list`).exists()).toEqual(true);
  589. // fewer nodes
  590. let nodes = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  591. expect(nodes.length).toBeLessThan(10);
  592. });
  593. it('disabled', () => {
  594. let spyOnChange = sinon.spy(() => { });
  595. let tree = getTree({
  596. defaultExpandAll: true,
  597. disabled: true,
  598. onChange: spyOnChange,
  599. });
  600. let nodes = tree.find(`.${BASE_CLASS_PREFIX}-tree-option-disabled`);
  601. expect(nodes.length).toEqual(10);
  602. // cannot select
  603. let nodeBeijing = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-3`).at(0);
  604. nodeBeijing.simulate('click');
  605. expect(spyOnChange.notCalled).toBe(true);
  606. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`).exists()).toEqual(false);
  607. });
  608. it('treedata in json format', () => {
  609. let spyOnChange = sinon.spy(() => { });
  610. let tree = mount(
  611. <Tree
  612. defaultExpandAll={true}
  613. onChange={spyOnChange}
  614. treeDataSimpleJson={{
  615. "Node1": {
  616. "Child1": '0-0-1',
  617. "Child2": '0-0-2',
  618. },
  619. "Node2": "0-1"
  620. }}
  621. />,
  622. {
  623. attachTo: document.getElementById('container')
  624. }
  625. );
  626. let nodes = tree.find(`.${BASE_CLASS_PREFIX}-tree-option`);
  627. expect(nodes.length).toEqual(4);
  628. // select
  629. let child1 = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0);
  630. child1.simulate('click');
  631. expect(spyOnChange.calledOnce).toBe(true);
  632. expect(spyOnChange.calledWithMatch({
  633. "Node1": {
  634. "Child1": '0-0-1',
  635. },
  636. })).toEqual(true);
  637. expect(tree.find(`.${BASE_CLASS_PREFIX}-tree-option-selected`).exists()).toEqual(true);
  638. });
  639. it('onContextMenu', () => {
  640. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  641. let spyOnContextMenu = sinon.spy(() => { });
  642. let tree = getTree({
  643. onContextMenu: spyOnContextMenu,
  644. });
  645. let event = {};
  646. // yazhou
  647. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  648. // right click on yazhou
  649. topNodeAsia.simulate('contextmenu', nativeEvent);
  650. expect(spyOnContextMenu.calledWithMatch(event, { key: 'yazhou' })).toEqual(true);
  651. // should not select item
  652. expect(topNodeAsia.hasClass(`${BASE_CLASS_PREFIX}-tree-option-selected`)).toEqual(false);
  653. expect(tree.state().selectedKeys.length).toEqual(0);
  654. });
  655. it('onDoubleClick', () => {
  656. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  657. let spyOnDoubleClick = sinon.spy(() => { });
  658. let tree = getTree({
  659. onDoubleClick: spyOnDoubleClick,
  660. });
  661. let event = {};
  662. // yazhou
  663. let topNodeAsia = tree.find('.semi-tree-option.semi-tree-option-level-1').at(0);
  664. // double click on yazhou
  665. topNodeAsia.simulate('doubleClick', nativeEvent);
  666. expect(spyOnDoubleClick.calledWithMatch(event, { key: 'yazhou' })).toEqual(true);
  667. // should not select item
  668. expect(topNodeAsia.hasClass(`${BASE_CLASS_PREFIX}-tree-option-selected`)).toEqual(false);
  669. expect(tree.state().selectedKeys.length).toEqual(0);
  670. });
  671. /**
  672. * Detect whether the expanded item will be expanded according to the value when the value
  673. * or treeData is changed, when expandedKeys is not controlled
  674. */
  675. const treeJsonData1 = {
  676. "Node0": {
  677. "Child Node0-0": '0-0',
  678. "Child Node0-1": '0-1',
  679. },
  680. "Node1": {
  681. "Child Node1-0": '1-0',
  682. "Child Node1-1": '1-1',
  683. }
  684. };
  685. const treeJsonData2 = {
  686. "Updated Node0": {
  687. "Updated Child Node0-0": {
  688. 'Updated Child Node0-0-0':'0-0'
  689. },
  690. "Updated Child Node0-1": '0-1',
  691. },
  692. "Updated Node1": {
  693. "Updated Child Node1-0": '1-0',
  694. "Updated Child Node1-1": '1-1',
  695. }
  696. };
  697. it('expandedKeys when treeDataSimpleJson update', () => {
  698. const tree = mount(
  699. <Tree
  700. value='0-0'
  701. multiple
  702. treeDataSimpleJson={treeJsonData1}
  703. />,
  704. {
  705. attachTo: document.getElementById('container')
  706. }
  707. );
  708. const treeDataButton = mount(
  709. <Button
  710. onClick={() => {
  711. if (isEqual(tree.props().treeDataSimpleJson, treeJsonData1)) {
  712. tree.setProps({ treeDataSimpleJson: treeJsonData2 });
  713. tree.update();
  714. } else {
  715. tree.setProps({ treeDataSimpleJson: treeJsonData1 });
  716. tree.update();
  717. }
  718. }}
  719. >
  720. update treeData
  721. </Button>
  722. );
  723. expect(
  724. tree
  725. .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`)
  726. .at(0)
  727. .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
  728. ).toEqual(false);
  729. expect(
  730. tree
  731. .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
  732. .at(0)
  733. .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
  734. ).toEqual(true);
  735. expect(
  736. tree
  737. .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`)
  738. .at(1)
  739. .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
  740. ).toEqual(true);
  741. treeDataButton.simulate('click');
  742. expect(
  743. tree
  744. .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
  745. .at(0)
  746. .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
  747. ).toEqual(false);
  748. treeDataButton.simulate('click');
  749. tree.unmount();
  750. treeDataButton.unmount();
  751. });
  752. it('expandAction = false / default behavior', () => {
  753. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  754. let spyOnExpand = sinon.spy(() => { });
  755. let tree = getTree({
  756. onExpand: spyOnExpand,
  757. });
  758. // yazhou
  759. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  760. // expand yazhou
  761. topNodeAsia.simulate('click', nativeEvent);
  762. expect(spyOnExpand.notCalled).toBe(true);
  763. expect(tree.state().expandedKeys.size).toEqual(0);
  764. });
  765. it('expandAction = click', () => {
  766. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  767. let spyOnExpand = sinon.spy(() => { });
  768. let tree = getTree({
  769. onExpand: spyOnExpand,
  770. expandAction: 'click',
  771. });
  772. // yazhou
  773. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  774. // expand yazhou
  775. topNodeAsia.simulate('click', nativeEvent);
  776. expect(spyOnExpand.calledOnce).toBe(true);
  777. expect(spyOnExpand.calledWithMatch(["yazhou"], { expanded: true, node: { key: 'yazhou' } })).toEqual(true);
  778. // yazhou beimeizhou
  779. let topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  780. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(false);
  781. expect(topNode.at(1).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  782. // collapse yazhou
  783. topNodeAsia.simulate('click', nativeEvent);
  784. expect(spyOnExpand.calledWithMatch([], { expanded: false, node: { key: 'yazhou' } })).toEqual(true);
  785. topNode = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`);
  786. expect(topNode.at(0).hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)).toEqual(true);
  787. });
  788. it('expandAction = doubleClick', () => {
  789. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  790. let spyOnExpand = sinon.spy(() => { });
  791. let tree = getTree({
  792. onExpand: spyOnExpand,
  793. expandAction: 'doubleClick',
  794. });
  795. // yazhou
  796. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  797. // expand yazhou
  798. topNodeAsia.simulate('click', nativeEvent);
  799. expect(spyOnExpand.calledOnce).toBe(false);
  800. topNodeAsia.simulate('doubleClick', nativeEvent);
  801. expect(spyOnExpand.calledOnce).toBe(true);
  802. expect(spyOnExpand.calledWithMatch(["yazhou"], { expanded: true, node: { key: 'yazhou' } })).toEqual(true);
  803. // yazhou beimeizhou
  804. expect(tree.state().expandedKeys).toEqual(new Set(["yazhou"]));
  805. expect(tree.state().selectedKeys).toEqual(["yazhou"]);
  806. });
  807. it('async load data', () => {
  808. const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
  809. const then = jest.fn(() => Promise.resolve());
  810. const loadData = jest.fn(() => ({ then }));
  811. const data = {
  812. label: '亚洲',
  813. value: 'Asia',
  814. key: 'asia',
  815. };
  816. let tree = getTree({
  817. loadData,
  818. treeData: [data]
  819. });
  820. let topNodeAsia = tree.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`).at(0);
  821. let expandIcon = topNodeAsia.find(`.${BASE_CLASS_PREFIX}-tree-option-expand-icon`).at(0);
  822. // expand yazhou
  823. expandIcon.simulate('click', nativeEvent);
  824. expect(loadData).toHaveBeenCalledWith(data);
  825. expect(then).toHaveBeenCalled();
  826. });
  827. it('DND - dragStart event', () => {
  828. const spyOnDragStart = sinon.spy(() => { });
  829. let tree = getTree({
  830. draggable: true,
  831. onDragStart: spyOnDragStart
  832. });
  833. let dragNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(0);
  834. dragNode.simulate('dragStart');
  835. expect(spyOnDragStart.calledOnce).toBe(true);
  836. expect(spyOnDragStart.calledWithMatch({node: dragNodeData})).toEqual(true);
  837. });
  838. it('DND - dragEnter event', (done) => {
  839. const spyOnDragEnter = sinon.spy(() => { });
  840. let tree = getTree({
  841. draggable: true,
  842. // autoExpandWhenDragEnter: false,
  843. onDragEnter: spyOnDragEnter
  844. });
  845. let dragNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(0);
  846. dragNode.simulate('dragStart');
  847. dragNode.simulate('dragEnter');
  848. // not trigger on self
  849. expect(spyOnDragEnter.notCalled).toBe(true);
  850. let dropNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(1);
  851. dropNode.simulate('dragEnter');
  852. setTimeout(() => {
  853. expect(spyOnDragEnter.calledOnce).toBe(true);
  854. expect(spyOnDragEnter.calledWithMatch({node: dropNodeData, expandedKeys: ['beimeizhou']})).toEqual(true);
  855. done();
  856. }, 500);
  857. });
  858. it('DND - dragOver event', () => {
  859. const spyOnDragOver = sinon.spy(() => { });
  860. let tree = getTree({
  861. draggable: true,
  862. onDragOver: spyOnDragOver
  863. });
  864. let dropNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(1);
  865. dropNode.simulate('dragOver');
  866. expect(spyOnDragOver.calledOnce).toBe(true);
  867. expect(spyOnDragOver.calledWithMatch({node: dropNodeData})).toEqual(true);
  868. });
  869. it('DND - dragLeave event', () => {
  870. const spyOnDragLeave = sinon.spy(() => { });
  871. let tree = getTree({
  872. draggable: true,
  873. onDragLeave: spyOnDragLeave
  874. });
  875. let dropNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(1);
  876. dropNode.simulate('dragLeave');
  877. expect(spyOnDragLeave.calledOnce).toBe(true);
  878. expect(spyOnDragLeave.calledWithMatch({node: dropNodeData})).toEqual(true);
  879. });
  880. it('DND - drop event', () => {
  881. const spyOnDrop = sinon.spy(() => { });
  882. let tree = getTree({
  883. draggable: true,
  884. onDrop: spyOnDrop
  885. });
  886. let dragNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(0);
  887. dragNode.simulate('dragStart');
  888. let dropNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(1);
  889. dropNode.simulate('drop');
  890. expect(spyOnDrop.calledOnce).toBe(true);
  891. expect(spyOnDrop.calledWithMatch({
  892. dragNode: dragNodeData,
  893. dragNodesKeys: ["yazhou","zhongguo","beijing","shanghai","riben","dongjing","daban"],
  894. dropPosition: 1
  895. })).toEqual(true);
  896. });
  897. it('DND - dragEnd event', () => {
  898. const spyOnDragEnd = sinon.spy(() => { });
  899. let tree = getTree({
  900. draggable: true,
  901. onDragEnd: spyOnDragEnd
  902. });
  903. let dragNode = tree.find('.semi-tree-option.semi-tree-option-level-1').at(0);
  904. dragNode.simulate('dragEnd');
  905. expect(spyOnDragEnd.calledOnce).toBe(true);
  906. expect(spyOnDragEnd.calledWithMatch({node: dragNodeData})).toEqual(true);
  907. });
  908. })