From 4ed9e5c7d6860f3466e5d058b650c3b45ca00ebc Mon Sep 17 00:00:00 2001 From: Laura Silva <91160746+silvalaura@users.noreply.github.com> Date: Sat, 14 Dec 2024 10:18:30 -0500 Subject: [PATCH] fix(TreeView): Add more unit tests (#1600) --- .changeset/tree-unitTests.md | 5 + .../components/TreeView/TreeView.stories.tsx | 41 ++- .../src/components/TreeView/TreeView.test.js | 234 +++++++++++++++++- .../src/components/TreeView/useTreeView.ts | 4 +- .../src/pages/api/tree-view.mdx | 2 +- 5 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 .changeset/tree-unitTests.md diff --git a/.changeset/tree-unitTests.md b/.changeset/tree-unitTests.md new file mode 100644 index 000000000..e046d47b0 --- /dev/null +++ b/.changeset/tree-unitTests.md @@ -0,0 +1,5 @@ +--- +'react-magma-dom': patch +--- + +fix(TreeView): Add more unit tests diff --git a/packages/react-magma-dom/src/components/TreeView/TreeView.stories.tsx b/packages/react-magma-dom/src/components/TreeView/TreeView.stories.tsx index fa37ce94b..59b818371 100644 --- a/packages/react-magma-dom/src/components/TreeView/TreeView.stories.tsx +++ b/packages/react-magma-dom/src/components/TreeView/TreeView.stories.tsx @@ -1331,12 +1331,29 @@ export const ComplexTreeWithShowAll = (args: Partial) => { { id: 'ad-1', title: 'Animation', - children: [], + children: null, }, { id: 'ad-2', title: 'Photography', - children: [], + children: [ + { + id: 'ad-2-child1', + title: 'Wedding', + children: [], + }, + { + id: 'ad-2-child2', + title: 'Nature', + children: [ + { + id: 'ad-2-child2-child1', + title: 'Pet', + children: [], + } + ], + } + ], }, { id: 'ad-3', @@ -1380,7 +1397,7 @@ export const ComplexTreeWithShowAll = (args: Partial) => { { id: 'discipline-geography', title: 'Geography', - children: [], + children: undefined, }, { id: 'discipline-his', @@ -1436,7 +1453,23 @@ export const ComplexTreeWithShowAll = (args: Partial) => { { id: 'nutr-2', title: 'Sports Nutrition', - children: [], + children: [ + { + id: 'nutr-2-child1', + title: 'Protein', + children: [], + }, + { + id: 'nutr-2-child2', + title: 'Supplements', + children: [ + { + id: 'nutr-2-child2-child1', + title: 'Creatine' + } + ], + } + ], }, ], }, diff --git a/packages/react-magma-dom/src/components/TreeView/TreeView.test.js b/packages/react-magma-dom/src/components/TreeView/TreeView.test.js index 878c2aee3..8d048f47d 100644 --- a/packages/react-magma-dom/src/components/TreeView/TreeView.test.js +++ b/packages/react-magma-dom/src/components/TreeView/TreeView.test.js @@ -172,6 +172,25 @@ const TreeItemsMultiLevelControlledOutside = props => { ); }; +const renderTreeItemsRecursively = (treeItems, depth) => { + return treeItems.map(item => { + return ( + + {item.children?.length ? ( + renderTreeItemsRecursively(item.children, depth + 1) + ) : ( + <> + )} + + ); + }); +}; + describe('TreeView', () => { it('should find element by testId', () => { const { getByTestId } = render( @@ -2058,7 +2077,7 @@ describe('TreeView', () => { it('parent should have checked checkbox state when all disabled children are selected and all enabled children are selected. parent should have indeterminate checkbox state when all disabled children are selected and enabled children are partially selected. parent should have indeterminate checkbox state when all disabled children are selected and all enabled children are not selected. and toggle children selection', () => { const onSelectedItemChange = jest.fn(); - const { getByTestId, debug } = render( + const { getByTestId } = render( getTreeItemsWithDisabledChildren({ selectable: TreeViewSelectable.multi, preselectedItems: [ @@ -2598,6 +2617,219 @@ describe('TreeView', () => { }); }); + describe('recursive children', () => { + const recursiveTreeItems = [ + { + id: 'discipline-arts-design', + title: 'Arts and Design', + children: [ + { + id: 'ad-1', + title: 'Animation', + children: [], + }, + { + id: 'ad-2', + title: 'Photography', + children: [ + { + id: 'ad-2-child1', + title: 'Wedding', + children: [], + }, + { + id: 'ad-2-child2', + title: 'Nature', + children: [ + { + id: 'ad-2-child2-child1', + title: 'Pet', + children: [], + }, + ], + }, + ], + }, + { + id: 'ad-3', + title: 'Web Design', + children: [], + }, + ], + }, + { + id: 'discipline-geography', + title: 'Geography', + children: [], + }, + { + id: 'discipline-nutr', + title: 'Nutrition', + children: [ + { + id: 'nutr-1', + title: 'Community Nutrition', + children: [], + }, + { + id: 'nutr-2', + title: 'Sports Nutrition', + children: [ + { + id: 'nutr-2-child1', + title: 'Protein', + children: [], + }, + { + id: 'nutr-2-child2', + title: 'Supplements', + children: [ + { + id: 'nutr-2-child2-child1', + title: 'Creatine', + children: [ + { + id: 'nutr-2-child2-child1-child1', + title: 'Is it safe?', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ]; + + it('can render recursively created children', () => { + const { getByTestId } = render( + {renderTreeItemsRecursively(recursiveTreeItems, 0)} + ); + + expect(getByTestId('discipline-arts-design')).toBeInTheDocument(); + expect(getByTestId('discipline-geography')).toBeInTheDocument(); + expect(getByTestId('discipline-nutr')).toBeInTheDocument(); + + userEvent.click(getByTestId('discipline-arts-design-expand')); + expect(getByTestId('ad-1')).toBeInTheDocument(); + expect(getByTestId('ad-2')).toBeInTheDocument(); + expect(getByTestId('ad-3')).toBeInTheDocument(); + userEvent.click(getByTestId('ad-2-expand')); + expect(getByTestId('ad-2-child1')).toBeInTheDocument(); + expect(getByTestId('ad-2-child2')).toBeInTheDocument(); + userEvent.click(getByTestId('ad-2-child2-expand')); + expect(getByTestId('ad-2-child2-child1')).toBeInTheDocument(); + + userEvent.click(getByTestId('discipline-nutr-expand')); + expect(getByTestId('nutr-1')).toBeInTheDocument(); + expect(getByTestId('nutr-2')).toBeInTheDocument(); + userEvent.click(getByTestId('nutr-2-expand')); + expect(getByTestId('nutr-2-child1')).toBeInTheDocument(); + expect(getByTestId('nutr-2-child2')).toBeInTheDocument(); + userEvent.click(getByTestId('nutr-2-child2-expand')); + expect(getByTestId('nutr-2-child2-child1')).toBeInTheDocument(); + userEvent.click(getByTestId('nutr-2-child2-child1-expand')); + expect(getByTestId('nutr-2-child2-child1-child1')).toBeInTheDocument(); + }); + + it('can render recursively created children with preselected items', () => { + const { getByTestId } = render( + + {renderTreeItemsRecursively(recursiveTreeItems, 0)} + + ); + + expect(getByTestId('discipline-arts-design')).toBeInTheDocument(); + expect(getByTestId('discipline-geography')).toBeInTheDocument(); + expect(getByTestId('discipline-nutr')).toBeInTheDocument(); + expect(getByTestId('discipline-geography')).toHaveAttribute( + 'aria-checked', + 'true' + ); + + userEvent.click(getByTestId('discipline-arts-design-expand')); + expect(getByTestId('ad-1')).toBeInTheDocument(); + expect(getByTestId('ad-2')).toBeInTheDocument(); + expect(getByTestId('ad-3')).toBeInTheDocument(); + userEvent.click(getByTestId('ad-2-expand')); + expect(getByTestId('ad-2-child1')).toBeInTheDocument(); + expect(getByTestId('ad-2-child2')).toBeInTheDocument(); + userEvent.click(getByTestId('ad-2-child2-expand')); + expect(getByTestId('ad-2-child2-child1')).toBeInTheDocument(); + expect(getByTestId('discipline-arts-design')).toHaveAttribute( + 'aria-checked', + 'mixed' + ); + expect(getByTestId('ad-1')).toHaveAttribute('aria-checked', 'true'); + }); + + it('can select and deselect recursively created children', () => { + const { getByTestId } = render( + + {renderTreeItemsRecursively(recursiveTreeItems, 0)} + + ); + + expect(getByTestId('discipline-arts-design')).toBeInTheDocument(); + expect(getByTestId('discipline-geography')).toBeInTheDocument(); + expect(getByTestId('discipline-nutr')).toBeInTheDocument(); + + userEvent.click(getByTestId('discipline-nutr-expand')); + expect(getByTestId('nutr-1')).toHaveAttribute('aria-checked', 'false'); + expect(getByTestId('nutr-2')).toHaveAttribute('aria-checked', 'false'); + + userEvent.click(getByTestId('nutr-2-expand')); + expect(getByTestId('nutr-2-child1')).toBeInTheDocument(); + expect(getByTestId('nutr-2-child2')).toBeInTheDocument(); + + userEvent.click(getByTestId('nutr-2-child2-expand')); + userEvent.click(getByTestId('nutr-2-child2-checkbox')); + expect(getByTestId('nutr-2-child2')).toHaveAttribute( + 'aria-checked', + 'true' + ); + expect(getByTestId('nutr-2-child2-child1')).toHaveAttribute( + 'aria-checked', + 'true' + ); + userEvent.click(getByTestId('nutr-2-child2-child1-expand')); + expect(getByTestId('nutr-2-child2-child1-child1')).toHaveAttribute( + 'aria-checked', + 'true' + ); + + expect(getByTestId('nutr-2')).toHaveAttribute('aria-checked', 'mixed'); + expect(getByTestId('discipline-nutr')).toHaveAttribute( + 'aria-checked', + 'mixed' + ); + userEvent.click(getByTestId('nutr-2-child1-checkbox')); + expect(getByTestId('nutr-2')).toHaveAttribute('aria-checked', 'true'); + userEvent.click(getByTestId('nutr-2-child2-child1-child1-checkbox')); + expect(getByTestId('nutr-2-child1')).toHaveAttribute( + 'aria-checked', + 'true' + ); + expect(getByTestId('nutr-2-child2')).toHaveAttribute( + 'aria-checked', + 'false' + ); + }); + }); + describe('tree with hidden items', () => { const propsFlatTree = { title: 'Chapter/Subchapter', diff --git a/packages/react-magma-dom/src/components/TreeView/useTreeView.ts b/packages/react-magma-dom/src/components/TreeView/useTreeView.ts index 28f9c8ae9..b99f159e1 100644 --- a/packages/react-magma-dom/src/components/TreeView/useTreeView.ts +++ b/packages/react-magma-dom/src/components/TreeView/useTreeView.ts @@ -152,8 +152,6 @@ export function useTreeView(props: UseTreeViewProps) { }); const selectedItems = React.useMemo(() => { - console.log(items); - return items.filter( item => item.checkedStatus === IndeterminateCheckboxStatus.checked ); @@ -167,7 +165,7 @@ export function useTreeView(props: UseTreeViewProps) { }, [items, rawInitialExpandedItems]); const itemToFocus = React.useMemo(() => { - const enabledItems = items.filter(item => !item?.isDisabled); + const enabledItems = items.filter(item => !item.isDisabled); const [firstItem] = enabledItems; if (selectable === TreeViewSelectable.off) { diff --git a/website/react-magma-docs/src/pages/api/tree-view.mdx b/website/react-magma-docs/src/pages/api/tree-view.mdx index d65a53690..0ad6dbf90 100644 --- a/website/react-magma-docs/src/pages/api/tree-view.mdx +++ b/website/react-magma-docs/src/pages/api/tree-view.mdx @@ -880,7 +880,7 @@ export function Example() { } ``` -## Show All / Show Less Button +## Show More / Show Less Button Use the `apiRef.showMore()` prop when using a Show All button inside a tree, and `apiRef.showLess()` when using a Show Less button.