1- import { inject , ComponentFixture , TestBed , async } from '@angular/core/testing' ;
1+ import { inject , ComponentFixture , TestBed } from '@angular/core/testing' ;
22import {
33 NgModule ,
44 Component ,
@@ -20,13 +20,11 @@ import {DomPortalOutlet} from './dom-portal-outlet';
2020
2121describe ( 'Portals' , ( ) => {
2222
23- beforeEach ( async ( ( ) => {
24- TestBed . configureTestingModule ( {
25- imports : [ PortalModule , PortalTestModule ] ,
26- } ) ;
27-
28- TestBed . compileComponents ( ) ;
29- } ) ) ;
23+ beforeEach ( ( ) => {
24+ TestBed
25+ . configureTestingModule ( { imports : [ PortalModule , PortalTestModule ] } )
26+ . compileComponents ( ) ;
27+ } ) ;
3028
3129 describe ( 'CdkPortalOutlet' , ( ) => {
3230 let fixture : ComponentFixture < PortalTestApp > ;
@@ -37,28 +35,33 @@ describe('Portals', () => {
3735
3836 it ( 'should load a component into the portal' , ( ) => {
3937 // Set the selectedHost to be a ComponentPortal.
40- let testAppComponent = fixture . debugElement . componentInstance ;
41- testAppComponent . selectedPortal = new ComponentPortal ( PizzaMsg ) ;
38+ let testAppComponent = fixture . componentInstance ;
39+ let componentPortal = new ComponentPortal ( PizzaMsg ) ;
40+ let hostContainer = fixture . nativeElement . querySelector ( '.portal-container' ) ;
41+
42+ testAppComponent . selectedPortal = componentPortal ;
4243 fixture . detectChanges ( ) ;
4344
4445 // Expect that the content of the attached portal is present.
45- let hostContainer = fixture . nativeElement . querySelector ( '.portal-container' ) ;
4646 expect ( hostContainer . textContent ) . toContain ( 'Pizza' ) ;
47+ expect ( testAppComponent . portalOutlet . portal ) . toBe ( componentPortal ) ;
4748 } ) ;
4849
4950 it ( 'should load a template into the portal' , ( ) => {
50- let testAppComponent = fixture . debugElement . componentInstance ;
51+ let testAppComponent = fixture . componentInstance ;
5152 let hostContainer = fixture . nativeElement . querySelector ( '.portal-container' ) ;
52-
5353 let templatePortal = new TemplatePortal ( testAppComponent . templateRef , null ! ) ;
54+
5455 testAppComponent . selectedPortal = templatePortal ;
5556 fixture . detectChanges ( ) ;
57+
5658 // Expect that the content of the attached portal is present and no context is projected
5759 expect ( hostContainer . textContent ) . toContain ( 'Banana' ) ;
60+ expect ( testAppComponent . portalOutlet . portal ) . toBe ( templatePortal ) ;
5861 } ) ;
5962
6063 it ( 'should project template context bindings in the portal' , ( ) => {
61- let testAppComponent = fixture . debugElement . componentInstance ;
64+ let testAppComponent = fixture . componentInstance ;
6265 let hostContainer = fixture . nativeElement . querySelector ( '.portal-container' ) ;
6366
6467 // TemplatePortal without context:
@@ -99,7 +102,7 @@ describe('Portals', () => {
99102
100103 it ( 'should dispose the host when destroyed' , ( ) => {
101104 // Set the selectedHost to be a ComponentPortal.
102- let testAppComponent = fixture . debugElement . componentInstance ;
105+ let testAppComponent = fixture . componentInstance ;
103106 testAppComponent . selectedPortal = new ComponentPortal ( PizzaMsg ) ;
104107
105108 fixture . detectChanges ( ) ;
@@ -114,7 +117,7 @@ describe('Portals', () => {
114117 let chocolateInjector = new ChocolateInjector ( fixture . componentInstance . injector ) ;
115118
116119 // Set the selectedHost to be a ComponentPortal.
117- let testAppComponent = fixture . debugElement . componentInstance ;
120+ let testAppComponent = fixture . componentInstance ;
118121 testAppComponent . selectedPortal = new ComponentPortal ( PizzaMsg , undefined , chocolateInjector ) ;
119122 fixture . detectChanges ( ) ;
120123
@@ -125,7 +128,7 @@ describe('Portals', () => {
125128 } ) ;
126129
127130 it ( 'should load a <ng-template> portal' , ( ) => {
128- let testAppComponent = fixture . debugElement . componentInstance ;
131+ let testAppComponent = fixture . componentInstance ;
129132
130133 // Detect changes initially so that the component's ViewChildren are resolved.
131134 fixture . detectChanges ( ) ;
@@ -140,7 +143,7 @@ describe('Portals', () => {
140143 } ) ;
141144
142145 it ( 'should load a <ng-template> portal with the `*` sugar' , ( ) => {
143- let testAppComponent = fixture . debugElement . componentInstance ;
146+ let testAppComponent = fixture . componentInstance ;
144147
145148 // Detect changes initially so that the component's ViewChildren are resolved.
146149 fixture . detectChanges ( ) ;
@@ -155,7 +158,7 @@ describe('Portals', () => {
155158 } ) ;
156159
157160 it ( 'should load a <ng-template> portal with a binding' , ( ) => {
158- let testAppComponent = fixture . debugElement . componentInstance ;
161+ let testAppComponent = fixture . componentInstance ;
159162
160163 // Detect changes initially so that the component's ViewChildren are resolved.
161164 fixture . detectChanges ( ) ;
@@ -177,7 +180,7 @@ describe('Portals', () => {
177180 } ) ;
178181
179182 it ( 'should load a <ng-template> portal with an inner template' , ( ) => {
180- let testAppComponent = fixture . debugElement . componentInstance ;
183+ let testAppComponent = fixture . componentInstance ;
181184
182185 // Detect changes initially so that the component's ViewChildren are resolved.
183186 fixture . detectChanges ( ) ;
@@ -199,7 +202,7 @@ describe('Portals', () => {
199202 } ) ;
200203
201204 it ( 'should change the attached portal' , ( ) => {
202- let testAppComponent = fixture . debugElement . componentInstance ;
205+ let testAppComponent = fixture . componentInstance ;
203206
204207 // Detect changes initially so that the component's ViewChildren are resolved.
205208 fixture . detectChanges ( ) ;
@@ -219,22 +222,22 @@ describe('Portals', () => {
219222 } ) ;
220223
221224 it ( 'should detach the portal when it is set to null' , ( ) => {
222- let testAppComponent = fixture . debugElement . componentInstance ;
225+ let testAppComponent = fixture . componentInstance ;
223226 testAppComponent . selectedPortal = new ComponentPortal ( PizzaMsg ) ;
224227
225228 fixture . detectChanges ( ) ;
226229 expect ( testAppComponent . portalOutlet . hasAttached ( ) ) . toBe ( true ) ;
227230 expect ( testAppComponent . portalOutlet . portal ) . toBe ( testAppComponent . selectedPortal ) ;
228231
229- testAppComponent . selectedPortal = null ;
232+ testAppComponent . selectedPortal = null ! ;
230233 fixture . detectChanges ( ) ;
231234
232235 expect ( testAppComponent . portalOutlet . hasAttached ( ) ) . toBe ( false ) ;
233236 expect ( testAppComponent . portalOutlet . portal ) . toBeNull ( ) ;
234237 } ) ;
235238
236239 it ( 'should set the `portal` when attaching a component portal programmatically' , ( ) => {
237- let testAppComponent = fixture . debugElement . componentInstance ;
240+ let testAppComponent = fixture . componentInstance ;
238241 let portal = new ComponentPortal ( PizzaMsg ) ;
239242
240243 testAppComponent . portalOutlet . attachComponentPortal ( portal ) ;
@@ -243,7 +246,7 @@ describe('Portals', () => {
243246 } ) ;
244247
245248 it ( 'should set the `portal` when attaching a template portal programmatically' , ( ) => {
246- let testAppComponent = fixture . debugElement . componentInstance ;
249+ let testAppComponent = fixture . componentInstance ;
247250 fixture . detectChanges ( ) ;
248251
249252 testAppComponent . portalOutlet . attachTemplatePortal ( testAppComponent . cakePortal ) ;
@@ -252,7 +255,7 @@ describe('Portals', () => {
252255 } ) ;
253256
254257 it ( 'should clear the portal reference on destroy' , ( ) => {
255- let testAppComponent = fixture . debugElement . componentInstance ;
258+ let testAppComponent = fixture . componentInstance ;
256259
257260 testAppComponent . selectedPortal = new ComponentPortal ( PizzaMsg ) ;
258261 fixture . detectChanges ( ) ;
@@ -263,6 +266,40 @@ describe('Portals', () => {
263266
264267 expect ( testAppComponent . portalOutlet . portal ) . toBeNull ( ) ;
265268 } ) ;
269+
270+ it ( 'should not clear programmatically-attached portals on init' , ( ) => {
271+ fixture . destroy ( ) ;
272+
273+ const unboundFixture = TestBed . createComponent ( UnboundPortalTestApp ) ;
274+
275+ // Note: calling `detectChanges` here will cause a false positive.
276+ // What we're testing is attaching before the first CD cycle.
277+ unboundFixture . componentInstance . portalOutlet . attach ( new ComponentPortal ( PizzaMsg ) ) ;
278+ unboundFixture . detectChanges ( ) ;
279+
280+ expect ( unboundFixture . nativeElement . querySelector ( '.portal-container' ) . textContent )
281+ . toContain ( 'Pizza' ) ;
282+ } ) ;
283+
284+ it ( 'should be considered attached when attaching using `attach`' , ( ) => {
285+ expect ( fixture . componentInstance . portalOutlet . hasAttached ( ) ) . toBe ( false ) ;
286+ fixture . componentInstance . portalOutlet . attach ( new ComponentPortal ( PizzaMsg ) ) ;
287+ expect ( fixture . componentInstance . portalOutlet . hasAttached ( ) ) . toBe ( true ) ;
288+ } ) ;
289+
290+ it ( 'should be considered attached when attaching using `attachComponentPortal`' , ( ) => {
291+ expect ( fixture . componentInstance . portalOutlet . hasAttached ( ) ) . toBe ( false ) ;
292+ fixture . componentInstance . portalOutlet . attachComponentPortal ( new ComponentPortal ( PizzaMsg ) ) ;
293+ expect ( fixture . componentInstance . portalOutlet . hasAttached ( ) ) . toBe ( true ) ;
294+ } ) ;
295+
296+ it ( 'should be considered attached when attaching using `attachTemplatePortal`' , ( ) => {
297+ const instance = fixture . componentInstance ;
298+ expect ( instance . portalOutlet . hasAttached ( ) ) . toBe ( false ) ;
299+ instance . portalOutlet . attachTemplatePortal ( new TemplatePortal ( instance . templateRef , null ! ) ) ;
300+ expect ( instance . portalOutlet . hasAttached ( ) ) . toBe ( true ) ;
301+ } ) ;
302+
266303 } ) ;
267304
268305 describe ( 'DomPortalOutlet' , ( ) => {
@@ -345,7 +382,7 @@ describe('Portals', () => {
345382 it ( 'should attach and detach a template portal with a binding' , ( ) => {
346383 let fixture = TestBed . createComponent ( PortalTestApp ) ;
347384
348- let testAppComponent = fixture . debugElement . componentInstance ;
385+ let testAppComponent = fixture . componentInstance ;
349386
350387 // Detect changes initially so that the component's ViewChildren are resolved.
351388 fixture . detectChanges ( ) ;
@@ -484,7 +521,7 @@ class PortalTestApp {
484521 @ViewChild ( CdkPortalOutlet ) portalOutlet : CdkPortalOutlet ;
485522 @ViewChild ( 'templateRef' , { read : TemplateRef } ) templateRef : TemplateRef < any > ;
486523
487- selectedPortal : Portal < any > ;
524+ selectedPortal : Portal < any > | undefined ;
488525 fruit : string = 'Banana' ;
489526 fruits = [ 'Apple' , 'Pineapple' , 'Durian' ] ;
490527
@@ -508,9 +545,27 @@ class PortalTestApp {
508545
509546}
510547
548+ /** Test-bed component that contains a portal outlet and a couple of template portals. */
549+ @Component ( {
550+ template : `
551+ <div class="portal-container">
552+ <ng-template cdkPortalOutlet></ng-template>
553+ </div>
554+ ` ,
555+ } )
556+ class UnboundPortalTestApp {
557+ @ViewChild ( CdkPortalOutlet ) portalOutlet : CdkPortalOutlet ;
558+ }
559+
511560// Create a real (non-test) NgModule as a workaround for
512561// https://github.com/angular/angular/issues/10760
513- const TEST_COMPONENTS = [ PortalTestApp , ArbitraryViewContainerRefComponent , PizzaMsg ] ;
562+ const TEST_COMPONENTS = [
563+ PortalTestApp ,
564+ UnboundPortalTestApp ,
565+ ArbitraryViewContainerRefComponent ,
566+ PizzaMsg
567+ ] ;
568+
514569@NgModule ( {
515570 imports : [ CommonModule , PortalModule ] ,
516571 exports : TEST_COMPONENTS ,
0 commit comments