@@ -5,21 +5,23 @@ import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform
55import { Router } from '@angular/router' ;
66import { RouterTestingModule } from '@angular/router/testing' ;
77import {
8- fireEvent ,
98 FireFunction ,
109 FireObject ,
1110 getQueriesForElement ,
1211 prettyDOM ,
1312 waitFor ,
1413 waitForElementToBeRemoved ,
14+ fireEvent as dtlFireEvent ,
15+ screen as dtlScreen ,
16+ queries as dtlQueries ,
1517} from '@testing-library/dom' ;
1618import { RenderComponentOptions , RenderDirectiveOptions , RenderResult } from './models' ;
1719import { createSelectOptions , createType , tab } from './user-events' ;
1820
1921@Component ( { selector : 'wrapper-component' , template : '' } )
2022class WrapperComponent { }
2123
22- const mountedContainers = new Set ( ) ;
24+ const mountedFixtures = new Set < ComponentFixture < any > > ( ) ;
2325
2426export async function render < ComponentType > (
2527 component : Type < ComponentType > ,
@@ -75,9 +77,10 @@ export async function render<SutType, WrapperType = SutType>(
7577 if ( idAttribute && idAttribute . startsWith ( 'root' ) ) {
7678 fixture . nativeElement . removeAttribute ( 'id' ) ;
7779 }
78- mountedContainers . add ( fixture . nativeElement ) ;
7980 }
8081
82+ mountedFixtures . add ( fixture ) ;
83+
8184 await TestBed . compileComponents ( ) ;
8285
8386 let isAlive = true ;
@@ -93,10 +96,10 @@ export async function render<SutType, WrapperType = SutType>(
9396 detectChanges ( ) ;
9497 }
9598
96- const eventsWithDetectChanges = Object . keys ( fireEvent ) . reduce (
99+ const eventsWithDetectChanges = Object . keys ( dtlFireEvent ) . reduce (
97100 ( events , key ) => {
98101 events [ key ] = ( element : HTMLElement , options ?: { } ) => {
99- const result = fireEvent [ key ] ( element , options ) ;
102+ const result = dtlFireEvent [ key ] ( element , options ) ;
100103 detectChanges ( ) ;
101104 return result ;
102105 } ;
@@ -137,10 +140,12 @@ export async function render<SutType, WrapperType = SutType>(
137140 attributes : boolean ;
138141 characterData : boolean ;
139142 } ;
140- } = { container : fixture . nativeElement , interval : 50 } ,
143+ } = { container : fixture . nativeElement } ,
141144 ) : Promise < T > {
142- const interval = setInterval ( detectChanges , options . interval ) ;
143- return waitFor < T > ( callback , options ) . finally ( ( ) => clearInterval ( interval ) ) ;
145+ return waitFor < T > ( ( ) => {
146+ detectChanges ( ) ;
147+ return callback ( ) ;
148+ } , options ) ;
144149 }
145150
146151 function componentWaitForElementToBeRemoved < T > (
@@ -155,10 +160,12 @@ export async function render<SutType, WrapperType = SutType>(
155160 attributes : boolean ;
156161 characterData : boolean ;
157162 } ;
158- } = { container : fixture . nativeElement , interval : 50 } ,
163+ } = { container : fixture . nativeElement } ,
159164 ) : Promise < T > {
160- const interval = setInterval ( detectChanges , options . interval ) ;
161- return waitForElementToBeRemoved < T > ( callback , options ) . finally ( ( ) => clearInterval ( interval ) ) ;
165+ return waitForElementToBeRemoved < T > ( ( ) => {
166+ detectChanges ( ) ;
167+ return callback ( ) ;
168+ } , options ) ;
162169 }
163170
164171 return {
@@ -168,13 +175,16 @@ export async function render<SutType, WrapperType = SutType>(
168175 rerender,
169176 debugElement : fixture . debugElement . query ( By . directive ( sut ) ) ,
170177 container : fixture . nativeElement ,
171- debug : ( element = fixture . nativeElement ) => console . log ( prettyDOM ( element ) ) ,
178+ debug : ( element = fixture . nativeElement , maxLength , options ) =>
179+ Array . isArray ( element )
180+ ? element . forEach ( e => console . log ( prettyDOM ( e , maxLength , options ) ) )
181+ : console . log ( prettyDOM ( element , maxLength , options ) ) ,
172182 type : createType ( eventsWithDetectChanges ) ,
173183 selectOptions : createSelectOptions ( eventsWithDetectChanges ) ,
174184 tab,
175185 waitFor : componentWaitFor ,
176186 waitForElementToBeRemoved : componentWaitForElementToBeRemoved ,
177- ...getQueriesForElement ( fixture . nativeElement , queries ) ,
187+ ...replaceFindWithFindAndDetectChanges ( fixture . nativeElement , getQueriesForElement ( fixture . nativeElement , queries ) ) ,
178188 ...eventsWithDetectChanges ,
179189 } ;
180190}
@@ -237,19 +247,65 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
237247 return [ ...imports , ...animations ( ) , ...routing ( ) ] ;
238248}
239249
250+ // for the findBy queries we first want to run a change detection cycle
251+ function replaceFindWithFindAndDetectChanges < T > ( container : HTMLElement , originalQueriesForContainer : T ) : T {
252+ return Object . keys ( originalQueriesForContainer ) . reduce (
253+ ( newQueries , key ) => {
254+ if ( key . startsWith ( 'find' ) ) {
255+ const getByQuery = dtlQueries [ key . replace ( 'find' , 'get' ) ] ;
256+ newQueries [ key ] = async ( text , options , waitForOptions ) => {
257+ // original implementation at https://github.com/testing-library/dom-testing-library/blob/master/src/query-helpers.js
258+ const result = await waitFor ( ( ) => {
259+ detectChangesForMountedFixtures ( ) ;
260+ return getByQuery ( container , text , options ) ;
261+ } , waitForOptions ) ;
262+ return result ;
263+ } ;
264+ } else {
265+ newQueries [ key ] = originalQueriesForContainer [ key ] ;
266+ }
267+
268+ return newQueries ;
269+ } ,
270+ { } as T ,
271+ ) ;
272+ }
273+
240274function cleanup ( ) {
241- mountedContainers . forEach ( cleanupAtContainer ) ;
275+ mountedFixtures . forEach ( cleanupAtFixture ) ;
242276}
243277
244- function cleanupAtContainer ( container ) {
245- if ( container . parentNode === document . body ) {
246- document . body . removeChild ( container ) ;
278+ function cleanupAtFixture ( fixture ) {
279+ if ( ! fixture . nativeElement . getAttribute ( 'ng-version' ) && fixture . nativeElement . parentNode === document . body ) {
280+ document . body . removeChild ( fixture . nativeElement ) ;
247281 }
248- mountedContainers . delete ( container ) ;
282+ mountedFixtures . delete ( fixture ) ;
249283}
250284
251285if ( typeof afterEach === 'function' && ! process . env . ATL_SKIP_AUTO_CLEANUP ) {
252286 afterEach ( async ( ) => {
253287 cleanup ( ) ;
254288 } ) ;
255289}
290+
291+ function detectChangesForMountedFixtures ( ) {
292+ mountedFixtures . forEach ( fixture => fixture . detectChanges ( ) ) ;
293+ }
294+
295+ export * from '@testing-library/dom' ;
296+
297+ const fireEvent = Object . keys ( dtlFireEvent ) . reduce (
298+ ( events , key ) => {
299+ events [ key ] = ( element : HTMLElement , options ?: { } ) => {
300+ const result = dtlFireEvent [ key ] ( element , options ) ;
301+ detectChangesForMountedFixtures ( ) ;
302+ return result ;
303+ } ;
304+ return events ;
305+ } ,
306+ { } as typeof dtlFireEvent ,
307+ ) ;
308+
309+ const screen = replaceFindWithFindAndDetectChanges ( document . body , dtlScreen ) ;
310+
311+ export { fireEvent , screen } ;
0 commit comments