@@ -52,7 +52,7 @@ function waitFor(
52
52
} = { } ,
53
53
) {
54
54
function getElementError ( message ) {
55
- const prettifiedDOM = prettyFormat ( container )
55
+ const prettifiedDOM = prettyFormat . format ( container )
56
56
const error = new Error (
57
57
[ message , prettifiedDOM ] . filter ( Boolean ) . join ( '\n\n' ) ,
58
58
)
@@ -126,6 +126,22 @@ function waitFor(
126
126
return result
127
127
}
128
128
129
+ const { MutationObserver} = getWindowFromNode ( container )
130
+ const observer = new MutationObserver ( ( ) => {
131
+ const result = checkCallbackWithExpensiveErrorDiagnosticsDisabled ( )
132
+ if ( typeof result ?. then === 'function' ) {
133
+ result . then ( resolvedValue => {
134
+ onDone ( null , resolvedValue )
135
+ } )
136
+ } else {
137
+ onDone ( null , result )
138
+ }
139
+ } )
140
+ observer . observe ( container , mutationObserverOptions )
141
+ controller . signal . addEventListener ( 'abort' , ( ) => {
142
+ observer . disconnect ( )
143
+ } )
144
+
129
145
waitForWeb ( checkCallbackWithExpensiveErrorDiagnosticsDisabled , {
130
146
clock,
131
147
interval,
@@ -147,18 +163,77 @@ function waitFor(
147
163
}
148
164
} ,
149
165
)
150
-
151
- const { MutationObserver} = getWindowFromNode ( container )
152
- const observer = new MutationObserver (
153
- checkCallbackWithExpensiveErrorDiagnosticsDisabled ,
154
- )
155
- observer . observe ( container , mutationObserverOptions )
156
- controller . signal . addEventListener ( 'abort' , ( ) => {
157
- observer . disconnect ( )
158
- } )
159
166
} )
160
167
}
161
168
162
- test ( 'runs' , async ( ) => {
163
- await expect ( waitFor ( ( ) => { } ) ) . resolves . toBeUndefined ( )
169
+ describe . each ( [
170
+ [ 'real timers' , ( ) => jest . useRealTimers ( ) ] ,
171
+ [ 'fake legacy timers' , ( ) => jest . useFakeTimers ( 'legacy' ) ] ,
172
+ [ 'fake modern timers' , ( ) => jest . useFakeTimers ( 'modern' ) ] ,
173
+ ] ) ( 'waitFor DOM reference implementation using %s' , ( label , useTimers ) => {
174
+ beforeEach ( ( ) => {
175
+ useTimers ( )
176
+ } )
177
+
178
+ afterEach ( ( ) => {
179
+ jest . useRealTimers ( )
180
+ } )
181
+
182
+ test ( 'void callback' , async ( ) => {
183
+ await expect ( waitFor ( ( ) => { } ) ) . resolves . toBeUndefined ( )
184
+ } )
185
+
186
+ test ( 'callback passes after timeout' , async ( ) => {
187
+ let state = 'pending'
188
+ setTimeout ( ( ) => {
189
+ state = 'done'
190
+ } , 10 )
191
+
192
+ await expect (
193
+ waitFor (
194
+ ( ) => {
195
+ if ( state !== 'done' ) {
196
+ throw new Error ( 'Not done' )
197
+ }
198
+ } ,
199
+ { interval : 5 } ,
200
+ ) ,
201
+ ) . resolves . toBeUndefined ( )
202
+ } )
203
+
204
+ test ( 'timeout' , async ( ) => {
205
+ const state = 'pending'
206
+
207
+ await expect (
208
+ waitFor (
209
+ ( ) => {
210
+ if ( state !== 'done' ) {
211
+ throw new Error ( 'Not done' )
212
+ }
213
+ } ,
214
+ { timeout : 10 } ,
215
+ ) ,
216
+ ) . rejects . toThrowErrorMatchingSnapshot ( )
217
+ } )
218
+
219
+ test ( 'can resolve early due to mutations' , async ( ) => {
220
+ const container = document . createElement ( 'div' )
221
+
222
+ setTimeout ( ( ) => {
223
+ container . appendChild ( document . createTextNode ( 'Done' ) )
224
+ } , 50 )
225
+
226
+ const p = waitFor (
227
+ ( ) => {
228
+ if ( container . textContent !== 'Done' ) {
229
+ throw new Error ( 'Not done' )
230
+ }
231
+ return container . textContent
232
+ } ,
233
+ // this would never resolve with real timers without using a MutationObserver
234
+ { container, interval : 200 , timeout : 200 } ,
235
+ )
236
+
237
+ await expect ( p ) . resolves . toBe ( 'Done' )
238
+ } )
164
239
} )
0 commit comments