@@ -11,16 +11,8 @@ import {
11
11
hide ,
12
12
limitShift ,
13
13
} from '../src' ;
14
- import { renderHook } from '@testing-library/react-hooks' ;
15
- import { render , waitFor , fireEvent } from '@testing-library/react' ;
16
- import { useRef , useState } from 'react' ;
17
-
18
- test ( '`x` and `y` are initially `null`' , async ( ) => {
19
- const { result} = renderHook ( ( ) => useFloating ( ) ) ;
20
-
21
- expect ( result . current . x ) . toBe ( null ) ;
22
- expect ( result . current . y ) . toBe ( null ) ;
23
- } ) ;
14
+ import { render , fireEvent , screen , cleanup , act } from '@testing-library/react' ;
15
+ import { useRef , useState , useEffect } from 'react' ;
24
16
25
17
test ( 'middleware is always fresh and does not cause an infinite loop' , async ( ) => {
26
18
function InlineMiddleware ( ) {
@@ -129,16 +121,142 @@ test('middleware is always fresh and does not cause an infinite loop', async ()
129
121
) ;
130
122
}
131
123
132
- await waitFor ( ( ) => render ( < InlineMiddleware /> ) ) ;
124
+ render ( < InlineMiddleware /> ) ;
125
+
126
+ const { getByTestId} = render ( < StateMiddleware /> ) ;
127
+ fireEvent . click ( getByTestId ( 'step1' ) ) ;
128
+
129
+ await act ( async ( ) => { } ) ;
133
130
134
- const { getByTestId} = await waitFor ( ( ) => render ( < StateMiddleware /> ) ) ;
135
- await waitFor ( ( ) => fireEvent . click ( getByTestId ( 'step1' ) ) ) ;
136
- await waitFor ( ( ) => expect ( getByTestId ( 'x' ) . textContent ) . toBe ( '10' ) ) ;
131
+ expect ( getByTestId ( 'x' ) . textContent ) . toBe ( '10' ) ;
137
132
138
- await waitFor ( ( ) => fireEvent . click ( getByTestId ( 'step2' ) ) ) ;
139
- await waitFor ( ( ) => expect ( getByTestId ( 'x' ) . textContent ) . toBe ( '5' ) ) ;
133
+ fireEvent . click ( getByTestId ( 'step2' ) ) ;
134
+
135
+ await act ( async ( ) => { } ) ;
136
+
137
+ expect ( getByTestId ( 'x' ) . textContent ) . toBe ( '5' ) ;
140
138
141
139
// No `expect` as this test will fail if a render loop occurs
142
- await waitFor ( ( ) => fireEvent . click ( getByTestId ( 'step3' ) ) ) ;
143
- await waitFor ( ( ) => fireEvent . click ( getByTestId ( 'step4' ) ) ) ;
140
+ fireEvent . click ( getByTestId ( 'step3' ) ) ;
141
+ fireEvent . click ( getByTestId ( 'step4' ) ) ;
142
+
143
+ await act ( async ( ) => { } ) ;
144
+ } ) ;
145
+
146
+ describe ( 'whileElementsMounted' , ( ) => {
147
+ test ( 'is called a single time when both elements mount' , ( ) => {
148
+ const spy = jest . fn ( ) ;
149
+
150
+ function App ( ) {
151
+ const { reference, floating} = useFloating ( { whileElementsMounted : spy } ) ;
152
+ return (
153
+ < >
154
+ < button ref = { reference } />
155
+ < div ref = { floating } />
156
+ </ >
157
+ ) ;
158
+ }
159
+
160
+ render ( < App /> ) ;
161
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
162
+ cleanup ( ) ;
163
+ } ) ;
164
+
165
+ test ( 'is called a single time after floating mounts conditionally' , ( ) => {
166
+ const spy = jest . fn ( ) ;
167
+
168
+ function App ( ) {
169
+ const [ open , setOpen ] = useState ( false ) ;
170
+ const { reference, floating} = useFloating ( { whileElementsMounted : spy } ) ;
171
+ return (
172
+ < >
173
+ < button ref = { reference } onClick = { ( ) => setOpen ( true ) } />
174
+ { open && < div ref = { floating } /> }
175
+ </ >
176
+ ) ;
177
+ }
178
+
179
+ render ( < App /> ) ;
180
+ expect ( spy ) . toHaveBeenCalledTimes ( 0 ) ;
181
+ fireEvent . click ( screen . getByRole ( 'button' ) ) ;
182
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
183
+
184
+ cleanup ( ) ;
185
+ } ) ;
186
+
187
+ test ( 'is called a single time after reference mounts conditionally' , ( ) => {
188
+ const spy = jest . fn ( ) ;
189
+
190
+ function App ( ) {
191
+ const [ open , setOpen ] = useState ( false ) ;
192
+ const { reference, floating} = useFloating ( { whileElementsMounted : spy } ) ;
193
+ return (
194
+ < >
195
+ { open && < button ref = { reference } /> }
196
+ < div role = "tooltip" ref = { floating } onClick = { ( ) => setOpen ( true ) } />
197
+ </ >
198
+ ) ;
199
+ }
200
+
201
+ render ( < App /> ) ;
202
+ expect ( spy ) . toHaveBeenCalledTimes ( 0 ) ;
203
+ fireEvent . click ( screen . getByRole ( 'tooltip' ) ) ;
204
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
205
+
206
+ cleanup ( ) ;
207
+ } ) ;
208
+
209
+ test ( 'is called a single time both elements mount conditionally' , ( ) => {
210
+ const spy = jest . fn ( ) ;
211
+
212
+ function App ( ) {
213
+ const [ open , setOpen ] = useState ( false ) ;
214
+ const { reference, floating} = useFloating ( { whileElementsMounted : spy } ) ;
215
+
216
+ useEffect ( ( ) => {
217
+ setOpen ( true ) ;
218
+ } , [ ] ) ;
219
+
220
+ return (
221
+ < >
222
+ { open && < button ref = { reference } /> }
223
+ { open && < div role = "tooltip" ref = { floating } /> }
224
+ </ >
225
+ ) ;
226
+ }
227
+
228
+ render ( < App /> ) ;
229
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
230
+
231
+ cleanup ( ) ;
232
+ } ) ;
233
+
234
+ test ( 'calls the cleanup function' , ( ) => {
235
+ const cleanupSpy = jest . fn ( ) ;
236
+ const spy = jest . fn ( ( ) => cleanupSpy ) ;
237
+
238
+ function App ( ) {
239
+ const [ open , setOpen ] = useState ( true ) ;
240
+ const { reference, floating} = useFloating ( { whileElementsMounted : spy } ) ;
241
+
242
+ useEffect ( ( ) => {
243
+ setOpen ( false ) ;
244
+ } , [ ] ) ;
245
+
246
+ return (
247
+ < >
248
+ { open && < button ref = { reference } /> }
249
+ { open && < div role = "tooltip" ref = { floating } /> }
250
+ </ >
251
+ ) ;
252
+ }
253
+
254
+ render ( < App /> ) ;
255
+ expect ( cleanupSpy ) . toHaveBeenCalledTimes ( 1 ) ;
256
+
257
+ // Does not get called again post-cleanup
258
+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
259
+
260
+ cleanup ( ) ;
261
+ } ) ;
144
262
} ) ;
0 commit comments