|
6 | 6 | * found in the LICENSE file at https://angular.io/license
|
7 | 7 | */
|
8 | 8 |
|
9 |
| -import {Component, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; |
| 9 | +import {Component, ComponentFactoryResolver, Injector, NgModule, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; |
10 | 10 | import {TestBed} from '@angular/core/testing';
|
11 | 11 | import {expect} from '@angular/platform-browser/testing/src/matchers';
|
12 | 12 | import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
@@ -180,5 +180,97 @@ describe('TemplateRef', () => {
|
180 | 180 | expect(rootNodes.length).toBe(7);
|
181 | 181 | }
|
182 | 182 | });
|
| 183 | + |
| 184 | + it('should return an empty array for an embedded view with projection and no projectable nodes', |
| 185 | + () => { |
| 186 | + const rootNodes = |
| 187 | + getRootNodes(`<ng-template #templateRef><ng-content></ng-content></ng-template>`); |
| 188 | + // VE will, incorrectly, return an additional comment node in this case |
| 189 | + expect(rootNodes.length).toBe(ivyEnabled ? 0 : 1); |
| 190 | + }); |
| 191 | + |
| 192 | + it('should return an empty array for an embedded view with multiple projections and no projectable nodes', |
| 193 | + () => { |
| 194 | + const rootNodes = getRootNodes( |
| 195 | + `<ng-template #templateRef><ng-content></ng-content><ng-content select="foo"></ng-content></ng-template>`); |
| 196 | + // VE will, incorrectly, return an additional comment node in this case |
| 197 | + expect(rootNodes.length).toBe(ivyEnabled ? 0 : 1); |
| 198 | + }); |
| 199 | + |
| 200 | + describe('projectable nodes provided to a dynamically created component', () => { |
| 201 | + @Component({selector: 'dynamic', template: ''}) |
| 202 | + class DynamicCmp { |
| 203 | + @ViewChild('templateRef', {static: true}) templateRef!: TemplateRef<any>; |
| 204 | + } |
| 205 | + |
| 206 | + @NgModule({ |
| 207 | + declarations: [DynamicCmp], |
| 208 | + entryComponents: [DynamicCmp], |
| 209 | + }) |
| 210 | + class WithDynamicCmpModule { |
| 211 | + } |
| 212 | + |
| 213 | + @Component({selector: 'test', template: ''}) |
| 214 | + class TestCmp { |
| 215 | + constructor(public cfr: ComponentFactoryResolver) {} |
| 216 | + } |
| 217 | + |
| 218 | + beforeEach(() => { |
| 219 | + TestBed.configureTestingModule({ |
| 220 | + declarations: [TestCmp], |
| 221 | + imports: [WithDynamicCmpModule], |
| 222 | + }); |
| 223 | + }); |
| 224 | + |
| 225 | + it('should return projectable nodes when provided', () => { |
| 226 | + TestBed.overrideTemplate( |
| 227 | + DynamicCmp, `<ng-template #templateRef><ng-content></ng-content></ng-template>`); |
| 228 | + |
| 229 | + const fixture = TestBed.createComponent(TestCmp); |
| 230 | + const dynamicCmptFactory = |
| 231 | + fixture.componentInstance.cfr.resolveComponentFactory(DynamicCmp); |
| 232 | + |
| 233 | + // Number of projectable nodes matches the number of slots - all nodes should be returned |
| 234 | + const projectableNodes = [[document.createTextNode('textNode')]]; |
| 235 | + const cmptRef = dynamicCmptFactory.create(Injector.NULL, projectableNodes); |
| 236 | + const viewRef = cmptRef.instance.templateRef.createEmbeddedView({}); |
| 237 | + |
| 238 | + // VE will, incorrectly, return an additional comment node in this case |
| 239 | + expect(viewRef.rootNodes.length).toBe(ivyEnabled ? 1 : 2); |
| 240 | + }); |
| 241 | + |
| 242 | + it('should return an empty collection when no projectable nodes were provided', () => { |
| 243 | + TestBed.overrideTemplate( |
| 244 | + DynamicCmp, `<ng-template #templateRef><ng-content></ng-content></ng-template>`); |
| 245 | + |
| 246 | + const fixture = TestBed.createComponent(TestCmp); |
| 247 | + const dynamicCmptFactory = |
| 248 | + fixture.componentInstance.cfr.resolveComponentFactory(DynamicCmp); |
| 249 | + |
| 250 | + // There are slots but projectable nodes were not provided - nothing should be returned |
| 251 | + const cmptRef = dynamicCmptFactory.create(Injector.NULL, []); |
| 252 | + const viewRef = cmptRef.instance.templateRef.createEmbeddedView({}); |
| 253 | + |
| 254 | + // VE will, incorrectly, return an additional comment node in this case |
| 255 | + expect(viewRef.rootNodes.length).toBe(ivyEnabled ? 0 : 1); |
| 256 | + }); |
| 257 | + |
| 258 | + it('should return an empty collection when projectable nodes were provided but there are no slots', |
| 259 | + () => { |
| 260 | + TestBed.overrideTemplate(DynamicCmp, `<ng-template #templateRef></ng-template>`); |
| 261 | + |
| 262 | + const fixture = TestBed.createComponent(TestCmp); |
| 263 | + const dynamicCmptFactory = |
| 264 | + fixture.componentInstance.cfr.resolveComponentFactory(DynamicCmp); |
| 265 | + |
| 266 | + // There are no slots but projectable were provided - nothing should be returned |
| 267 | + const projectableNodes = [[document.createTextNode('textNode')]]; |
| 268 | + const cmptRef = dynamicCmptFactory.create(Injector.NULL, projectableNodes); |
| 269 | + const viewRef = cmptRef.instance.templateRef.createEmbeddedView({}); |
| 270 | + |
| 271 | + // VE will, incorrectly, return an additional comment node in this case |
| 272 | + expect(viewRef.rootNodes.length).toBe(ivyEnabled ? 0 : 1); |
| 273 | + }); |
| 274 | + }); |
183 | 275 | });
|
184 | 276 | });
|
0 commit comments