tree.test.js 38 KB

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