tree.test.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import { describe, expect, it } from 'vitest';
  2. import { filterTree, mapTree, traverseTreeValues } from './tree';
  3. describe('traverseTreeValues', () => {
  4. interface Node {
  5. children?: Node[];
  6. name: string;
  7. }
  8. type NodeValue = string;
  9. const sampleTree: Node[] = [
  10. {
  11. name: 'A',
  12. children: [
  13. { name: 'B' },
  14. {
  15. name: 'C',
  16. children: [{ name: 'D' }, { name: 'E' }],
  17. },
  18. ],
  19. },
  20. {
  21. name: 'F',
  22. children: [
  23. { name: 'G' },
  24. {
  25. name: 'H',
  26. children: [{ name: 'I' }],
  27. },
  28. ],
  29. },
  30. ];
  31. it('traverses tree and returns all node values', () => {
  32. const values = traverseTreeValues<Node, NodeValue>(
  33. sampleTree,
  34. (node) => node.name,
  35. {
  36. childProps: 'children',
  37. },
  38. );
  39. expect(values).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']);
  40. });
  41. it('handles empty tree', () => {
  42. const values = traverseTreeValues<Node, NodeValue>([], (node) => node.name);
  43. expect(values).toEqual([]);
  44. });
  45. it('handles tree with only root node', () => {
  46. const rootNode = { name: 'A' };
  47. const values = traverseTreeValues<Node, NodeValue>(
  48. [rootNode],
  49. (node) => node.name,
  50. );
  51. expect(values).toEqual(['A']);
  52. });
  53. it('handles tree with only leaf nodes', () => {
  54. const leafNodes = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
  55. const values = traverseTreeValues<Node, NodeValue>(
  56. leafNodes,
  57. (node) => node.name,
  58. );
  59. expect(values).toEqual(['A', 'B', 'C']);
  60. });
  61. });
  62. describe('filterTree', () => {
  63. const tree = [
  64. {
  65. id: 1,
  66. children: [
  67. { id: 2 },
  68. { id: 3, children: [{ id: 4 }, { id: 5 }, { id: 6 }] },
  69. { id: 7 },
  70. ],
  71. },
  72. { id: 8, children: [{ id: 9 }, { id: 10 }] },
  73. { id: 11 },
  74. ];
  75. it('should return all nodes when condition is always true', () => {
  76. const result = filterTree(tree, () => true, { childProps: 'children' });
  77. expect(result).toEqual(tree);
  78. });
  79. it('should return only root nodes when condition is always false', () => {
  80. const result = filterTree(tree, () => false);
  81. expect(result).toEqual([]);
  82. });
  83. it('should return nodes with even id values', () => {
  84. const result = filterTree(tree, (node) => node.id % 2 === 0);
  85. expect(result).toEqual([{ id: 8, children: [{ id: 10 }] }]);
  86. });
  87. it('should return nodes with odd id values and their ancestors', () => {
  88. const result = filterTree(tree, (node) => node.id % 2 === 1);
  89. expect(result).toEqual([
  90. {
  91. id: 1,
  92. children: [{ id: 3, children: [{ id: 5 }] }, { id: 7 }],
  93. },
  94. { id: 11 },
  95. ]);
  96. });
  97. it('should return nodes with "leaf" in their name', () => {
  98. const tree = [
  99. {
  100. name: 'root',
  101. children: [
  102. { name: 'leaf 1' },
  103. {
  104. name: 'branch',
  105. children: [{ name: 'leaf 2' }, { name: 'leaf 3' }],
  106. },
  107. { name: 'leaf 4' },
  108. ],
  109. },
  110. ];
  111. const result = filterTree(
  112. tree,
  113. (node) => node.name.includes('leaf') || node.name === 'root',
  114. );
  115. expect(result).toEqual([
  116. {
  117. name: 'root',
  118. children: [{ name: 'leaf 1' }, { name: 'leaf 4' }],
  119. },
  120. ]);
  121. });
  122. });
  123. describe('mapTree', () => {
  124. it('map infinite depth tree using mapTree', () => {
  125. const tree = [
  126. {
  127. id: 1,
  128. name: 'node1',
  129. children: [
  130. { id: 2, name: 'node2' },
  131. { id: 3, name: 'node3' },
  132. {
  133. id: 4,
  134. name: 'node4',
  135. children: [
  136. {
  137. id: 5,
  138. name: 'node5',
  139. children: [
  140. { id: 6, name: 'node6' },
  141. { id: 7, name: 'node7' },
  142. ],
  143. },
  144. { id: 8, name: 'node8' },
  145. ],
  146. },
  147. ],
  148. },
  149. ];
  150. const newTree = mapTree(tree, (node) => ({
  151. ...node,
  152. name: `${node.name}-new`,
  153. }));
  154. expect(newTree).toEqual([
  155. {
  156. id: 1,
  157. name: 'node1-new',
  158. children: [
  159. { id: 2, name: 'node2-new' },
  160. { id: 3, name: 'node3-new' },
  161. {
  162. id: 4,
  163. name: 'node4-new',
  164. children: [
  165. {
  166. id: 5,
  167. name: 'node5-new',
  168. children: [
  169. { id: 6, name: 'node6-new' },
  170. { id: 7, name: 'node7-new' },
  171. ],
  172. },
  173. { id: 8, name: 'node8-new' },
  174. ],
  175. },
  176. ],
  177. },
  178. ]);
  179. });
  180. });