From c0bf68118201ba84dca3d555980badd40e987919 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 30 May 2024 17:08:08 +0200 Subject: [PATCH 1/3] Merge --- .../src/TreeItem/TreeItem.test.tsx | 74 +++++------------- .../src/TreeItem2/TreeItem2.test.tsx | 48 ++++++++++++ test/utils/describeSlotsConformance.tsx | 76 +++++++++++++++++++ test/utils/tree-view/fakeContextValue.ts | 40 ++++++++++ 4 files changed, 181 insertions(+), 57 deletions(-) create mode 100644 packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx create mode 100644 test/utils/describeSlotsConformance.tsx create mode 100644 test/utils/tree-view/fakeContextValue.ts diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx index 6256ac0bb6a7..fc5ee4cdf59c 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx @@ -2,47 +2,11 @@ import * as React from 'react'; import { expect } from 'chai'; import PropTypes from 'prop-types'; import { createRenderer } from '@mui/internal-test-utils'; -import { SimpleTreeViewPlugins } from '@mui/x-tree-view/SimpleTreeView/SimpleTreeView.plugins'; import { TreeItem, treeItemClasses as classes } from '@mui/x-tree-view/TreeItem'; -import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider'; import { TreeViewContext } from '@mui/x-tree-view/internals/TreeViewProvider/TreeViewContext'; import { describeConformance } from 'test/utils/describeConformance'; import { describeTreeView } from 'test/utils/tree-view/describeTreeView'; - -const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { - instance: { - isItemExpandable: () => false, - isItemExpanded: () => false, - isItemFocused: () => false, - isItemSelected: () => false, - isItemDisabled: (itemId: string | null): itemId is string => !!itemId, - getTreeItemIdAttribute: () => '', - mapFirstCharFromJSX: () => () => {}, - canItemBeTabbed: () => false, - } as any, - publicAPI: { - focusItem: () => {}, - getItem: () => ({}), - setItemExpansion: () => {}, - }, - runItemPlugins: () => ({ rootRef: null, contentRef: null }), - wrapItem: ({ children }) => children, - wrapRoot: ({ children }) => children, - disabledItemsFocusable: false, - indentationAtItemLevel: false, - icons: { - slots: {}, - slotProps: {}, - }, - selection: { - multiSelect: false, - checkboxSelection: false, - disableSelection: false, - }, - rootRef: { - current: null, - }, -}; +import { getFakeContextValue } from 'test/utils/tree-view/fakeContextValue'; describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) => { describe('ContentComponent / ContentProps props (TreeItem only)', () => { @@ -52,9 +16,9 @@ describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) = } const ContentComponent = React.forwardRef((props: any, ref: React.Ref) => ( -
- MOCK CONTENT COMPONENT -
+
+ MOCK CONTENT COMPONENT +
)); const response = render({ @@ -71,9 +35,9 @@ describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) = } const ContentComponent = React.forwardRef((props: any, ref: React.Ref) => ( -
- {props.customProp} -
+
+ {props.customProp} +
)); const response = render({ @@ -94,17 +58,13 @@ describe('', () => { inheritComponent: 'li', wrapMount: (mount) => (item: React.ReactNode) => { const wrapper = mount( - - {item} - , + {item}, ); return wrapper.childAt(0); }, render: (item) => { return render( - - {item} - , + {item}, ); }, muiName: 'MuiTreeItem', @@ -120,10 +80,10 @@ describe('', () => { it('should warn if an onFocus callback is supplied', () => { expect(() => { PropTypes.checkPropTypes( - TreeItem.propTypes, - { itemId: 'one', onFocus: () => {} }, - 'prop', - 'TreeItem', + TreeItem.propTypes, + { itemId: 'one', onFocus: () => {} }, + 'prop', + 'TreeItem', ); }).toErrorDev('Failed prop type: The prop `onFocus` is not supported.'); }); @@ -131,10 +91,10 @@ describe('', () => { it('should warn if an `ContentComponent` that does not hold a ref is used', () => { expect(() => { PropTypes.checkPropTypes( - TreeItem.propTypes, - { itemId: 'one', ContentComponent: () => {} }, - 'prop', - 'TreeItem', + TreeItem.propTypes, + { itemId: 'one', ContentComponent: () => {} }, + 'prop', + 'TreeItem', ); }).toErrorDev('Expected an element type that can hold a ref.'); }); diff --git a/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx b/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx new file mode 100644 index 000000000000..71fb2d7dfa94 --- /dev/null +++ b/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import { createRenderer } from '@mui/internal-test-utils'; +import { TreeItem2 } from '@mui/x-tree-view/TreeItem2'; +import { treeItemClasses as classes } from '@mui/x-tree-view/TreeItem'; +import { TreeViewContext } from '@mui/x-tree-view/internals/TreeViewProvider/TreeViewContext'; +import { describeConformance } from 'test/utils/describeConformance'; +import { getFakeContextValue} from 'test/utils/tree-view/fakeContextValue'; +import { describeSlotsConformance } from 'test/utils/describeSlotsConformance'; + +describe.only('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + classes, + inheritComponent: 'li', + wrapMount: (mount) => (item: React.ReactNode) => { + const wrapper = mount( + {item}, + ); + return wrapper.childAt(0); + }, + render: (item) => { + return render( + {item}, + ); + }, + muiName: 'MuiTreeItem2', + refInstanceof: window.HTMLLIElement, + skip: ['reactTestRenderer', 'componentProp', 'componentsProp', 'themeVariants'], + })); + + describeSlotsConformance({ + render, + getElement: ({ props, slotName }) => ( + + + + ), + slots: { + label: { className: classes.label }, + iconContainer: { className: classes.iconContainer }, + content: { className: classes.content }, + checkbox: { className: classes.checkbox }, + }, + }); +}); diff --git a/test/utils/describeSlotsConformance.tsx b/test/utils/describeSlotsConformance.tsx new file mode 100644 index 000000000000..ffb2e2da4eea --- /dev/null +++ b/test/utils/describeSlotsConformance.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import createDescribe from '@mui/internal-test-utils/createDescribe'; +import { MuiRenderResult } from '@mui/internal-test-utils/createRenderer'; + +interface DescribeSlotsConformanceParams { + getElement: (params: { slotName: string; props: any }) => React.ReactElement; + render: (node: React.ReactElement) => MuiRenderResult; + slots: { [slotName: string]: { className: string } }; +} + +export function innerDescribeSlotsConformance(params: DescribeSlotsConformanceParams) { + const { getElement, render, slots } = params; + + Object.keys(slots).forEach((slotName) => { + describe(`Slot: ${slotName}`, () => { + it('should replace the default slot when defined', () => { + const slotConfig = slots[slotName]; + const response = render( + getElement({ + slotName, + props: { + slots: { + [slotName]: React.forwardRef((props, ref: React.Ref) => ( +
+ )), + }, + }, + }), + ); + + // Check if the default slot is being rendered + expect(response.container.querySelector(`.${slotConfig.className}`)).to.equal(null); + + // Check if the custom slot is being rendered + expect(response.getByTestId('custom-slot')).to.not.equal(null); + }); + + it('should pass props to the default slot', () => { + const slotConfig = slots[slotName]; + const response = render( + getElement({ + slotName, + props: { + slotProps: { + [slotName]: { 'data-testid': 'default-slot', className: 'default-slot' }, + }, + }, + }), + ); + + const slotElement = response.container.querySelector(`.${slotConfig.className}`); + + // Check if the default slot is being rendered + expect(slotElement).not.to.equal(null); + + // Check if the default slot receives the `data-testid` + expect(slotElement).to.have.attribute('data-testid', 'default-slot'); + + // Check if the custom class is being applied + expect(slotElement).to.have.class('default-slot'); + + // Make sure that the default class has not been removed + expect(slotElement).to.have.class(slotConfig.className); + }); + }); + }); +} + +/** + * Test the slots of the component. + */ +export const describeSlotsConformance = createDescribe( + 'Slots conformance', + innerDescribeSlotsConformance, +); diff --git a/test/utils/tree-view/fakeContextValue.ts b/test/utils/tree-view/fakeContextValue.ts new file mode 100644 index 000000000000..8913c22c352e --- /dev/null +++ b/test/utils/tree-view/fakeContextValue.ts @@ -0,0 +1,40 @@ +import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider'; +import { SimpleTreeViewPlugins } from '@mui/x-tree-view/SimpleTreeView/SimpleTreeView.plugins'; + +export const getFakeContextValue = (features: { checkboxSelection?: boolean } = {}): TreeViewContextValue => ({ + instance: { + isItemExpandable: () => false, + isItemExpanded: () => false, + isItemFocused: () => false, + isItemSelected: () => false, + isItemDisabled: (itemId: string | null): itemId is string => !!itemId, + getTreeItemIdAttribute: () => '', + mapFirstCharFromJSX: () => () => {}, + canItemBeTabbed: () => false, + } as any, + publicAPI: { + focusItem: () => {}, + getItem: () => ({}), + setItemExpansion: () => {}, + }, + runItemPlugins: () => ({ + rootRef: null, + contentRef: null, + }), + wrapItem: ({ children }) => children, + wrapRoot: ({ children }) => children, + disabledItemsFocusable: false, + indentationAtItemLevel: false, + icons: { + slots: {}, + slotProps: {}, + }, + selection: { + multiSelect: false, + checkboxSelection: features.checkboxSelection ?? false, + disableSelection: false, + }, + rootRef: { + current: null, + }, +}); From d71a681e65d00af5c2eb760fba658cf038904b8d Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 30 May 2024 17:10:50 +0200 Subject: [PATCH 2/3] Fix --- .../src/TreeItem/TreeItem.test.tsx | 32 +++++++++---------- .../src/TreeItem2/TreeItem2.test.tsx | 18 +++++------ test/utils/tree-view/fakeContextValue.ts | 4 ++- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx index fc5ee4cdf59c..426275dd9f68 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx @@ -16,9 +16,9 @@ describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) = } const ContentComponent = React.forwardRef((props: any, ref: React.Ref) => ( -
- MOCK CONTENT COMPONENT -
+
+ MOCK CONTENT COMPONENT +
)); const response = render({ @@ -35,9 +35,9 @@ describeTreeView<[]>('TreeItem component', ({ render, treeItemComponentName }) = } const ContentComponent = React.forwardRef((props: any, ref: React.Ref) => ( -
- {props.customProp} -
+
+ {props.customProp} +
)); const response = render({ @@ -58,13 +58,13 @@ describe('', () => { inheritComponent: 'li', wrapMount: (mount) => (item: React.ReactNode) => { const wrapper = mount( - {item}, + {item}, ); return wrapper.childAt(0); }, render: (item) => { return render( - {item}, + {item}, ); }, muiName: 'MuiTreeItem', @@ -80,10 +80,10 @@ describe('', () => { it('should warn if an onFocus callback is supplied', () => { expect(() => { PropTypes.checkPropTypes( - TreeItem.propTypes, - { itemId: 'one', onFocus: () => {} }, - 'prop', - 'TreeItem', + TreeItem.propTypes, + { itemId: 'one', onFocus: () => {} }, + 'prop', + 'TreeItem', ); }).toErrorDev('Failed prop type: The prop `onFocus` is not supported.'); }); @@ -91,10 +91,10 @@ describe('', () => { it('should warn if an `ContentComponent` that does not hold a ref is used', () => { expect(() => { PropTypes.checkPropTypes( - TreeItem.propTypes, - { itemId: 'one', ContentComponent: () => {} }, - 'prop', - 'TreeItem', + TreeItem.propTypes, + { itemId: 'one', ContentComponent: () => {} }, + 'prop', + 'TreeItem', ); }).toErrorDev('Expected an element type that can hold a ref.'); }); diff --git a/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx b/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx index 71fb2d7dfa94..6476ec7eb8a9 100644 --- a/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx +++ b/packages/x-tree-view/src/TreeItem2/TreeItem2.test.tsx @@ -4,10 +4,10 @@ import { TreeItem2 } from '@mui/x-tree-view/TreeItem2'; import { treeItemClasses as classes } from '@mui/x-tree-view/TreeItem'; import { TreeViewContext } from '@mui/x-tree-view/internals/TreeViewProvider/TreeViewContext'; import { describeConformance } from 'test/utils/describeConformance'; -import { getFakeContextValue} from 'test/utils/tree-view/fakeContextValue'; +import { getFakeContextValue } from 'test/utils/tree-view/fakeContextValue'; import { describeSlotsConformance } from 'test/utils/describeSlotsConformance'; -describe.only('', () => { +describe('', () => { const { render } = createRenderer(); describeConformance(, () => ({ @@ -15,13 +15,13 @@ describe.only('', () => { inheritComponent: 'li', wrapMount: (mount) => (item: React.ReactNode) => { const wrapper = mount( - {item}, + {item}, ); return wrapper.childAt(0); }, render: (item) => { return render( - {item}, + {item}, ); }, muiName: 'MuiTreeItem2', @@ -32,11 +32,11 @@ describe.only('', () => { describeSlotsConformance({ render, getElement: ({ props, slotName }) => ( - - - + + + ), slots: { label: { className: classes.label }, diff --git a/test/utils/tree-view/fakeContextValue.ts b/test/utils/tree-view/fakeContextValue.ts index 8913c22c352e..98e9d8cb12f1 100644 --- a/test/utils/tree-view/fakeContextValue.ts +++ b/test/utils/tree-view/fakeContextValue.ts @@ -1,7 +1,9 @@ import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider'; import { SimpleTreeViewPlugins } from '@mui/x-tree-view/SimpleTreeView/SimpleTreeView.plugins'; -export const getFakeContextValue = (features: { checkboxSelection?: boolean } = {}): TreeViewContextValue => ({ +export const getFakeContextValue = ( + features: { checkboxSelection?: boolean } = {}, +): TreeViewContextValue => ({ instance: { isItemExpandable: () => false, isItemExpanded: () => false, From fc822229002d7e79ceb862e0f19abf451aaa499d Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 31 May 2024 08:28:47 +0200 Subject: [PATCH 3/3] Fix CI --- docs/pages/x/api/tree-view/tree-item-2.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/x/api/tree-view/tree-item-2.json b/docs/pages/x/api/tree-view/tree-item-2.json index 5a3135b2b98b..e6ef099e73e1 100644 --- a/docs/pages/x/api/tree-view/tree-item-2.json +++ b/docs/pages/x/api/tree-view/tree-item-2.json @@ -91,7 +91,10 @@ "isGlobal": true } ], + "spread": true, + "themeDefaultProps": true, "muiName": "MuiTreeItem2", + "forwardsRefTo": "HTMLLIElement", "filename": "/packages/x-tree-view/src/TreeItem2/TreeItem2.tsx", "inheritance": null, "demos": "",