@@ -10,9 +10,9 @@ import {animate, AnimationBuilder, state, style, transition, trigger} from '@ang
1010import { DOCUMENT , isPlatformServer , PlatformLocation , ɵgetDOM as getDOM } from '@angular/common' ;
1111import { HTTP_INTERCEPTORS , HttpClient , HttpClientModule , HttpEvent , HttpHandler , HttpInterceptor , HttpRequest } from '@angular/common/http' ;
1212import { HttpClientTestingModule , HttpTestingController } from '@angular/common/http/testing' ;
13- import { ApplicationRef , CompilerFactory , Component , destroyPlatform , getPlatform , HostListener , Inject , Injectable , Input , NgModule , NgZone , PLATFORM_ID , PlatformRef , ViewEncapsulation } from '@angular/core' ;
13+ import { ApplicationRef , CompilerFactory , Component , destroyPlatform , getPlatform , HostListener , Inject , inject as coreInject , Injectable , Input , NgModule , NgZone , PLATFORM_ID , PlatformRef , ViewEncapsulation } from '@angular/core' ;
1414import { inject , TestBed , waitForAsync } from '@angular/core/testing' ;
15- import { BrowserModule , Title } from '@angular/platform-browser' ;
15+ import { BrowserModule , makeStateKey , Title , TransferState } from '@angular/platform-browser' ;
1616import { BEFORE_APP_SERIALIZED , INITIAL_CONFIG , platformDynamicServer , PlatformState , renderModule , renderModuleFactory , ServerModule } from '@angular/platform-server' ;
1717import { Observable } from 'rxjs' ;
1818import { first } from 'rxjs/operators' ;
@@ -298,6 +298,33 @@ const MyStylesAppStandalone = createMyStylesApp(true);
298298class ExampleStylesModule {
299299}
300300
301+ function createMyTransferStateApp ( standalone : boolean ) {
302+ @Component ( {
303+ standalone,
304+ selector : 'app' ,
305+ template : `<div>Works!</div>` ,
306+ } )
307+ class MyStylesApp {
308+ state = coreInject ( TransferState ) ;
309+ constructor ( ) {
310+ this . state . set ( makeStateKey < string > ( 'some-key' ) , 'some-value' ) ;
311+ }
312+ }
313+ return MyStylesApp ;
314+ }
315+
316+ const MyTransferStateApp = createMyTransferStateApp ( false ) ;
317+ const MyTransferStateAppStandalone = createMyTransferStateApp ( true ) ;
318+
319+
320+ @NgModule ( {
321+ declarations : [ MyTransferStateApp ] ,
322+ imports : [ BrowserModule . withServerTransition ( { appId : 'transfer-state-app' } ) , ServerModule ] ,
323+ bootstrap : [ MyTransferStateApp ]
324+ } )
325+ class MyTransferStateModule {
326+ }
327+
301328@NgModule ( {
302329 bootstrap : [ MyServerApp ] ,
303330 imports : [ MyServerAppModule , ServerModule , HttpClientModule , HttpClientTestingModule ] ,
@@ -828,6 +855,23 @@ describe('platform-server integration', () => {
828855 } ) ;
829856 } ) ) ;
830857
858+ it ( `using ${ isStandalone ? 'renderApplication' : 'renderModule' } ` +
859+ `should serialize transfer state only once` ,
860+ waitForAsync ( ( ) => {
861+ const options = { document : doc } ;
862+ const bootstrap = isStandalone ?
863+ renderApplication (
864+ MyTransferStateAppStandalone , { ...options , appId : 'transfer-state-app' } ) :
865+ renderModule ( MyTransferStateModule , { ...options } ) ;
866+ bootstrap . then ( output => {
867+ const expectedOutput =
868+ '<html><head></head><body><app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other"><div>Works!</div></app>' +
869+ '<script id="transfer-state-app-state" type="application/json">{&q;some-key&q;:&q;some-value&q;}</script></body></html>' ;
870+ expect ( output ) . toEqual ( expectedOutput ) ;
871+ called = true ;
872+ } ) ;
873+ } ) ) ;
874+
831875 it ( 'uses `other` as the `serverContext` value when all symbols are removed after sanitization' ,
832876 waitForAsync ( ( ) => {
833877 const options = {
0 commit comments