1+ import userEvent from '@testing-library/user-event' ;
2+
13import {
24 createPlayground ,
35 createSource ,
@@ -29,6 +31,202 @@ describe('getEnvironmentProps', () => {
2931 ) ;
3032 } ) ;
3133
34+ describe ( 'onMouseDown' , ( ) => {
35+ test ( 'is a noop when panel is not open and status is idle' , ( ) => {
36+ const onStateChange = jest . fn ( ) ;
37+ const {
38+ getEnvironmentProps,
39+ inputElement,
40+ formElement,
41+ } = createPlayground ( createAutocomplete , { onStateChange } ) ;
42+ const panelElement = document . createElement ( 'div' ) ;
43+
44+ const { onMouseDown } = getEnvironmentProps ( {
45+ inputElement,
46+ formElement,
47+ panelElement,
48+ } ) ;
49+ window . addEventListener ( 'mousedown' , onMouseDown ) ;
50+
51+ // Dispatch MouseDown event on window
52+ const customEvent = new CustomEvent ( 'mousedown' , { bubbles : true } ) ;
53+ window . dispatchEvent ( customEvent ) ;
54+
55+ expect ( onStateChange ) . not . toHaveBeenCalled ( ) ;
56+
57+ window . removeEventListener ( 'mousedown' , onMouseDown ) ;
58+ } ) ;
59+
60+ test ( 'is a noop when the event target is the input element' , async ( ) => {
61+ const onStateChange = jest . fn ( ) ;
62+ const {
63+ getEnvironmentProps,
64+ inputElement,
65+ formElement,
66+ } = createPlayground ( createAutocomplete , {
67+ onStateChange,
68+ openOnFocus : true ,
69+ getSources ( ) {
70+ return [
71+ createSource ( {
72+ getItems : ( ) => [ { label : '1' } ] ,
73+ } ) ,
74+ ] ;
75+ } ,
76+ } ) ;
77+ const panelElement = document . createElement ( 'div' ) ;
78+
79+ const { onMouseDown } = getEnvironmentProps ( {
80+ inputElement,
81+ formElement,
82+ panelElement,
83+ } ) ;
84+ window . addEventListener ( 'mousedown' , onMouseDown ) ;
85+
86+ // Click input (focuses it, which opens the panel)
87+ userEvent . click ( inputElement ) ;
88+
89+ await runAllMicroTasks ( ) ;
90+
91+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
92+ expect . objectContaining ( {
93+ state : expect . objectContaining ( {
94+ isOpen : true ,
95+ } ) ,
96+ } )
97+ ) ;
98+
99+ onStateChange . mockClear ( ) ;
100+
101+ // Dispatch MouseDown event on the input (bubbles to window)
102+ const customEvent = new CustomEvent ( 'mousedown' , { bubbles : true } ) ;
103+ inputElement . dispatchEvent ( customEvent ) ;
104+
105+ await runAllMicroTasks ( ) ;
106+
107+ expect ( onStateChange ) . not . toHaveBeenCalled ( ) ;
108+
109+ window . removeEventListener ( 'mousedown' , onMouseDown ) ;
110+ } ) ;
111+
112+ test ( 'closes panel and resets `activeItemId` if the target is outside Autocomplete' , async ( ) => {
113+ const onStateChange = jest . fn ( ) ;
114+ const {
115+ getEnvironmentProps,
116+ inputElement,
117+ formElement,
118+ } = createPlayground ( createAutocomplete , {
119+ onStateChange,
120+ openOnFocus : true ,
121+ defaultActiveItemId : 1 ,
122+ getSources ( ) {
123+ return [
124+ createSource ( {
125+ getItems : ( ) => [ { label : '1' } ] ,
126+ } ) ,
127+ ] ;
128+ } ,
129+ } ) ;
130+ const panelElement = document . createElement ( 'div' ) ;
131+
132+ const { onMouseDown } = getEnvironmentProps ( {
133+ inputElement,
134+ formElement,
135+ panelElement,
136+ } ) ;
137+ window . addEventListener ( 'mousedown' , onMouseDown ) ;
138+
139+ // Click input (focuses it, which opens the panel)
140+ userEvent . click ( inputElement ) ;
141+
142+ await runAllMicroTasks ( ) ;
143+
144+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
145+ expect . objectContaining ( {
146+ state : expect . objectContaining ( {
147+ isOpen : true ,
148+ } ) ,
149+ } )
150+ ) ;
151+
152+ onStateChange . mockClear ( ) ;
153+
154+ // Dispatch MouseDown event on window (so, outside of Autocomplete)
155+ const customEvent = new CustomEvent ( 'mousedown' , { bubbles : true } ) ;
156+ window . document . dispatchEvent ( customEvent ) ;
157+
158+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
159+ expect . objectContaining ( {
160+ state : expect . objectContaining ( {
161+ isOpen : false ,
162+ activeItemId : null ,
163+ } ) ,
164+ } )
165+ ) ;
166+
167+ window . removeEventListener ( 'mousedown' , onMouseDown ) ;
168+ } ) ;
169+
170+ test ( 'does not close panel nor reset `activeItemId` if the target is outside Autocomplete in debug mode' , async ( ) => {
171+ const onStateChange = jest . fn ( ) ;
172+ const {
173+ getEnvironmentProps,
174+ inputElement,
175+ formElement,
176+ } = createPlayground ( createAutocomplete , {
177+ onStateChange,
178+ openOnFocus : true ,
179+ defaultActiveItemId : 1 ,
180+ debug : true ,
181+ getSources ( ) {
182+ return [
183+ createSource ( {
184+ getItems : ( ) => [ { label : '1' } ] ,
185+ } ) ,
186+ ] ;
187+ } ,
188+ } ) ;
189+ const panelElement = document . createElement ( 'div' ) ;
190+
191+ const { onMouseDown } = getEnvironmentProps ( {
192+ inputElement,
193+ formElement,
194+ panelElement,
195+ } ) ;
196+ window . addEventListener ( 'mousedown' , onMouseDown ) ;
197+
198+ // Click input (focuses it, which opens the panel)
199+ userEvent . click ( inputElement ) ;
200+
201+ await runAllMicroTasks ( ) ;
202+
203+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
204+ expect . objectContaining ( {
205+ state : expect . objectContaining ( {
206+ isOpen : true ,
207+ } ) ,
208+ } )
209+ ) ;
210+
211+ onStateChange . mockClear ( ) ;
212+
213+ // Dispatch MouseDown event on window (so, outside of Autocomplete)
214+ const customEvent = new CustomEvent ( 'mousedown' , { bubbles : true } ) ;
215+ window . document . dispatchEvent ( customEvent ) ;
216+
217+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
218+ expect . objectContaining ( {
219+ state : expect . objectContaining ( {
220+ isOpen : true ,
221+ activeItemId : 1 ,
222+ } ) ,
223+ } )
224+ ) ;
225+
226+ window . removeEventListener ( 'mousedown' , onMouseDown ) ;
227+ } ) ;
228+ } ) ;
229+
32230 describe ( 'onTouchStart' , ( ) => {
33231 test ( 'is a noop when panel is not open and status is idle' , ( ) => {
34232 const onStateChange = jest . fn ( ) ;
@@ -107,7 +305,7 @@ describe('getEnvironmentProps', () => {
107305 window . removeEventListener ( 'touchstart' , onTouchStart ) ;
108306 } ) ;
109307
110- test ( 'closes panel if the target is outside Autocomplete' , async ( ) => {
308+ test ( 'closes panel and resets `activeItemId` if the target is outside Autocomplete' , async ( ) => {
111309 const onStateChange = jest . fn ( ) ;
112310 const {
113311 getEnvironmentProps,
@@ -116,6 +314,7 @@ describe('getEnvironmentProps', () => {
116314 } = createPlayground ( createAutocomplete , {
117315 onStateChange,
118316 openOnFocus : true ,
317+ defaultActiveItemId : 1 ,
119318 getSources ( ) {
120319 return [
121320 createSource ( {
@@ -156,6 +355,66 @@ describe('getEnvironmentProps', () => {
156355 expect . objectContaining ( {
157356 state : expect . objectContaining ( {
158357 isOpen : false ,
358+ activeItemId : null ,
359+ } ) ,
360+ } )
361+ ) ;
362+
363+ window . removeEventListener ( 'touchstart' , onTouchStart ) ;
364+ } ) ;
365+
366+ test ( 'does not close panel nor reset `activeItemId` if the target is outside Autocomplete in debug mode' , async ( ) => {
367+ const onStateChange = jest . fn ( ) ;
368+ const {
369+ getEnvironmentProps,
370+ inputElement,
371+ formElement,
372+ } = createPlayground ( createAutocomplete , {
373+ onStateChange,
374+ openOnFocus : true ,
375+ defaultActiveItemId : 1 ,
376+ debug : true ,
377+ getSources ( ) {
378+ return [
379+ createSource ( {
380+ getItems : ( ) => [ { label : '1' } ] ,
381+ } ) ,
382+ ] ;
383+ } ,
384+ } ) ;
385+ const panelElement = document . createElement ( 'div' ) ;
386+
387+ const { onTouchStart } = getEnvironmentProps ( {
388+ inputElement,
389+ formElement,
390+ panelElement,
391+ } ) ;
392+ window . addEventListener ( 'touchstart' , onTouchStart ) ;
393+
394+ // Focus input (opens the panel)
395+ inputElement . focus ( ) ;
396+
397+ await runAllMicroTasks ( ) ;
398+
399+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
400+ expect . objectContaining ( {
401+ state : expect . objectContaining ( {
402+ isOpen : true ,
403+ } ) ,
404+ } )
405+ ) ;
406+
407+ onStateChange . mockClear ( ) ;
408+
409+ // Dispatch TouchStart event on window (so, outside of Autocomplete)
410+ const customEvent = new CustomEvent ( 'touchstart' , { bubbles : true } ) ;
411+ window . document . dispatchEvent ( customEvent ) ;
412+
413+ expect ( onStateChange ) . toHaveBeenLastCalledWith (
414+ expect . objectContaining ( {
415+ state : expect . objectContaining ( {
416+ isOpen : true ,
417+ activeItemId : 1 ,
159418 } ) ,
160419 } )
161420 ) ;
0 commit comments