@@ -467,6 +467,65 @@ describe('platform-server hydration integration', () => {
467467 verifyClientAndSSRContentsMatch ( ssrContents , clientRootNode ) ;
468468 } ) ;
469469
470+ it ( 'should hydrate root components with empty templates' , async ( ) => {
471+ @Component ( {
472+ standalone : true ,
473+ selector : 'app' ,
474+ template : '' ,
475+ } )
476+ class SimpleComponent {
477+ }
478+
479+ const html = await ssr ( SimpleComponent ) ;
480+ const ssrContents = getAppContents ( html ) ;
481+
482+ expect ( ssrContents ) . toContain ( `<app ${ NGH_ATTR_NAME } ` ) ;
483+
484+ resetTViewsFor ( SimpleComponent ) ;
485+
486+ const appRef = await hydrate ( html , SimpleComponent ) ;
487+ const compRef = getComponentRef < SimpleComponent > ( appRef ) ;
488+ appRef . tick ( ) ;
489+
490+ const clientRootNode = compRef . location . nativeElement ;
491+ verifyAllNodesClaimedForHydration ( clientRootNode ) ;
492+ verifyClientAndSSRContentsMatch ( ssrContents , clientRootNode ) ;
493+ } ) ;
494+
495+ it ( 'should hydrate child components with empty templates' , async ( ) => {
496+ @Component ( {
497+ standalone : true ,
498+ selector : 'child' ,
499+ template : '' ,
500+ } )
501+ class ChildComponent {
502+ }
503+
504+ @Component ( {
505+ standalone : true ,
506+ imports : [ ChildComponent ] ,
507+ selector : 'app' ,
508+ template : '<child />' ,
509+ } )
510+ class SimpleComponent {
511+ }
512+
513+ const html = await ssr ( SimpleComponent ) ;
514+ const ssrContents = getAppContents ( html ) ;
515+
516+ expect ( ssrContents ) . toContain ( `<app ${ NGH_ATTR_NAME } ` ) ;
517+
518+ resetTViewsFor ( SimpleComponent , ChildComponent ) ;
519+
520+ const appRef = await hydrate ( html , SimpleComponent ) ;
521+ const compRef = getComponentRef < SimpleComponent > ( appRef ) ;
522+ appRef . tick ( ) ;
523+
524+ const clientRootNode = compRef . location . nativeElement ;
525+ verifyAllNodesClaimedForHydration ( clientRootNode ) ;
526+ verifyClientAndSSRContentsMatch ( ssrContents , clientRootNode ) ;
527+ } ) ;
528+
470529 it ( 'should support a single text interpolation' , async ( ) => {
471530 @Component ( {
472531 standalone : true ,
@@ -6469,6 +6528,54 @@ describe('platform-server hydration integration', () => {
64696528 [ 4 , 5 ] . map ( id => compRef . location . nativeElement . querySelector ( `[id=${ id } ]` ) ) ;
64706529 verifyAllNodesClaimedForHydration ( clientRootNode , Array . from ( clientRenderedItems ) ) ;
64716530 } ) ;
6531+
6532+ it ( 'should handle a reconciliation with swaps' , async ( ) => {
6533+ @Component ( {
6534+ selector : 'app' ,
6535+ standalone : true ,
6536+ template : `
6537+ @for(item of items; track item) {
6538+ <div>{{ item }}</div>
6539+ }
6540+ ` ,
6541+ } )
6542+ class SimpleComponent {
6543+ items = [ 'a' , 'b' , 'c' ] ;
6544+
6545+ swap ( ) {
6546+ // Reshuffling of the array will result in
6547+ // "swap" operations in repeater.
6548+ this . items = [ 'b' , 'c' , 'a' ] ;
6549+ }
6550+ }
6551+
6552+ const html = await ssr ( SimpleComponent ) ;
6553+ const ssrContents = getAppContents ( html ) ;
6554+
6555+ expect ( ssrContents ) . toContain ( `<app ${ NGH_ATTR_NAME } ` ) ;
6556+
6557+ resetTViewsFor ( SimpleComponent ) ;
6558+
6559+ expect ( ssrContents ) . toContain ( 'a' ) ;
6560+ expect ( ssrContents ) . toContain ( 'b' ) ;
6561+ expect ( ssrContents ) . toContain ( 'c' ) ;
6562+
6563+ const appRef = await hydrate ( html , SimpleComponent ) ;
6564+ const compRef = getComponentRef < SimpleComponent > ( appRef ) ;
6565+ appRef . tick ( ) ;
6566+
6567+ await whenStable ( appRef ) ;
6568+
6569+ const root : HTMLElement = compRef . location . nativeElement ;
6570+ const divs = root . querySelectorAll ( 'div' ) ;
6571+ expect ( divs . length ) . toBe ( 3 ) ;
6572+
6573+ compRef . instance . swap ( ) ;
6574+ compRef . changeDetectorRef . detectChanges ( ) ;
6575+
6576+ const divsAfterSwap = root . querySelectorAll ( 'div' ) ;
6577+ expect ( divsAfterSwap . length ) . toBe ( 3 ) ;
6578+ } ) ;
64726579 } ) ;
64736580
64746581 describe ( 'Router' , ( ) => {
0 commit comments