@@ -3,8 +3,10 @@ import * as React from 'react';
3
3
4
4
import { axe } from 'jest-axe' ;
5
5
6
+ import * as mediaHooks from '@/hooks/useMediaDevice/useMediaDevice' ;
6
7
import { renderProvider } from '@/tests/renderProvider/renderProvider.utility' ;
7
8
import { windowMatchMedia } from '@/tests/windowMatchMedia' ;
9
+ import { DeviceBreakpointsType } from '@/types' ;
8
10
9
11
import { OliveMenu } from '../oliveMenu' ;
10
12
import { IOliveMenu , OliveMenuListOptions } from '../types' ;
@@ -74,8 +76,15 @@ const mockProps: IOliveMenu = {
74
76
window . matchMedia = windowMatchMedia ( ) ;
75
77
76
78
describe ( 'OliveMenu component' , ( ) => {
79
+ afterEach ( ( ) => {
80
+ window . matchMedia = windowMatchMedia ( ) ;
81
+ jest . clearAllMocks ( ) ;
82
+ jest . resetAllMocks ( ) ;
83
+ jest . restoreAllMocks ( ) ;
84
+ } ) ;
85
+
77
86
it ( 'Should render OliveMenu' , async ( ) => {
78
- const { container } = renderProvider ( < OliveMenu { ...mockProps } /> ) ;
87
+ const { container } = renderProvider ( < OliveMenu { ...mockProps } ref = { jest . fn ( ) } /> ) ;
79
88
80
89
const oliveMenu = screen . getByText (
81
90
( _content , element ) => element ?. tagName . toLowerCase ( ) === 'button'
@@ -94,10 +103,55 @@ describe('OliveMenu component', () => {
94
103
const openButton = screen . getAllByText ( 'Options' ) ;
95
104
fireEvent . click ( openButton [ 0 ] ) ;
96
105
97
- const menu = screen . getByText (
98
- ( content , element ) => element ?. tagName . toLowerCase ( ) === 'dialog'
99
- ) ;
100
- expect ( menu ) . toBeInTheDocument ( ) ;
106
+ // Element in the popover
107
+ const popoverElement = screen . getByText ( 'list 1' ) ;
108
+ expect ( popoverElement ) . toBeInTheDocument ( ) ;
109
+
110
+ const results = await axe ( container ) ;
111
+ expect ( container ) . toHTMLValidate ( {
112
+ rules : {
113
+ 'no-inline-style' : 'off' ,
114
+ } ,
115
+ } ) ;
116
+ expect ( results ) . toHaveNoViolations ( ) ;
117
+ } ) ;
118
+
119
+ it ( 'When desktop popover will be a div' , async ( ) => {
120
+ window . matchMedia = windowMatchMedia ( 'onlyDesktop' ) ;
121
+ jest
122
+ . spyOn ( mediaHooks , 'useMediaDevice' )
123
+ . mockImplementation ( ( ) => DeviceBreakpointsType . DESKTOP ) ;
124
+
125
+ const { container } = renderProvider ( < OliveMenu { ...mockProps } /> ) ;
126
+
127
+ const openButton = screen . getAllByText ( 'Options' ) ;
128
+ fireEvent . click ( openButton [ 0 ] ) ;
129
+
130
+ // Element in the popover
131
+ const popover = container . querySelector ( '[data-popover]' ) ;
132
+ expect ( popover ?. tagName ) . toBe ( 'DIV' ) ;
133
+
134
+ const results = await axe ( container ) ;
135
+ expect ( container ) . toHTMLValidate ( {
136
+ rules : {
137
+ 'no-inline-style' : 'off' ,
138
+ } ,
139
+ } ) ;
140
+ expect ( results ) . toHaveNoViolations ( ) ;
141
+ } ) ;
142
+
143
+ it ( 'When mobile or tablet, popover will be a dialog' , async ( ) => {
144
+ window . matchMedia = windowMatchMedia ( 'onlyMobile' ) ;
145
+ jest . spyOn ( mediaHooks , 'useMediaDevice' ) . mockImplementation ( ( ) => DeviceBreakpointsType . MOBILE ) ;
146
+
147
+ const { container } = renderProvider ( < OliveMenu { ...mockProps } /> ) ;
148
+
149
+ const openButton = screen . getAllByText ( 'Options' ) ;
150
+ fireEvent . click ( openButton [ 0 ] ) ;
151
+
152
+ // Element in the popover
153
+ const popover = container . querySelector ( '[data-popover]' ) ;
154
+ expect ( popover ?. tagName ) . toBe ( 'DIALOG' ) ;
101
155
102
156
const results = await axe ( container ) ;
103
157
expect ( container ) . toHTMLValidate ( {
@@ -127,38 +181,102 @@ describe('OliveMenu component', () => {
127
181
const openButton = screen . getAllByText ( 'Options' ) ;
128
182
fireEvent . click ( openButton [ 0 ] ) ;
129
183
130
- const menu = screen . getByText (
131
- ( _content , element ) => element ?. tagName . toLowerCase ( ) === 'dialog'
132
- ) ;
184
+ // Element in the popover
185
+ const popoverElement = screen . getByText ( 'list 1' ) ;
133
186
134
187
const closeButton = screen . getByLabelText (
135
188
mockProps . actionBottomSheetStructure ?. closeIcon ?. altText as string
136
189
) ;
137
190
fireEvent . click ( closeButton ) ;
138
191
139
- expect ( menu ) . not . toBeInTheDocument ( ) ;
192
+ expect ( popoverElement ) . not . toBeInTheDocument ( ) ;
140
193
} ) ;
141
194
142
- it ( 'Should close the menu when the popover is closed automatically' , async ( ) => {
195
+ it ( 'Should close the menu when lose the focus outside' , async ( ) => {
196
+ const handleOpenClose = jest . fn ( ) ;
143
197
renderProvider (
144
- < div >
145
- < button > external</ button >
146
- < OliveMenu { ...mockProps } />
147
- </ div >
198
+ < OliveMenu { ...mockProps } dataTestId = "OliveMenu" onOpenClose = { handleOpenClose } />
148
199
) ;
149
200
201
+ const container = screen . getByTestId ( 'OliveMenuContainer' ) ;
202
+
203
+ // Lossing the focus when the popover is closed
204
+ act ( ( ) => {
205
+ fireEvent . blur ( container ) ;
206
+ } ) ;
207
+ expect ( handleOpenClose ) . not . toHaveBeenCalled ( ) ;
208
+
209
+ // Open the popover
150
210
const openButton = screen . getAllByText ( 'Options' ) ;
151
- fireEvent . click ( openButton [ 0 ] ) ;
211
+ act ( ( ) => {
212
+ fireEvent . click ( openButton [ 0 ] ) ;
213
+ } ) ;
152
214
153
- const menu = screen . getByText (
154
- ( _content , element ) => element ?. tagName . toLowerCase ( ) === 'dialog'
155
- ) ;
215
+ // Element in the popover
216
+ const popoverElement = screen . getByText ( 'list 1' ) ;
217
+ expect ( popoverElement ) . toBeInTheDocument ( ) ;
218
+
219
+ // Move focus to an element inside the popover
220
+ // Do not close the popover
221
+ const option = screen . getAllByText ( 'option 1' ) [ 0 ] ;
222
+ act ( ( ) => {
223
+ fireEvent . blur ( container , { relatedTarget : option } ) ;
224
+ } ) ;
225
+ expect ( popoverElement ) . toBeInTheDocument ( ) ;
226
+
227
+ // Close the popover lossing the focus
228
+ act ( ( ) => {
229
+ fireEvent . blur ( container ) ;
230
+ } ) ;
156
231
157
- const external = screen . getByText ( 'external' ) ;
232
+ expect ( handleOpenClose ) . toHaveBeenCalledWith ( false , expect . anything ( ) ) ;
233
+
234
+ expect ( popoverElement ) . not . toBeInTheDocument ( ) ;
235
+ } ) ;
236
+
237
+ it ( 'Should close the menu when pressing Escape' , async ( ) => {
238
+ const handleOpenClose = jest . fn ( ) ;
239
+ renderProvider ( < OliveMenu { ...mockProps } onOpenClose = { handleOpenClose } /> ) ;
240
+
241
+ // Open the popover
242
+ const openButton = screen . getAllByText ( 'Options' ) ;
243
+
244
+ // Simulate a inner element has the focus
245
+ openButton [ 0 ] . focus ( ) ;
246
+
247
+ // Press escape when is already close
158
248
await act ( async ( ) => {
159
- fireEvent . mouseUp ( external ) ;
249
+ fireEvent . keyDown ( window , {
250
+ key : 'Escape' ,
251
+ code : 'Escape' ,
252
+ keyCode : 27 ,
253
+ charCode : 27 ,
254
+ } ) ;
160
255
} ) ;
256
+ expect ( handleOpenClose ) . not . toHaveBeenCalled ( ) ;
257
+
258
+ act ( ( ) => {
259
+ fireEvent . click ( openButton [ 0 ] ) ;
260
+ } ) ;
261
+
262
+ // Element in the popover
263
+ const popoverElement = screen . getByText ( 'list 1' ) ;
264
+
265
+ // Simulate a inner element has the focus
266
+ openButton [ 0 ] . focus ( ) ;
267
+
268
+ // Press escape
269
+ await act ( async ( ) => {
270
+ fireEvent . keyDown ( window , {
271
+ key : 'Escape' ,
272
+ code : 'Escape' ,
273
+ keyCode : 27 ,
274
+ charCode : 27 ,
275
+ } ) ;
276
+ } ) ;
277
+
278
+ expect ( handleOpenClose ) . toHaveBeenCalledWith ( false ) ;
161
279
162
- expect ( menu ) . not . toBeInTheDocument ( ) ;
280
+ expect ( popoverElement ) . not . toBeInTheDocument ( ) ;
163
281
} ) ;
164
282
} ) ;
0 commit comments