/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/core/test/defer_fixture_spec.ts
447 строк
13 KB
Matthieu Riegler
ci: reformat files
17 дек 2025, 01:44
17 дек 2025, 01:44
6270bba
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import {ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; import {Component, inject, PLATFORM_ID, ViewContainerRef} from '../src/core'; import {PendingTasksInternal} from '../src/pending_tasks_internal'; import {DeferBlockBehavior, DeferBlockState, TestBed} from '../testing'; import {expect} from '@angular/private/testing/matchers'; @Component({ selector: 'second-deferred-comp', template: `<div class="more">More Deferred Component</div>`, }) class SecondDeferredComp {} const COMMON_PROVIDERS = [{provide: PLATFORM_ID, useValue: PLATFORM_BROWSER_ID}]; describe('DeferFixture', () => { it('should start in manual behavior mode', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, teardown: {destroyAfterEach: true}, }); const componentFixture = TestBed.createComponent(DeferComp); const el = componentFixture.nativeElement as HTMLElement; expect(el.querySelectorAll('.more').length).toBe(0); }); it('should start in manual trigger mode by default', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, }); const componentFixture = TestBed.createComponent(DeferComp); const el = componentFixture.nativeElement as HTMLElement; expect(el.querySelectorAll('.more').length).toBe(0); }); it('should defer load immediately on playthrough', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (when shouldLoad) { <second-deferred-comp /> } </div> `, }) class DeferComp { shouldLoad = false; } TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, }); const componentFixture = TestBed.createComponent(DeferComp); const el = componentFixture.nativeElement as HTMLElement; expect(el.querySelectorAll('.more').length).toBe(0); componentFixture.componentInstance.shouldLoad = true; componentFixture.detectChanges(); await componentFixture.whenStable(); // await loading of deps expect(el.querySelector('.more')).toBeDefined(); }); it('should not defer load immediately when set to manual', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (when shouldLoad) { <second-deferred-comp /> } </div> `, }) class DeferComp { shouldLoad = false; } TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const el = componentFixture.nativeElement as HTMLElement; expect(el.querySelectorAll('.more').length).toBe(0); componentFixture.componentInstance.shouldLoad = true; componentFixture.detectChanges(); await componentFixture.whenStable(); // await loading of deps expect(el.querySelectorAll('.more').length).toBe(0); }); it('should render a completed defer state', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Complete); expect(el.querySelector('.more')).toBeDefined(); }); it('should not wait forever if application is unstable for a long time', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp { constructor(taskService: PendingTasksInternal) { // Add a task and never remove it. Keeps application unstable forever taskService.add(); } } TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Complete); expect(el.querySelector('.more')).toBeDefined(); }); it('should work with templates that have local refs', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <ng-template #template>Hello</ng-template> <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Complete); expect(el.querySelector('.more')).toBeDefined(); }); it('should render a placeholder defer state', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } @placeholder { <span class="ph">This is placeholder content</span> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Placeholder); expect(el.querySelectorAll('.more').length).toBe(0); const phContent = el.querySelector('.ph'); expect(phContent).toBeDefined(); expect(phContent?.innerHTML).toBe('This is placeholder content'); }); it('should render a loading defer state', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } @loading { <span class="loading">Loading...</span> } w </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Loading); expect(el.querySelectorAll('.more').length).toBe(0); const loadingContent = el.querySelector('.loading'); expect(loadingContent).toBeDefined(); expect(loadingContent?.innerHTML).toBe('Loading...'); }); it('should render an error defer state', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } @error { <span class="error">Flagrant Error!</span> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; const el = componentFixture.nativeElement as HTMLElement; await deferBlock.render(DeferBlockState.Error); expect(el.querySelectorAll('.more').length).toBe(0); const errContent = el.querySelector('.error'); expect(errContent).toBeDefined(); expect(errContent?.innerHTML).toBe('Flagrant Error!'); }); it('should throw when rendering a template that does not exist', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; try { await deferBlock.render(DeferBlockState.Placeholder); } catch (er: any) { expect(er.message).toBe( 'Tried to render this defer block in the `Placeholder` state, but' + ' there was no @placeholder block defined in a template.', ); } }); it('should transition between states when `after` and `minimum` are used', async () => { @Component({ selector: 'defer-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { Main content } @loading (after 1s) { Loading } @placeholder (minimum 2s) { Placeholder } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, SecondDeferredComp], providers: COMMON_PROVIDERS, deferBlockBehavior: DeferBlockBehavior.Manual, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; await deferBlock.render(DeferBlockState.Placeholder); expect(componentFixture.nativeElement.outerHTML).toContain('Placeholder'); await deferBlock.render(DeferBlockState.Loading); expect(componentFixture.nativeElement.outerHTML).toContain('Loading'); await deferBlock.render(DeferBlockState.Complete); expect(componentFixture.nativeElement.outerHTML).toContain('Main'); }); it('should get child defer blocks', async () => { @Component({ selector: 'deferred-comp', imports: [SecondDeferredComp], template: ` <div> @defer (on immediate) { <second-deferred-comp /> } </div> `, }) class DeferredComp {} @Component({ selector: 'defer-comp', imports: [DeferredComp], template: ` <div> @defer (on immediate) { <deferred-comp /> } </div> `, }) class DeferComp {} TestBed.configureTestingModule({ imports: [DeferComp, DeferredComp, SecondDeferredComp], providers: COMMON_PROVIDERS, }); const componentFixture = TestBed.createComponent(DeferComp); const deferBlock = (await componentFixture.getDeferBlocks())[0]; await deferBlock.render(DeferBlockState.Complete); const fixtures = await deferBlock.getDeferBlocks(); expect(fixtures.length).toBe(1); }); it('should resolve defer blocks in components that inject ViewContainerRef', async () => { @Component({template: '@defer {Hello}'}) class DeferTestComponent { viewContainerRef = inject(ViewContainerRef); } TestBed.configureTestingModule({deferBlockBehavior: DeferBlockBehavior.Manual}); const fixture = TestBed.createComponent(DeferTestComponent); fixture.detectChanges(); const deferBlocks = await fixture.getDeferBlocks(); expect(deferBlocks.length).toBe(1); expect(fixture.componentInstance.viewContainerRef).toBeTruthy(); }); });