@@ -5,21 +5,23 @@ import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform
5
5
import { Router } from '@angular/router' ;
6
6
import { RouterTestingModule } from '@angular/router/testing' ;
7
7
import {
8
- fireEvent ,
9
8
FireFunction ,
10
9
FireObject ,
11
10
getQueriesForElement ,
12
11
prettyDOM ,
13
12
waitFor ,
14
13
waitForElementToBeRemoved ,
14
+ fireEvent as dtlFireEvent ,
15
+ screen as dtlScreen ,
16
+ queries as dtlQueries ,
15
17
} from '@testing-library/dom' ;
16
18
import { RenderComponentOptions , RenderDirectiveOptions , RenderResult } from './models' ;
17
19
import { createSelectOptions , createType , tab } from './user-events' ;
18
20
19
21
@Component ( { selector : 'wrapper-component' , template : '' } )
20
22
class WrapperComponent { }
21
23
22
- const mountedContainers = new Set ( ) ;
24
+ const mountedFixtures = new Set < ComponentFixture < any > > ( ) ;
23
25
24
26
export async function render < ComponentType > (
25
27
component : Type < ComponentType > ,
@@ -75,9 +77,10 @@ export async function render<SutType, WrapperType = SutType>(
75
77
if ( idAttribute && idAttribute . startsWith ( 'root' ) ) {
76
78
fixture . nativeElement . removeAttribute ( 'id' ) ;
77
79
}
78
- mountedContainers . add ( fixture . nativeElement ) ;
79
80
}
80
81
82
+ mountedFixtures . add ( fixture ) ;
83
+
81
84
await TestBed . compileComponents ( ) ;
82
85
83
86
let isAlive = true ;
@@ -93,10 +96,10 @@ export async function render<SutType, WrapperType = SutType>(
93
96
detectChanges ( ) ;
94
97
}
95
98
96
- const eventsWithDetectChanges = Object . keys ( fireEvent ) . reduce (
99
+ const eventsWithDetectChanges = Object . keys ( dtlFireEvent ) . reduce (
97
100
( events , key ) => {
98
101
events [ key ] = ( element : HTMLElement , options ?: { } ) => {
99
- const result = fireEvent [ key ] ( element , options ) ;
102
+ const result = dtlFireEvent [ key ] ( element , options ) ;
100
103
detectChanges ( ) ;
101
104
return result ;
102
105
} ;
@@ -137,10 +140,12 @@ export async function render<SutType, WrapperType = SutType>(
137
140
attributes : boolean ;
138
141
characterData : boolean ;
139
142
} ;
140
- } = { container : fixture . nativeElement , interval : 50 } ,
143
+ } = { container : fixture . nativeElement } ,
141
144
) : 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 ) ;
144
149
}
145
150
146
151
function componentWaitForElementToBeRemoved < T > (
@@ -155,10 +160,12 @@ export async function render<SutType, WrapperType = SutType>(
155
160
attributes : boolean ;
156
161
characterData : boolean ;
157
162
} ;
158
- } = { container : fixture . nativeElement , interval : 50 } ,
163
+ } = { container : fixture . nativeElement } ,
159
164
) : 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 ) ;
162
169
}
163
170
164
171
return {
@@ -168,13 +175,16 @@ export async function render<SutType, WrapperType = SutType>(
168
175
rerender,
169
176
debugElement : fixture . debugElement . query ( By . directive ( sut ) ) ,
170
177
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 ) ) ,
172
182
type : createType ( eventsWithDetectChanges ) ,
173
183
selectOptions : createSelectOptions ( eventsWithDetectChanges ) ,
174
184
tab,
175
185
waitFor : componentWaitFor ,
176
186
waitForElementToBeRemoved : componentWaitForElementToBeRemoved ,
177
- ...getQueriesForElement ( fixture . nativeElement , queries ) ,
187
+ ...replaceFindWithFindAndDetectChanges ( fixture . nativeElement , getQueriesForElement ( fixture . nativeElement , queries ) ) ,
178
188
...eventsWithDetectChanges ,
179
189
} ;
180
190
}
@@ -237,19 +247,65 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
237
247
return [ ...imports , ...animations ( ) , ...routing ( ) ] ;
238
248
}
239
249
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
+
240
274
function cleanup ( ) {
241
- mountedContainers . forEach ( cleanupAtContainer ) ;
275
+ mountedFixtures . forEach ( cleanupAtFixture ) ;
242
276
}
243
277
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 ) ;
247
281
}
248
- mountedContainers . delete ( container ) ;
282
+ mountedFixtures . delete ( fixture ) ;
249
283
}
250
284
251
285
if ( typeof afterEach === 'function' && ! process . env . ATL_SKIP_AUTO_CLEANUP ) {
252
286
afterEach ( async ( ) => {
253
287
cleanup ( ) ;
254
288
} ) ;
255
289
}
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