11/* eslint-disable no-undef */
2- import { fireEvent , render } from '@testing-library/react' ;
2+ import { act , fireEvent , render } from '@testing-library/react' ;
3+ import { spyElementPrototypes } from 'rc-util/lib/test/domHook' ;
34import React from 'react' ;
4- import Menu , { MenuItem , SubMenu } from '../src' ;
5+ import Menu , { MenuItem , MenuItemGroup , MenuRef , SubMenu } from '../src' ;
56
67describe ( 'Focus' , ( ) => {
8+ beforeAll ( ( ) => {
9+ // Mock to force make menu item visible
10+ spyElementPrototypes ( HTMLElement , {
11+ offsetParent : {
12+ get ( ) {
13+ return this . parentElement ;
14+ } ,
15+ } ,
16+ } ) ;
17+ } ) ;
718
819 beforeEach ( ( ) => {
920 global . triggerProps = null ;
@@ -15,13 +26,15 @@ describe('Focus', () => {
1526 jest . useRealTimers ( ) ;
1627 } ) ;
1728
18- it ( 'Get focus' , ( ) => {
19- const { container } = render (
20- < Menu mode = "inline" openKeys = { [ 's' ] } >
21- < SubMenu key = "s" title = "submenu" >
22- < MenuItem key = "1" > 1</ MenuItem >
23- </ SubMenu >
24- </ Menu > ,
29+ it ( 'Get focus' , async ( ) => {
30+ const { container } = await act ( async ( ) =>
31+ render (
32+ < Menu mode = "inline" openKeys = { [ 's' ] } >
33+ < SubMenu key = "s" title = "submenu" >
34+ < MenuItem key = "1" > 1</ MenuItem >
35+ </ SubMenu >
36+ </ Menu > ,
37+ ) ,
2538 ) ;
2639
2740 // Item focus
@@ -34,5 +47,149 @@ describe('Focus', () => {
3447 fireEvent . focus ( container . querySelector ( '.rc-menu-submenu-title' ) ) ;
3548 expect ( container . querySelector ( '.rc-menu-submenu-active' ) ) . toBeTruthy ( ) ;
3649 } ) ;
50+
51+ it ( 'should support focus through ref' , async ( ) => {
52+ const menuRef = React . createRef < MenuRef > ( ) ;
53+ const { getByTestId } = await act ( async ( ) =>
54+ render (
55+ < Menu ref = { menuRef } >
56+ < SubMenu key = "bamboo" title = "Disabled" disabled >
57+ < MenuItem key = "bamboo-child" > Disabled child</ MenuItem >
58+ </ SubMenu >
59+ < MenuItem key = "light" data-testid = "first-focusable" >
60+ Light
61+ </ MenuItem >
62+ </ Menu > ,
63+ ) ,
64+ ) ;
65+
66+ act ( ( ) => menuRef . current . focus ( ) ) ;
67+
68+ const firstFocusableItem = getByTestId ( 'first-focusable' ) ;
69+ expect ( document . activeElement ) . toBe ( firstFocusableItem ) ;
70+ expect ( firstFocusableItem ) . toHaveClass ( 'rc-menu-item-active' ) ;
71+ } ) ;
72+
73+ it ( 'should focus active item through ref' , async ( ) => {
74+ const menuRef = React . createRef < MenuRef > ( ) ;
75+ const { getByTestId } = await act ( async ( ) =>
76+ render (
77+ < Menu ref = { menuRef } activeKey = "cat" >
78+ < MenuItem key = "light" > Light</ MenuItem >
79+ < MenuItem key = "cat" data-testid = "active-key" >
80+ Cat
81+ </ MenuItem >
82+ </ Menu > ,
83+ ) ,
84+ ) ;
85+ act ( ( ) => menuRef . current . focus ( ) ) ;
86+
87+ const activeKey = getByTestId ( 'active-key' ) ;
88+ expect ( document . activeElement ) . toBe ( activeKey ) ;
89+ expect ( activeKey ) . toHaveClass ( 'rc-menu-item-active' ) ;
90+ } ) ;
91+
92+ it ( 'focus moves to the next accessible menu item if the first child is empty group' , async ( ) => {
93+ const menuRef = React . createRef < MenuRef > ( ) ;
94+ const { getByTestId } = await act ( async ( ) =>
95+ render (
96+ < Menu ref = { menuRef } >
97+ < MenuItemGroup title = "group" key = "group" />
98+ < SubMenu key = "bamboo" title = "Disabled" disabled >
99+ < MenuItem key = "bamboo-child" > Disabled child</ MenuItem >
100+ </ SubMenu >
101+ < MenuItem key = "light" data-testid = "first-focusable" >
102+ Light
103+ </ MenuItem >
104+ </ Menu > ,
105+ ) ,
106+ ) ;
107+
108+ act ( ( ) => menuRef . current . focus ( ) ) ;
109+
110+ const firstFocusableItem = getByTestId ( 'first-focusable' ) ;
111+ expect ( document . activeElement ) . toBe ( firstFocusableItem ) ;
112+ expect ( firstFocusableItem ) . toHaveClass ( 'rc-menu-item-active' ) ;
113+ } ) ;
114+
115+ it ( 'focus moves to the next accessible group item if the first child is non-empty group' , async ( ) => {
116+ const menuRef = React . createRef < MenuRef > ( ) ;
117+ const { getByTestId } = await act ( async ( ) =>
118+ render (
119+ < Menu ref = { menuRef } >
120+ < MenuItemGroup title = "group" key = "group" >
121+ < MenuItem key = "group-child-1" disabled >
122+ group-child-1
123+ </ MenuItem >
124+ < MenuItem key = "group-child-2" data-testid = "first-focusable" >
125+ group-child-2
126+ </ MenuItem >
127+ </ MenuItemGroup >
128+ < MenuItem key = "light" > Light</ MenuItem >
129+ </ Menu > ,
130+ ) ,
131+ ) ;
132+
133+ act ( ( ) => menuRef . current . focus ( ) ) ;
134+
135+ const firstFocusableItem = getByTestId ( 'first-focusable' ) ;
136+ expect ( document . activeElement ) . toBe ( firstFocusableItem ) ;
137+ expect ( firstFocusableItem ) . toHaveClass ( 'rc-menu-item-active' ) ;
138+ } ) ;
139+
140+ it ( 'focus moves to nested group item correctly' , async ( ) => {
141+ const menuRef = React . createRef < MenuRef > ( ) ;
142+ const { getByTestId } = await act ( async ( ) =>
143+ render (
144+ < Menu ref = { menuRef } >
145+ < MenuItemGroup title = "group" key = "group" >
146+ < MenuItem key = "group-child-1" disabled >
147+ group-child-1
148+ </ MenuItem >
149+ < MenuItemGroup title = "nested group" key = "nested-group" >
150+ < MenuItem key = "nested-group-child-1" disabled >
151+ nested-group-child-1
152+ </ MenuItem >
153+ < MenuItem
154+ key = "nested-group-child-2"
155+ data-testid = "first-focusable"
156+ >
157+ nested-group-child-2
158+ </ MenuItem >
159+ </ MenuItemGroup >
160+ < MenuItem key = "group-child-3" > group-child-3</ MenuItem >
161+ </ MenuItemGroup >
162+ </ Menu > ,
163+ ) ,
164+ ) ;
165+
166+ act ( ( ) => menuRef . current . focus ( ) ) ;
167+
168+ const firstFocusableItem = getByTestId ( 'first-focusable' ) ;
169+ expect ( document . activeElement ) . toBe ( firstFocusableItem ) ;
170+ expect ( firstFocusableItem ) . toHaveClass ( 'rc-menu-item-active' ) ;
171+ } ) ;
172+
173+ it ( 'focus moves to submenu correctly' , async ( ) => {
174+ const menuRef = React . createRef < MenuRef > ( ) ;
175+ const { getByTestId, getByTitle } = await act ( async ( ) =>
176+ render (
177+ < Menu ref = { menuRef } >
178+ < SubMenu key = "sub-menu-disabled" title = "Disabled" disabled >
179+ < MenuItem key = "sub-menu-disabled-child" > Disabled child</ MenuItem >
180+ </ SubMenu >
181+ < SubMenu key = "sub-menu" data-testid = "sub-menu" title = "Submenu" >
182+ < MenuItem key = "sub-menu-child-1" > Submenu child</ MenuItem >
183+ </ SubMenu >
184+ < MenuItem key = "light" > Light</ MenuItem >
185+ </ Menu > ,
186+ ) ,
187+ ) ;
188+
189+ act ( ( ) => menuRef . current . focus ( ) ) ;
190+
191+ expect ( document . activeElement ) . toBe ( getByTitle ( 'Submenu' ) ) ;
192+ expect ( getByTestId ( 'sub-menu' ) ) . toHaveClass ( 'rc-menu-submenu-active' ) ;
193+ } ) ;
37194} ) ;
38195/* eslint-enable */
0 commit comments