diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
index d811edeb77b6..5ea5973c0010 100644
--- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
+++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
@@ -201,497 +201,6 @@ describe('', () => {
expect(getByRole('group')).to.contain(getByText('test2'));
});
- describe('Navigation', () => {
- describe('right arrow interaction', () => {
- it('should open the item and not move the focus if focus is on a closed item', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowRight' });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
- expect(getByTestId('one')).toHaveFocus();
- });
-
- it('should move focus to the first child if focus is on an open item', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowRight' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
-
- it('should do nothing if focus is on an end item', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowRight' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
- });
-
- describe('left arrow interaction', () => {
- it('should close the item if focus is on an open item', () => {
- const { getByTestId, getByText } = render(
-
-
-
-
- ,
- );
-
- fireEvent.click(getByText('one'));
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowLeft' });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
- expect(getByTestId('one')).toHaveFocus();
- });
-
- it("should move focus to the item's parent item if focus is on a child item that is an end item", () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowLeft' });
-
- expect(getByTestId('one')).toHaveFocus();
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
- });
-
- it("should move focus to the item's parent item if focus is on a child item that is closed", () => {
- const { getByTestId } = render(
-
-
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowLeft' });
-
- expect(getByTestId('one')).toHaveFocus();
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
- });
-
- it('should do nothing if focus is on a root item that is closed', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowLeft' });
- expect(getByTestId('one')).toHaveFocus();
- });
-
- it('should do nothing if focus is on a root item that is an end item', () => {
- const { getByTestId } = render(
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowLeft' });
-
- expect(getByTestId('one')).toHaveFocus();
- });
- });
-
- describe('down arrow interaction', () => {
- it('moves focus to a sibling item', () => {
- const { getByTestId } = render(
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowDown' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
-
- it('moves focus to a child item', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowDown' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
-
- it('moves focus to a child item works with a dynamic tree', () => {
- function TestComponent() {
- const [hide, setState] = React.useState(false);
-
- return (
-
-
-
- {!hide && (
-
-
-
- )}
-
-
-
- );
- }
-
- const { queryByTestId, getByTestId, getByText } = render();
-
- expect(getByTestId('one')).not.to.equal(null);
- fireEvent.click(getByText('Toggle Hide'));
- expect(queryByTestId('one')).to.equal(null);
- fireEvent.click(getByText('Toggle Hide'));
- expect(getByTestId('one')).not.to.equal(null);
-
- act(() => {
- getByTestId('one').focus();
- });
- fireEvent.keyDown(getByTestId('one'), { key: 'ArrowDown' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
-
- it("moves focus to a parent's sibling", () => {
- const { getByTestId } = render(
-
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowDown' });
-
- expect(getByTestId('three')).toHaveFocus();
- });
- });
-
- describe('up arrow interaction', () => {
- it('moves focus to a sibling item', () => {
- const { getByTestId } = render(
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowUp' });
-
- expect(getByTestId('one')).toHaveFocus();
- });
-
- it('moves focus to a parent', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('two').focus();
- });
-
- expect(getByTestId('two')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('two'), { key: 'ArrowUp' });
-
- expect(getByTestId('one')).toHaveFocus();
- });
-
- it("moves focus to a sibling's child", () => {
- const { getByTestId } = render(
-
-
-
-
-
- ,
- );
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- act(() => {
- getByTestId('three').focus();
- });
-
- expect(getByTestId('three')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('three'), { key: 'ArrowUp' });
-
- expect(getByTestId('two')).toHaveFocus();
- });
- });
-
- describe('home key interaction', () => {
- it('moves focus to the first item in the tree', () => {
- const { getByTestId } = render(
-
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('four').focus();
- });
-
- expect(getByTestId('four')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('four'), { key: 'Home' });
-
- expect(getByTestId('one')).toHaveFocus();
- });
- });
-
- describe('end key interaction', () => {
- it('moves focus to the last item in the tree without expanded items', () => {
- const { getByTestId } = render(
-
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('one'), { key: 'End' });
-
- expect(getByTestId('four')).toHaveFocus();
- });
-
- it('moves focus to the last item in the tree with expanded items', () => {
- const { getByTestId } = render(
-
-
-
-
-
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).toHaveFocus();
-
- fireEvent.keyDown(getByTestId('one'), { key: 'End' });
-
- expect(getByTestId('six')).toHaveFocus();
- });
- });
-
- describe('asterisk key interaction', () => {
- it('expands all siblings that are at the same level as the current item', () => {
- const onExpandedItemsChange = spy();
-
- const { getByTestId } = render(
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
- expect(getByTestId('three')).to.have.attribute('aria-expanded', 'false');
- expect(getByTestId('five')).to.have.attribute('aria-expanded', 'false');
-
- fireEvent.keyDown(getByTestId('one'), { key: '*' });
-
- expect(onExpandedItemsChange.args[0][1]).to.have.length(3);
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
- expect(getByTestId('three')).to.have.attribute('aria-expanded', 'true');
- expect(getByTestId('five')).to.have.attribute('aria-expanded', 'true');
- expect(getByTestId('six')).to.have.attribute('aria-expanded', 'false');
- expect(getByTestId('eight')).not.to.have.attribute('aria-expanded');
- });
- });
- });
-
- describe('Expansion', () => {
- describe('enter key interaction', () => {
- it('expands an item with children', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
-
- fireEvent.keyDown(getByTestId('one'), { key: 'Enter' });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
- });
-
- it('collapses an item with children', () => {
- const { getByTestId } = render(
-
-
-
-
- ,
- );
-
- act(() => {
- getByTestId('one').focus();
- });
-
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
-
- fireEvent.keyDown(getByTestId('one'), { key: 'Enter' });
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'true');
-
- fireEvent.keyDown(getByTestId('one'), { key: 'Enter' });
- expect(getByTestId('one')).to.have.attribute('aria-expanded', 'false');
- });
- });
- });
-
describe('Single Selection', () => {
describe('keyboard', () => {
it('should select an item when space is pressed', () => {
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.test.tsx
index 5b5c7a4990f5..6cf0805ab397 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.test.tsx
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.test.tsx
@@ -3,206 +3,553 @@ import { expect } from 'chai';
import { act, fireEvent } from '@mui-internal/test-utils';
import { describeTreeView } from 'test/utils/tree-view/describeTreeView';
import {
+ UseTreeViewExpansionSignature,
UseTreeViewItemsSignature,
UseTreeViewKeyboardNavigationSignature,
} from '@mui/x-tree-view/internals';
-describeTreeView<[UseTreeViewKeyboardNavigationSignature, UseTreeViewItemsSignature]>(
- 'useTreeViewKeyboardNavigation',
- ({ render, treeViewComponent }) => {
- describe('Type-ahead', () => {
- it('should move the focus to the next item with a name that starts with the typed character', () => {
- const { getFocusedItemId, getItemRoot } = render({
- items: [
- { id: '1', label: 'one' },
- { id: '2', label: 'two' },
- { id: '3', label: 'three' },
- { id: '4', label: 'four' },
- ],
+describeTreeView<
+ [UseTreeViewKeyboardNavigationSignature, UseTreeViewItemsSignature, UseTreeViewExpansionSignature]
+>('useTreeViewKeyboardNavigation', ({ render, treeViewComponent }) => {
+ describe('Navigation (focus and expansion)', () => {
+ describe('key: ArrowDown', () => {
+ it('should move the focus to a sibling item', () => {
+ const response = render({
+ items: [{ id: '1' }, { id: '2' }],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
-
- fireEvent.keyDown(getItemRoot('1'), { key: 't' });
- expect(getFocusedItemId()).to.equal('2');
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowDown' });
+ expect(response.getFocusedItemId()).to.equal('2');
+ });
- fireEvent.keyDown(getItemRoot('2'), { key: 'f' });
- expect(getFocusedItemId()).to.equal('4');
+ it('should move the focus to a child item', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
+ });
- fireEvent.keyDown(getItemRoot('4'), { key: 'o' });
- expect(getFocusedItemId()).to.equal('1');
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowDown' });
+ expect(response.getFocusedItemId()).to.equal('1.1');
});
- it('should move to the next item in the displayed order when typing the same starting character', () => {
- const { getFocusedItemId, getItemRoot } = render({
- items: [{ id: 'A1' }, { id: 'B1' }, { id: 'A2' }, { id: 'B3' }, { id: 'B2' }],
+ it('should move the focus to a child item with a dynamic tree', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }, { id: '2' }],
+ defaultExpandedItems: ['1'],
});
+ response.setItems([{ id: '2' }]);
+ response.setItems([{ id: '1', children: [{ id: '1.1' }] }, { id: '2' }]);
act(() => {
- getItemRoot('A1').focus();
+ response.getItemRoot('1').focus();
});
- expect(getFocusedItemId()).to.equal('A1');
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowDown' });
+ expect(response.getFocusedItemId()).to.equal('1.1');
+ });
- fireEvent.keyDown(getItemRoot('A1'), { key: 'b' });
- expect(getFocusedItemId()).to.equal('B1');
+ it("should move the focus to a parent's sibling", () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }, { id: '2' }] }],
+ defaultExpandedItems: ['1'],
+ });
- fireEvent.keyDown(getItemRoot('B1'), { key: 'b' });
- expect(getFocusedItemId()).to.equal('B3');
+ act(() => {
+ response.getItemRoot('1.1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1.1'), { key: 'ArrowDown' });
+ expect(response.getFocusedItemId()).to.equal('2');
+ });
+ });
- fireEvent.keyDown(getItemRoot('B3'), { key: 'b' });
- expect(getFocusedItemId()).to.equal('B2');
+ describe('key: ArrowUp', () => {
+ it('should move the focus to a sibling item', () => {
+ const response = render({
+ items: [{ id: '1' }, { id: '2' }],
+ });
- fireEvent.keyDown(getItemRoot('B2'), { key: 'b' });
- expect(getFocusedItemId()).to.equal('B1');
+ act(() => {
+ response.getItemRoot('2').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('2'), { key: 'ArrowUp' });
+ expect(response.getFocusedItemId()).to.equal('1');
});
- it('should work with capitalized label', () => {
- const { getFocusedItemId, getItemRoot } = render({
- items: [
- { id: '1', label: 'One' },
- { id: '2', label: 'Two' },
- { id: '3', label: 'Three' },
- { id: '4', label: 'Four' },
- ],
+ it('should move the focus to a parent', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1.1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
+ fireEvent.keyDown(response.getItemRoot('1.1'), { key: 'ArrowUp' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: 't' });
- expect(getFocusedItemId()).to.equal('2');
+ it("should move the focus to a sibling's child", () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }, { id: '2' }],
+ defaultExpandedItems: ['1'],
+ });
- fireEvent.keyDown(getItemRoot('2'), { key: 'f' });
- expect(getFocusedItemId()).to.equal('4');
+ act(() => {
+ response.getItemRoot('2').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('2'), { key: 'ArrowUp' });
+ expect(response.getFocusedItemId()).to.equal('1.1');
+ });
+ });
- fireEvent.keyDown(getItemRoot('4'), { key: 'o' });
- expect(getFocusedItemId()).to.equal('1');
+ describe('key: ArrowRight', () => {
+ it('should open the item and not move the focus if the focus is on a closed item', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowRight' });
+ expect(response.isItemExpanded('1')).to.equal(true);
+ expect(response.getFocusedItemId()).to.equal('1');
});
- it('should work with ReactElement label', function test() {
- // Only the SimpleTreeView can have React Element labels.
- if (treeViewComponent !== 'SimpleTreeView') {
- this.skip();
- }
+ it('should move the focus to the first child if the focus is on an open item', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
+ });
- const { getFocusedItemId, getItemRoot } = render({
- items: [
- { id: '1', label: one },
- { id: '2', label: two },
- { id: '3', label: three },
- { id: '4', label: four },
- ],
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowRight' });
+ expect(response.getFocusedItemId()).to.equal('1.1');
+ });
+
+ it('should do nothing if the focus is on a leaf', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1.1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
+ fireEvent.keyDown(response.getItemRoot('1.1'), { key: 'ArrowRight' });
+ expect(response.getFocusedItemId()).to.equal('1.1');
+ });
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: 't' });
- expect(getFocusedItemId()).to.equal('2');
+ describe('key: ArrowLeft', () => {
+ it('should close the item if the focus is on an open item', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
+ });
- fireEvent.keyDown(getItemRoot('2'), { key: 'f' });
- expect(getFocusedItemId()).to.equal('4');
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowLeft' });
+ expect(response.isItemExpanded('1')).to.equal(false);
+ });
- fireEvent.keyDown(getItemRoot('4'), { key: 'o' });
- expect(getFocusedItemId()).to.equal('1');
+ it("should move focus to the item's parent if the focus is on a child item that is a leaf", () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
+ });
+
+ act(() => {
+ response.getItemRoot('1.1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1.1'), { key: 'ArrowLeft' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ expect(response.isItemExpanded('1')).to.equal(true);
});
- it('should work after adding / removing items', () => {
- const { getFocusedItemId, getItemRoot, setItems } = render({
- items: [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }],
+ it("should move the focus to the item's parent if the focus is on a child item that is closed", () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1', children: [{ id: '1.1.1' }] }] }],
+ defaultExpandedItems: ['1'],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1.1').focus();
});
+ fireEvent.keyDown(response.getItemRoot('1.1'), { key: 'ArrowLeft' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ expect(response.isItemExpanded('1')).to.equal(true);
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: '4' });
- expect(getFocusedItemId()).to.equal('4');
+ it('should do nothing if the focus is on a root item that is closed', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ });
- setItems([{ id: '1' }, { id: '2' }, { id: '3' }]);
- expect(getFocusedItemId()).to.equal('1');
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowLeft' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ expect(response.isItemExpanded('1')).to.equal(false);
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: '2' });
- expect(getFocusedItemId()).to.equal('2');
+ it('should do nothing if the focus is on a root item that is a leaf', () => {
+ const response = render({
+ items: [{ id: '1' }],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'ArrowLeft' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
+ });
- setItems([{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }]);
- expect(getFocusedItemId()).to.equal('2');
+ describe('key: Home', () => {
+ it('should move the focus to the first item in the tree', () => {
+ const response = render({
+ items: [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }],
+ });
- fireEvent.keyDown(getItemRoot('2'), { key: '4' });
- expect(getFocusedItemId()).to.equal('4');
+ act(() => {
+ response.getItemRoot('4').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('4'), { key: 'Home' });
+ expect(response.getFocusedItemId()).to.equal('1');
});
+ });
- it('should not move focus when pressing a modifier key and a letter', () => {
- const { getFocusedItemId, getItemRoot } = render({
+ describe('key: End', () => {
+ it('should move the focus to the last item in the tree when the last item is not expanded', () => {
+ const response = render({
items: [
- { id: '1', label: 'one' },
- { id: '2', label: 'two' },
- { id: '3', label: 'three' },
- { id: '4', label: 'four' },
+ { id: '1' },
+ { id: '2' },
+ { id: '3' },
+ { id: '4', children: [{ id: '4.1' }, { id: '4.2' }] },
],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
-
- fireEvent.keyDown(getItemRoot('1'), { key: 't', ctrlKey: true });
- expect(getFocusedItemId()).to.equal('1');
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'End' });
+ expect(response.getFocusedItemId()).to.equal('4');
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: 't', metaKey: true });
- expect(getFocusedItemId()).to.equal('1');
+ it('should move the focus to the last item in the tree when the last item is expanded', () => {
+ const response = render({
+ items: [
+ { id: '1' },
+ { id: '2' },
+ { id: '3' },
+ { id: '4', children: [{ id: '4.1', children: [{ id: '4.1.1' }] }] },
+ ],
+ defaultExpandedItems: ['4', '4.1'],
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: 't', shiftKey: true });
- expect(getFocusedItemId()).to.equal('1');
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'End' });
+ expect(response.getFocusedItemId()).to.equal('4.1.1');
});
+ });
- it('should work on disabled item when disabledItemsFocusable={true}', () => {
- const { getFocusedItemId, getItemRoot } = render({
+ describe('key: * (asterisk)', () => {
+ it('should expand all items that are at the same depth as the current item (depth = 0)', () => {
+ const response = render({
items: [
- { id: '1', label: 'one', disabled: true },
- { id: '2', label: 'two', disabled: true },
- { id: '3', label: 'three', disabled: true },
- { id: '4', label: 'four', disabled: true },
+ { id: '1', children: [{ id: '1.1' }] },
+ { id: '2', children: [{ id: '2.1' }] },
+ { id: '3', children: [{ id: '3.1', children: [{ id: '3.1.1' }] }] },
+ { id: '4' },
],
- disabledItemsFocusable: true,
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
- fireEvent.keyDown(getItemRoot('1'), { key: 't' });
- expect(getFocusedItemId()).to.equal('2');
+ expect(response.isItemExpanded('1')).to.equal(false);
+ expect(response.isItemExpanded('2')).to.equal(false);
+ expect(response.isItemExpanded('3')).to.equal(false);
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: '*' });
+ expect(response.isItemExpanded('1')).to.equal(true);
+ expect(response.isItemExpanded('2')).to.equal(true);
+ expect(response.isItemExpanded('3')).to.equal(true);
+ expect(response.isItemExpanded('3.1')).to.equal(false);
});
- it('should not move focus on disabled item when disabledItemsFocusable={false}', () => {
- const { getFocusedItemId, getItemRoot } = render({
+ it('should expand all items that are at the same depth as the current item (depth = 1)', () => {
+ const response = render({
items: [
- { id: '1', label: 'one', disabled: true },
- { id: '2', label: 'two', disabled: true },
- { id: '3', label: 'three', disabled: true },
- { id: '4', label: 'four', disabled: true },
+ { id: '1', children: [{ id: '1.1' }] },
+ { id: '2', children: [{ id: '2.1' }] },
+ {
+ id: '3',
+ children: [
+ {
+ id: '3.1',
+ children: [{ id: '3.1.1' }, { id: '3.1.2', children: [{ id: '3.1.2.1' }] }],
+ },
+ ],
+ },
+ { id: '4' },
],
- disabledItemsFocusable: false,
+ defaultExpandedItems: ['3'],
+ });
+
+ act(() => {
+ response.getItemRoot('3.1').focus();
+ });
+
+ expect(response.isItemExpanded('1')).to.equal(false);
+ expect(response.isItemExpanded('2')).to.equal(false);
+ expect(response.isItemExpanded('3')).to.equal(true);
+ expect(response.isItemExpanded('3.1')).to.equal(false);
+
+ fireEvent.keyDown(response.getItemRoot('3.1'), { key: '*' });
+ expect(response.isItemExpanded('1')).to.equal(false);
+ expect(response.isItemExpanded('2')).to.equal(false);
+ expect(response.isItemExpanded('3')).to.equal(true);
+ expect(response.isItemExpanded('3.1')).to.equal(true);
+ expect(response.isItemExpanded('3.1.2')).to.equal(false);
+ });
+ });
+
+ describe('key: Enter', () => {
+ it('should expand an item with children if it is collapsed', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
});
act(() => {
- getItemRoot('1').focus();
+ response.getItemRoot('1').focus();
});
- expect(getFocusedItemId()).to.equal('1');
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'Enter' });
+ expect(response.isItemExpanded('1')).to.equal(true);
+ });
- fireEvent.keyDown(getItemRoot('1'), { key: 't' });
- expect(getFocusedItemId()).to.equal('1');
+ it('should collapse an item with children if it is expanded', () => {
+ const response = render({
+ items: [{ id: '1', children: [{ id: '1.1' }] }],
+ defaultExpandedItems: ['1'],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 'Enter' });
+ expect(response.isItemExpanded('1')).to.equal(false);
+ });
+ });
+ });
+
+ describe('Type-ahead', () => {
+ it('should move the focus to the next item with a name that starts with the typed character', () => {
+ const response = render({
+ items: [
+ { id: '1', label: 'one' },
+ { id: '2', label: 'two' },
+ { id: '3', label: 'three' },
+ { id: '4', label: 'four' },
+ ],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
});
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't' });
+ expect(response.getFocusedItemId()).to.equal('2');
+
+ fireEvent.keyDown(response.getItemRoot('2'), { key: 'f' });
+ expect(response.getFocusedItemId()).to.equal('4');
+
+ fireEvent.keyDown(response.getItemRoot('4'), { key: 'o' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
+
+ it('should move to the next item in the displayed order when typing the same starting character', () => {
+ const response = render({
+ items: [{ id: 'A1' }, { id: 'B1' }, { id: 'A2' }, { id: 'B3' }, { id: 'B2' }],
+ });
+
+ act(() => {
+ response.getItemRoot('A1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('A1');
+
+ fireEvent.keyDown(response.getItemRoot('A1'), { key: 'b' });
+ expect(response.getFocusedItemId()).to.equal('B1');
+
+ fireEvent.keyDown(response.getItemRoot('B1'), { key: 'b' });
+ expect(response.getFocusedItemId()).to.equal('B3');
+
+ fireEvent.keyDown(response.getItemRoot('B3'), { key: 'b' });
+ expect(response.getFocusedItemId()).to.equal('B2');
+
+ fireEvent.keyDown(response.getItemRoot('B2'), { key: 'b' });
+ expect(response.getFocusedItemId()).to.equal('B1');
+ });
+
+ it('should work with capitalized label', () => {
+ const response = render({
+ items: [
+ { id: '1', label: 'One' },
+ { id: '2', label: 'Two' },
+ { id: '3', label: 'Three' },
+ { id: '4', label: 'Four' },
+ ],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't' });
+ expect(response.getFocusedItemId()).to.equal('2');
+
+ fireEvent.keyDown(response.getItemRoot('2'), { key: 'f' });
+ expect(response.getFocusedItemId()).to.equal('4');
+
+ fireEvent.keyDown(response.getItemRoot('4'), { key: 'o' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
+
+ it('should work with ReactElement label', function test() {
+ // Only the SimpleTreeView can have React Element labels.
+ if (treeViewComponent !== 'SimpleTreeView') {
+ this.skip();
+ }
+
+ const response = render({
+ items: [
+ { id: '1', label: one },
+ { id: '2', label: two },
+ { id: '3', label: three },
+ { id: '4', label: four },
+ ],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't' });
+ expect(response.getFocusedItemId()).to.equal('2');
+
+ fireEvent.keyDown(response.getItemRoot('2'), { key: 'f' });
+ expect(response.getFocusedItemId()).to.equal('4');
+
+ fireEvent.keyDown(response.getItemRoot('4'), { key: 'o' });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
+
+ it('should work after adding / removing items', () => {
+ const response = render({
+ items: [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: '4' });
+ expect(response.getFocusedItemId()).to.equal('4');
+
+ response.setItems([{ id: '1' }, { id: '2' }, { id: '3' }]);
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: '2' });
+ expect(response.getFocusedItemId()).to.equal('2');
+
+ response.setItems([{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }]);
+ expect(response.getFocusedItemId()).to.equal('2');
+
+ fireEvent.keyDown(response.getItemRoot('2'), { key: '4' });
+ expect(response.getFocusedItemId()).to.equal('4');
+ });
+
+ it('should not move focus when pressing a modifier key and a letter', () => {
+ const response = render({
+ items: [
+ { id: '1', label: 'one' },
+ { id: '2', label: 'two' },
+ { id: '3', label: 'three' },
+ { id: '4', label: 'four' },
+ ],
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't', ctrlKey: true });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't', metaKey: true });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't', shiftKey: true });
+ expect(response.getFocusedItemId()).to.equal('1');
+ });
+
+ it('should work on disabled item when disabledItemsFocusable={true}', () => {
+ const response = render({
+ items: [
+ { id: '1', label: 'one', disabled: true },
+ { id: '2', label: 'two', disabled: true },
+ { id: '3', label: 'three', disabled: true },
+ { id: '4', label: 'four', disabled: true },
+ ],
+ disabledItemsFocusable: true,
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't' });
+ expect(response.getFocusedItemId()).to.equal('2');
+ });
+
+ it('should not move focus on disabled item when disabledItemsFocusable={false}', () => {
+ const response = render({
+ items: [
+ { id: '1', label: 'one', disabled: true },
+ { id: '2', label: 'two', disabled: true },
+ { id: '3', label: 'three', disabled: true },
+ { id: '4', label: 'four', disabled: true },
+ ],
+ disabledItemsFocusable: false,
+ });
+
+ act(() => {
+ response.getItemRoot('1').focus();
+ });
+ expect(response.getFocusedItemId()).to.equal('1');
+
+ fireEvent.keyDown(response.getItemRoot('1'), { key: 't' });
+ expect(response.getFocusedItemId()).to.equal('1');
});
- },
-);
+ });
+});