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": "
",
diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
index 49a9702b6f23..426275dd9f68 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 { SimpleTreeViewPluginSignatures } 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)', () => {
@@ -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',
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..6476ec7eb8a9
--- /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('', () => {
+ 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..5f4e44545102
--- /dev/null
+++ b/test/utils/tree-view/fakeContextValue.ts
@@ -0,0 +1,42 @@
+import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider';
+import { SimpleTreeViewPluginSignatures } 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,
+ },
+});