Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Use describeTreeView for icons tests #12672

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 7 additions & 3 deletions packages/x-tree-view/src/RichTreeView/RichTreeView.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import {
DefaultTreeViewPluginSlots,
DefaultTreeViewPlugins,
} from '../internals/plugins/defaultPlugins';
import { TreeItem, TreeItemProps } from '../TreeItem';
import { TreeItemProps } from '../TreeItem';
import { TreeItem2Props } from '../TreeItem2';
import { TreeViewItemId } from '../models';
import { TreeViewPublicAPI } from '../internals/models';
import { SlotComponentPropsFromProps, TreeViewPublicAPI } from '../internals/models';

interface RichTreeViewItemSlotOwnerState {
itemId: TreeViewItemId;
Expand All @@ -35,7 +35,11 @@ export interface RichTreeViewSlots extends DefaultTreeViewPluginSlots {
export interface RichTreeViewSlotProps<R extends {}, Multiple extends boolean | undefined>
extends DefaultTreeViewPluginSlotProps {
root?: SlotComponentProps<'ul', {}, RichTreeViewProps<R, Multiple>>;
item?: SlotComponentProps<typeof TreeItem, {}, RichTreeViewItemSlotOwnerState>;
item?: SlotComponentPropsFromProps<
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some typing issues while writing those tests so I improved the typing of this slot.

SlotComponentPropsFromProps allows us to skip the typeof TreeItem which can be expensive.
I also added TreeItem2Props which was completely missing

TreeItemProps | TreeItem2Props,
{},
RichTreeViewItemSlotOwnerState
>;
}

export type RichTreeViewApiRef = React.MutableRefObject<
Expand Down
40 changes: 0 additions & 40 deletions packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,46 +106,6 @@ describe('<TreeItem />', () => {
expect(handleClick.callCount).to.equal(1);
});

it('should display the right icons', () => {
const { getByTestId } = render(
<SimpleTreeView
slots={{
expandIcon: () => <div data-test="defaultExpandIcon" />,
collapseIcon: () => <div data-test="defaultCollapseIcon" />,
endIcon: () => <div data-test="defaultEndIcon" />,
}}
defaultExpandedItems={['1']}
>
<TreeItem itemId="1" label="1" data-testid="1">
<TreeItem itemId="2" label="2" data-testid="2" />
<TreeItem
itemId="5"
label="5"
data-testid="5"
slots={{ icon: () => <div data-test="icon" /> }}
/>
<TreeItem
itemId="6"
label="6"
data-testid="6"
slots={{ endIcon: () => <div data-test="endIcon" /> }}
/>
</TreeItem>
<TreeItem itemId="3" label="3" data-testid="3">
<TreeItem itemId="4" label="4" data-testid="4" />
</TreeItem>
</SimpleTreeView>,
);

const getIcon = (testId) => getByTestId(testId).querySelector(`.${classes.iconContainer} div`);

expect(getIcon('1')).attribute('data-test').to.equal('defaultCollapseIcon');
expect(getIcon('2')).attribute('data-test').to.equal('defaultEndIcon');
expect(getIcon('3')).attribute('data-test').to.equal('defaultExpandIcon');
expect(getIcon('5')).attribute('data-test').to.equal('icon');
expect(getIcon('6')).attribute('data-test').to.equal('endIcon');
});

it('should allow conditional child', () => {
function TestComponent() {
const [hide, setState] = React.useState(false);
Expand Down
6 changes: 5 additions & 1 deletion packages/x-tree-view/src/TreeItem2/TreeItem2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ const useUtilityClasses = (ownerState: TreeItem2OwnerState) => {
return composeClasses(slots, getTreeItemUtilityClass, classes);
};

type TreeItem2Component = ((
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to have this one for consistency

props: TreeItem2Props & React.RefAttributes<HTMLLIElement>,
) => React.JSX.Element) & { propTypes?: any };

/**
*
* Demos:
Expand Down Expand Up @@ -264,7 +268,7 @@ export const TreeItem2 = React.forwardRef(function TreeItem2(
</Root>
</TreeItem2Provider>
);
});
}) as TreeItem2Component;

TreeItem2.propTypes = {
// ----------------------------- Warning --------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useTreeItem2Utils } from '@mui/x-tree-view/hooks';
* All tests related to keyboard navigation (e.g.: expanding using "Enter" and "ArrowRight")
* are located in the `useTreeViewKeyboardNavigation.test.tsx` file.
*/
describeTreeView<UseTreeViewExpansionSignature>(
describeTreeView<[UseTreeViewExpansionSignature]>(
'useTreeViewExpansion plugin',
({ render, setup }) => {
describe('model props (expandedItems, defaultExpandedItems, onExpandedItemsChange)', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import * as React from 'react';
import { expect } from 'chai';
import {
describeTreeView,
DescribeTreeViewRendererReturnValue,
} from 'test/utils/tree-view/describeTreeView';
import {
UseTreeViewExpansionSignature,
UseTreeViewIconsSignature,
} from '@mui/x-tree-view/internals';

describeTreeView<[UseTreeViewIconsSignature, UseTreeViewExpansionSignature]>(
'useTreeViewIcons plugin',
({ render }) => {
describe('slots (expandIcon, collapseIcon, endIcon, icon)', () => {
const getIconTestId = (response: DescribeTreeViewRendererReturnValue<[]>, itemId: string) =>
response.getItemIconContainer(itemId).querySelector(`div`)?.dataset.testid;

it('should render the expandIcon slot defined on the tree if no icon is defined on the item and the item is collapsed', () => {
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
});

expect(getIconTestId(response, '1')).to.equal('treeExpandIcon');
});

it('should render the collapseIcon slot defined on the tree if no icon is defined on the item and the item is expanded', () => {
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
defaultExpandedItems: ['1'],
});

expect(getIconTestId(response, '1')).to.equal('treeCollapseIcon');
});

it('should render the endIcon slot defined on the tree if no icon is defined on the item and the item has no children', () => {
const response = render({
items: [{ id: '1' }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
});

expect(getIconTestId(response, '1')).to.equal('treeEndIcon');
});

it('should render the expandIcon slot defined on the item if the item is collapsed', () => {
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
},
},
},
});

expect(getIconTestId(response, '1')).to.equal('itemExpandIcon');
});

it('should render the collapseIcon slot defined on the item if the item is expanded', () => {
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
},
},
},
defaultExpandedItems: ['1'],
});

expect(getIconTestId(response, '1')).to.equal('itemCollapseIcon');
});

it('should render the endIcon slot defined on the tree if the item has no children', () => {
const response = render({
items: [{ id: '1' }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
},
},
},
});

expect(getIconTestId(response, '1')).to.equal('itemEndIcon');
});

it('should render the icon slot defined on the item if the item is collapsed', () => {
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
icon: () => <div data-testid="itemIcon" />,
},
},
},
});

expect(getIconTestId(response, '1')).to.equal('itemIcon');
});

it('should render the icon slot defined on the item if the item is expanded', () => {
const response = render({
items: [{ id: '1', children: [{ id: '1.1' }] }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
icon: () => <div data-testid="itemIcon" />,
},
},
},
defaultExpandedItems: ['1'],
});

expect(getIconTestId(response, '1')).to.equal('itemIcon');
});

it('should render the icon slot defined on the item if the item has no children', () => {
const response = render({
items: [{ id: '1' }],
slots: {
expandIcon: () => <div data-testid="treeExpandIcon" />,
collapseIcon: () => <div data-testid="treeCollapseIcon" />,
endIcon: () => <div data-testid="treeEndIcon" />,
},
slotProps: {
item: {
slots: {
expandIcon: () => <div data-testid="itemExpandIcon" />,
collapseIcon: () => <div data-testid="itemCollapseIcon" />,
endIcon: () => <div data-testid="itemEndIcon" />,
icon: () => <div data-testid="itemIcon" />,
},
},
},
});

expect(getIconTestId(response, '1')).to.equal('itemIcon');
});
});
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { UseTreeViewSelectionSignature } from '@mui/x-tree-view/internals';
* All tests related to keyboard navigation (e.g.: selection using "Space")
* are located in the `useTreeViewKeyboardNavigation.test.tsx` file.
*/
describeTreeView<UseTreeViewSelectionSignature>('useTreeViewSelection plugin', ({ render }) => {
describeTreeView<[UseTreeViewSelectionSignature]>('useTreeViewSelection plugin', ({ render }) => {
describe('model props (selectedItems, defaultSelectedItems, onSelectedItemsChange)', () => {
it('should not select items when no default state and no control state are defined', () => {
const response = render({
Expand Down