|
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