|
9 | 9 | ApplicationInitStatus, |
10 | 10 | isStandalone, |
11 | 11 | } from '@angular/core'; |
12 | | -import { ComponentFixture, TestBed, tick } from '@angular/core/testing'; |
| 12 | +import { ComponentFixture, DeferBlockState, TestBed, tick } from '@angular/core/testing'; |
13 | 13 | import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; |
14 | 14 | import { NavigationExtras, Router } from '@angular/router'; |
15 | 15 | import { RouterTestingModule } from '@angular/router/testing'; |
@@ -65,6 +65,7 @@ export async function render<SutType, WrapperType = SutType>( |
65 | 65 | removeAngularAttributes = false, |
66 | 66 | defaultImports = [], |
67 | 67 | initialRoute = '', |
| 68 | + deferBlockStates = undefined, |
68 | 69 | configureTestBed = () => { |
69 | 70 | /* noop*/ |
70 | 71 | }, |
@@ -160,10 +161,19 @@ export async function render<SutType, WrapperType = SutType>( |
160 | 161 | } |
161 | 162 | } |
162 | 163 |
|
163 | | - let fixture: ComponentFixture<SutType>; |
164 | 164 | let detectChanges: () => void; |
165 | 165 |
|
166 | | - await renderFixture(componentProperties, componentInputs, componentOutputs); |
| 166 | + const fixture = await renderFixture(componentProperties, componentInputs, componentOutputs); |
| 167 | + |
| 168 | + if (deferBlockStates) { |
| 169 | + if (Array.isArray(deferBlockStates)) { |
| 170 | + for (const deferBlockState of deferBlockStates) { |
| 171 | + await renderDeferBlock(fixture, deferBlockState.deferBlockState, deferBlockState.deferBlockIndex); |
| 172 | + } |
| 173 | + } else { |
| 174 | + await renderDeferBlock(fixture, deferBlockStates); |
| 175 | + } |
| 176 | + } |
167 | 177 |
|
168 | 178 | let renderedPropKeys = Object.keys(componentProperties); |
169 | 179 | let renderedInputKeys = Object.keys(componentInputs); |
@@ -210,60 +220,61 @@ export async function render<SutType, WrapperType = SutType>( |
210 | 220 | }; |
211 | 221 |
|
212 | 222 | return { |
213 | | - // @ts-ignore: fixture assigned |
214 | 223 | fixture, |
215 | 224 | detectChanges: () => detectChanges(), |
216 | 225 | navigate, |
217 | 226 | rerender, |
218 | | - // @ts-ignore: fixture assigned |
| 227 | + renderDeferBlock: async (deferBlockState: DeferBlockState, deferBlockIndex?: number) => { |
| 228 | + await renderDeferBlock(fixture, deferBlockState, deferBlockIndex); |
| 229 | + }, |
219 | 230 | debugElement: fixture.debugElement, |
220 | | - // @ts-ignore: fixture assigned |
221 | 231 | container: fixture.nativeElement, |
222 | 232 | debug: (element = fixture.nativeElement, maxLength, options) => |
223 | 233 | Array.isArray(element) |
224 | 234 | ? element.forEach((e) => console.log(dtlPrettyDOM(e, maxLength, options))) |
225 | 235 | : console.log(dtlPrettyDOM(element, maxLength, options)), |
226 | | - // @ts-ignore: fixture assigned |
227 | 236 | ...replaceFindWithFindAndDetectChanges(dtlGetQueriesForElement(fixture.nativeElement, queries)), |
228 | 237 | }; |
229 | 238 |
|
230 | | - async function renderFixture(properties: Partial<SutType>, inputs: Partial<SutType>, outputs: Partial<SutType>) { |
231 | | - if (fixture) { |
232 | | - cleanupAtFixture(fixture); |
233 | | - } |
234 | | - |
235 | | - fixture = await createComponent(componentContainer); |
236 | | - setComponentProperties(fixture, properties); |
237 | | - setComponentInputs(fixture, inputs); |
238 | | - setComponentOutputs(fixture, outputs); |
| 239 | + async function renderFixture( |
| 240 | + properties: Partial<SutType>, |
| 241 | + inputs: Partial<SutType>, |
| 242 | + outputs: Partial<SutType>, |
| 243 | + ): Promise<ComponentFixture<SutType>> { |
| 244 | + const createdFixture = await createComponent(componentContainer); |
| 245 | + setComponentProperties(createdFixture, properties); |
| 246 | + setComponentInputs(createdFixture, inputs); |
| 247 | + setComponentOutputs(createdFixture, outputs); |
239 | 248 |
|
240 | 249 | if (removeAngularAttributes) { |
241 | | - fixture.nativeElement.removeAttribute('ng-version'); |
242 | | - const idAttribute = fixture.nativeElement.getAttribute('id'); |
| 250 | + createdFixture.nativeElement.removeAttribute('ng-version'); |
| 251 | + const idAttribute = createdFixture.nativeElement.getAttribute('id'); |
243 | 252 | if (idAttribute && idAttribute.startsWith('root')) { |
244 | | - fixture.nativeElement.removeAttribute('id'); |
| 253 | + createdFixture.nativeElement.removeAttribute('id'); |
245 | 254 | } |
246 | 255 | } |
247 | 256 |
|
248 | | - mountedFixtures.add(fixture); |
| 257 | + mountedFixtures.add(createdFixture); |
249 | 258 |
|
250 | 259 | let isAlive = true; |
251 | | - fixture.componentRef.onDestroy(() => (isAlive = false)); |
| 260 | + createdFixture.componentRef.onDestroy(() => (isAlive = false)); |
252 | 261 |
|
253 | | - if (hasOnChangesHook(fixture.componentInstance) && Object.keys(properties).length > 0) { |
| 262 | + if (hasOnChangesHook(createdFixture.componentInstance) && Object.keys(properties).length > 0) { |
254 | 263 | const changes = getChangesObj(null, componentProperties); |
255 | | - fixture.componentInstance.ngOnChanges(changes); |
| 264 | + createdFixture.componentInstance.ngOnChanges(changes); |
256 | 265 | } |
257 | 266 |
|
258 | 267 | detectChanges = () => { |
259 | 268 | if (isAlive) { |
260 | | - fixture.detectChanges(); |
| 269 | + createdFixture.detectChanges(); |
261 | 270 | } |
262 | 271 | }; |
263 | 272 |
|
264 | 273 | if (detectChangesOnRender) { |
265 | 274 | detectChanges(); |
266 | 275 | } |
| 276 | + |
| 277 | + return createdFixture; |
267 | 278 | } |
268 | 279 | } |
269 | 280 |
|
@@ -429,6 +440,30 @@ function addAutoImports<SutType>( |
429 | 440 | return [...imports, ...components(), ...animations(), ...routing()]; |
430 | 441 | } |
431 | 442 |
|
| 443 | +async function renderDeferBlock<SutType>( |
| 444 | + fixture: ComponentFixture<SutType>, |
| 445 | + deferBlockState: DeferBlockState, |
| 446 | + deferBlockIndex?: number, |
| 447 | +) { |
| 448 | + const deferBlockFixtures = await fixture.getDeferBlocks(); |
| 449 | + |
| 450 | + if (deferBlockIndex !== undefined) { |
| 451 | + if (deferBlockIndex < 0) { |
| 452 | + throw new Error('deferBlockIndex must be a positive number'); |
| 453 | + } |
| 454 | + |
| 455 | + const deferBlockFixture = deferBlockFixtures[deferBlockIndex]; |
| 456 | + if (!deferBlockFixture) { |
| 457 | + throw new Error(`Could not find a deferrable block with index '${deferBlockIndex}'`); |
| 458 | + } |
| 459 | + await deferBlockFixture.render(deferBlockState); |
| 460 | + } else { |
| 461 | + for (const deferBlockFixture of deferBlockFixtures) { |
| 462 | + await deferBlockFixture.render(deferBlockState); |
| 463 | + } |
| 464 | + } |
| 465 | +} |
| 466 | + |
432 | 467 | /** |
433 | 468 | * Wrap waitFor to invoke the Angular change detection cycle before invoking the callback |
434 | 469 | */ |
|
0 commit comments