@@ -30,6 +30,19 @@ import {
3030} from '../../src/core' ;
3131import { TestBed } from '../../testing' ;
3232import { By } from '@angular/platform-browser' ;
33+ import {
34+ createContainerRef ,
35+ enableLocateOrCreateContainerRefImpl ,
36+ } from '../../src/linker/view_container_ref' ;
37+ import { getLContext } from '../../src/render3/context_discovery' ;
38+ import { DehydratedView } from '../../src/hydration/interfaces' ;
39+ import {
40+ TElementContainerNode ,
41+ TElementNode ,
42+ TContainerNode ,
43+ TNodeType ,
44+ } from '../../src/render3/interfaces/node' ;
45+ import { HYDRATION , TVIEW } from '../../src/render3/interfaces/view' ;
3346
3447describe ( 'query logic' , ( ) => {
3548 beforeEach ( ( ) => {
@@ -1762,6 +1775,48 @@ describe('query logic', () => {
17621775 expect ( qList . first ) . toBeInstanceOf ( ViewContainerRef ) ;
17631776 } ) ;
17641777
1778+ it ( 'should not throw when hydration metadata has no serialized container data' , ( ) => {
1779+ @Component ( {
1780+ template : `<div #foo></div>` ,
1781+ changeDetection : ChangeDetectionStrategy . OnPush ,
1782+ } )
1783+ class TestCmp { }
1784+
1785+ const fixture = TestBed . createComponent ( TestCmp ) ;
1786+ fixture . detectChanges ( ) ;
1787+
1788+ const element = fixture . nativeElement . querySelector ( 'div' ) ! ;
1789+ const context = getLContext ( element ) ! ;
1790+ const hostLView = context . lView ! ;
1791+ const candidateTNode = hostLView [ TVIEW ] . data [ context . nodeIndex ] as unknown ;
1792+
1793+ expect ( candidateTNode ) . toBeDefined ( ) ;
1794+ expect ( ! ! candidateTNode && typeof candidateTNode === 'object' && 'type' in candidateTNode )
1795+ . withContext ( 'Expected a TNode with a type field.' )
1796+ . toBeTrue ( ) ;
1797+
1798+ const hostTNode = candidateTNode as TElementNode | TContainerNode | TElementContainerNode ;
1799+ expect ( ! ! ( hostTNode . type & ( TNodeType . AnyContainer | TNodeType . AnyRNode ) ) )
1800+ . withContext ( 'Expected a host TNode that can create a ViewContainerRef.' )
1801+ . toBeTrue ( ) ;
1802+
1803+ hostLView [ HYDRATION ] = { data : { } , firstChild : null } as DehydratedView ;
1804+ enableLocateOrCreateContainerRefImpl ( ) ;
1805+
1806+ const warnSpy = spyOn ( console , 'warn' ) ;
1807+
1808+ expect ( ( ) => createContainerRef ( hostTNode , hostLView ) ) . not . toThrow ( ) ;
1809+
1810+ const warningMessages = warnSpy . calls
1811+ . allArgs ( )
1812+ . map ( ( [ message ] ) => String ( message ) )
1813+ . join ( '\n' ) ;
1814+
1815+ expect ( warningMessages ) . toContain (
1816+ 'Unexpected state: no hydration info available for a given TNode, which represents a view container.' ,
1817+ ) ;
1818+ } ) ;
1819+
17651820 it ( 'should read ElementRef with a native element pointing to comment DOM node from ng-template' , ( ) => {
17661821 @Component ( {
17671822 template : `<ng-template #foo></ng-template>` ,
0 commit comments