9
9
FireObject ,
10
10
getQueriesForElement ,
11
11
prettyDOM ,
12
- waitFor ,
13
- waitForElementToBeRemoved ,
12
+ waitFor as dtlWaitFor ,
13
+ waitForElementToBeRemoved as dtlWaitForElementToBeRemoved ,
14
14
fireEvent as dtlFireEvent ,
15
15
screen as dtlScreen ,
16
16
queries as dtlQueries ,
@@ -153,38 +153,22 @@ export async function render<SutType, WrapperType = SutType>(
153
153
container ?: HTMLElement ;
154
154
timeout ?: number ;
155
155
interval ?: number ;
156
- mutationObserverOptions ?: {
157
- subtree : boolean ;
158
- childList : boolean ;
159
- attributes : boolean ;
160
- characterData : boolean ;
161
- } ;
156
+ mutationObserverOptions ?: MutationObserverInit ;
162
157
} = { container : fixture . nativeElement } ,
163
158
) : Promise < T > {
164
- return waitFor < T > ( ( ) => {
165
- detectChanges ( ) ;
166
- return callback ( ) ;
167
- } , options ) ;
159
+ return waitForWrapper ( detectChanges , callback , options ) ;
168
160
}
169
161
170
162
function componentWaitForElementToBeRemoved < T > (
171
- callback : ( ) => T ,
163
+ callback : ( ( ) => T ) | T ,
172
164
options : {
173
165
container ?: HTMLElement ;
174
166
timeout ?: number ;
175
167
interval ?: number ;
176
- mutationObserverOptions ?: {
177
- subtree : boolean ;
178
- childList : boolean ;
179
- attributes : boolean ;
180
- characterData : boolean ;
181
- } ;
168
+ mutationObserverOptions ?: MutationObserverInit ;
182
169
} = { container : fixture . nativeElement } ,
183
170
) : Promise < T > {
184
- return waitForElementToBeRemoved < T > ( ( ) => {
185
- detectChanges ( ) ;
186
- return callback ( ) ;
187
- } , options ) ;
171
+ return waitForElementToBeRemovedWrapper ( detectChanges , callback , options ) ;
188
172
}
189
173
190
174
return {
@@ -266,28 +250,57 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
266
250
return [ ...imports , ...animations ( ) , ...routing ( ) ] ;
267
251
}
268
252
269
- // for the findBy queries we first want to run a change detection cycle
270
- function replaceFindWithFindAndDetectChanges < T > ( container : HTMLElement , originalQueriesForContainer : T ) : T {
271
- return Object . keys ( originalQueriesForContainer ) . reduce (
272
- ( newQueries , key ) => {
273
- if ( key . startsWith ( 'find' ) ) {
274
- const getByQuery = dtlQueries [ key . replace ( 'find' , 'get' ) ] ;
275
- newQueries [ key ] = async ( text , options , waitForOptions ) => {
276
- // original implementation at https://github.com/testing-library/dom-testing-library/blob/master/src/query-helpers.js
277
- const result = await waitFor ( ( ) => {
278
- detectChangesForMountedFixtures ( ) ;
279
- return getByQuery ( container , text , options ) ;
280
- } , waitForOptions ) ;
281
- return result ;
282
- } ;
283
- } else {
284
- newQueries [ key ] = originalQueriesForContainer [ key ] ;
253
+ /**
254
+ * Wrap waitFor to poke the Angular change detection cycle before invoking the callback
255
+ */
256
+ async function waitForWrapper < T > (
257
+ detectChanges : ( ) => void ,
258
+ callback : ( ) => T ,
259
+ options ?: {
260
+ container ?: HTMLElement ;
261
+ timeout ?: number ;
262
+ interval ?: number ;
263
+ mutationObserverOptions ?: MutationObserverInit ;
264
+ } ,
265
+ ) : Promise < T > {
266
+ return await dtlWaitFor ( ( ) => {
267
+ detectChanges ( ) ;
268
+ return callback ( ) ;
269
+ } , options ) ;
270
+ }
271
+
272
+ /**
273
+ * Wrap waitForElementToBeRemovedWrapper to poke the Angular change detection cycle before invoking the callback
274
+ */
275
+ async function waitForElementToBeRemovedWrapper < T > (
276
+ detectChanges : ( ) => void ,
277
+ callback : ( ( ) => T ) | T ,
278
+ options ?: {
279
+ container ?: HTMLElement ;
280
+ timeout ?: number ;
281
+ interval ?: number ;
282
+ mutationObserverOptions ?: MutationObserverInit ;
283
+ } ,
284
+ ) : Promise < T > {
285
+ let cb ;
286
+ if ( typeof callback !== 'function' ) {
287
+ const elements = ( Array . isArray ( callback ) ? callback : [ callback ] ) as HTMLElement [ ] ;
288
+ const getRemainingElements = elements . map ( element => {
289
+ let parent = element . parentElement ;
290
+ while ( parent . parentElement ) {
291
+ parent = parent . parentElement ;
285
292
}
293
+ return ( ) => ( parent . contains ( element ) ? element : null ) ;
294
+ } ) ;
295
+ cb = ( ) => getRemainingElements . map ( c => c ( ) ) . filter ( Boolean ) ;
296
+ } else {
297
+ cb = callback ;
298
+ }
286
299
287
- return newQueries ;
288
- } ,
289
- { } as T ,
290
- ) ;
300
+ return await dtlWaitForElementToBeRemoved ( ( ) => {
301
+ detectChanges ( ) ;
302
+ return cb ( ) ;
303
+ } , options ) ;
291
304
}
292
305
293
306
function cleanup ( ) {
@@ -307,11 +320,43 @@ if (typeof afterEach === 'function' && !process.env.ATL_SKIP_AUTO_CLEANUP) {
307
320
} ) ;
308
321
}
309
322
323
+ /**
324
+ * Wrap findBy queries to poke the Angular change detection cycle
325
+ */
326
+ function replaceFindWithFindAndDetectChanges < T > ( container : HTMLElement , originalQueriesForContainer : T ) : T {
327
+ return Object . keys ( originalQueriesForContainer ) . reduce (
328
+ ( newQueries , key ) => {
329
+ if ( key . startsWith ( 'find' ) ) {
330
+ const getByQuery = dtlQueries [ key . replace ( 'find' , 'get' ) ] ;
331
+ newQueries [ key ] = async ( text , options , waitForOptions ) => {
332
+ // original implementation at https://github.com/testing-library/dom-testing-library/blob/master/src/query-helpers.js
333
+ const result = await waitForWrapper (
334
+ detectChangesForMountedFixtures ,
335
+ ( ) => getByQuery ( container , text , options ) ,
336
+ waitForOptions ,
337
+ ) ;
338
+ return result ;
339
+ } ;
340
+ } else {
341
+ newQueries [ key ] = originalQueriesForContainer [ key ] ;
342
+ }
343
+
344
+ return newQueries ;
345
+ } ,
346
+ { } as T ,
347
+ ) ;
348
+ }
349
+
350
+ /**
351
+ * Call detectChanges for all fixtures
352
+ */
310
353
function detectChangesForMountedFixtures ( ) {
311
354
mountedFixtures . forEach ( fixture => fixture . detectChanges ( ) ) ;
312
355
}
313
356
314
- // wrap dom-fireEvent with a change detection cycle
357
+ /**
358
+ * Wrap dom-fireEvent to poke the Angular change detection cycle after an event is fired
359
+ */
315
360
const fireEvent = Object . keys ( dtlFireEvent ) . reduce (
316
361
( events , key ) => {
317
362
events [ key ] = ( element : HTMLElement , options ?: { } ) => {
@@ -324,18 +369,55 @@ const fireEvent = Object.keys(dtlFireEvent).reduce(
324
369
{ } as typeof dtlFireEvent ,
325
370
) ;
326
371
372
+ /**
373
+ * Re-export screen with patched queries
374
+ */
327
375
const screen = replaceFindWithFindAndDetectChanges ( document . body , dtlScreen ) ;
328
376
329
- // wrap user-events with the correct fireEvents
377
+ /**
378
+ * Re-export waitFor with patched waitFor
379
+ */
380
+ async function waitFor < T > (
381
+ callback : ( ) => T ,
382
+ options ?: {
383
+ container ?: HTMLElement ;
384
+ timeout ?: number ;
385
+ interval ?: number ;
386
+ mutationObserverOptions ?: MutationObserverInit ;
387
+ } ,
388
+ ) : Promise < T > {
389
+ return waitForWrapper ( detectChangesForMountedFixtures , callback , options ) ;
390
+ }
391
+
392
+ /**
393
+ * Re-export waitForElementToBeRemoved with patched waitForElementToBeRemoved
394
+ */
395
+ async function waitForElementToBeRemoved < T > (
396
+ callback : ( ( ) => T ) | T ,
397
+ options ?: {
398
+ container ?: HTMLElement ;
399
+ timeout ?: number ;
400
+ interval ?: number ;
401
+ mutationObserverOptions ?: MutationObserverInit ;
402
+ } ,
403
+ ) : Promise < T > {
404
+ return waitForElementToBeRemovedWrapper ( detectChangesForMountedFixtures , callback , options ) ;
405
+ }
406
+
407
+ /**
408
+ * Re-export userEvent with the patched fireEvent
409
+ */
330
410
const userEvent = {
331
411
type : createType ( fireEvent ) ,
332
412
selectOptions : createSelectOptions ( fireEvent ) ,
333
413
tab : tab ,
334
414
} ;
335
415
336
- // manually export otherwise we get the following error while running Jest tests
337
- // TypeError: Cannot set property fireEvent of [object Object] which has only a getter
338
- // exports.fireEvent = fireEvent;
416
+ /**
417
+ * Manually export otherwise we get the following error while running Jest tests
418
+ * TypeError: Cannot set property fireEvent of [object Object] which has only a getter
419
+ * exports.fireEvent = fireEvent
420
+ */
339
421
export {
340
422
buildQueries ,
341
423
configure ,
@@ -401,12 +483,7 @@ export {
401
483
queryAllByAttribute ,
402
484
queryByAttribute ,
403
485
queryHelpers ,
404
- wait ,
405
- waitFor ,
406
- waitForDomChange ,
407
- waitForElement ,
408
- waitForElementToBeRemoved ,
409
486
within ,
410
487
} from '@testing-library/dom' ;
411
488
412
- export { fireEvent , screen , userEvent } ;
489
+ export { fireEvent , screen , userEvent , waitFor , waitForElementToBeRemoved } ;
0 commit comments