From 5c8b02104c59e344508a3942f655fee772b16311 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Thu, 2 Nov 2023 13:02:35 -0700 Subject: [PATCH] test(core): Ensure signals can be read after view creation during change detection These tests ensure signals can be read in a template after embedded views are created in the middle of template execution of an update pass. The embedded view templates are executed in create mode in the middle of the component template being executed in update mode. This behavior was found to not work correctly in past implementations of the reactive template consumers. --- .../change_detection_signals_in_zones_spec.ts | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/core/test/acceptance/change_detection_signals_in_zones_spec.ts b/packages/core/test/acceptance/change_detection_signals_in_zones_spec.ts index aafffb0dcca9..9195f0460fa8 100644 --- a/packages/core/test/acceptance/change_detection_signals_in_zones_spec.ts +++ b/packages/core/test/acceptance/change_detection_signals_in_zones_spec.ts @@ -8,7 +8,7 @@ import {NgFor, NgIf} from '@angular/common'; import {PLATFORM_BROWSER_ID} from '@angular/common/src/platform_id'; -import {afterNextRender, ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, Directive, inject, Input, PLATFORM_ID, signal, ViewChild} from '@angular/core'; +import {afterNextRender, ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, Directive, inject, Input, PLATFORM_ID, signal, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; describe('CheckAlways components', () => { @@ -628,6 +628,53 @@ describe('OnPush components with signals', () => { }); describe('embedded views', () => { + describe('with a signal read after view creation during an update pass', () => { + it('should work with native control flow', () => { + @Component({ + template: ` + @if (true) { } + {{val()}} + `, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + }) + class MyComp { + val = signal('initial'); + } + + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + fixture.componentInstance.val.set('new'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerText).toBe('new'); + }); + + it('should work with createEmbeddedView', () => { + @Component({ + template: ` + + {{createEmbeddedView(template)}} + {{val()}} + `, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + }) + class MyComp { + val = signal('initial'); + vcr = inject(ViewContainerRef); + createEmbeddedView(ref: TemplateRef<{}>) { + this.vcr.createEmbeddedView(ref); + } + } + + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + fixture.componentInstance.val.set('new'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerText).toBe('new'); + }); + }); + it('refreshes an embedded view in a component', () => { @Component({ selector: 'signal-component',