@@ -42,6 +42,9 @@ import {
4242 ViewEncapsulation ,
4343 ɵPendingTasks as PendingTasks ,
4444 ɵwhenStable as whenStable ,
45+ APP_INITIALIZER ,
46+ inject ,
47+ getPlatform ,
4548} from '@angular/core' ;
4649import { SSR_CONTENT_INTEGRITY_MARKER } from '@angular/core/src/hydration/utils' ;
4750import { TestBed } from '@angular/core/testing' ;
@@ -1076,6 +1079,153 @@ class HiddenModule {}
10761079 ) ;
10771080 } ,
10781081 ) ;
1082+
1083+ it (
1084+ `should call onOnDestroy of a service after a successful render` +
1085+ `(standalone: ${ isStandalone } )` ,
1086+ async ( ) => {
1087+ let wasServiceNgOnDestroyCalled = false ;
1088+
1089+ @Injectable ( { providedIn : 'root' } )
1090+ class DestroyableService {
1091+ ngOnDestroy ( ) {
1092+ wasServiceNgOnDestroyCalled = true ;
1093+ }
1094+ }
1095+
1096+ const SuccessfulAppInitializerProviders = [
1097+ {
1098+ provide : APP_INITIALIZER ,
1099+ useFactory : ( ) => {
1100+ inject ( DestroyableService ) ;
1101+ return ( ) => Promise . resolve ( ) ; // Success in APP_INITIALIZER
1102+ } ,
1103+ multi : true ,
1104+ } ,
1105+ ] ;
1106+
1107+ @NgModule ( {
1108+ providers : SuccessfulAppInitializerProviders ,
1109+ imports : [ MyServerAppModule , ServerModule ] ,
1110+ bootstrap : [ MyServerApp ] ,
1111+ } )
1112+ class ServerSuccessfulAppInitializerModule { }
1113+
1114+ const ServerSuccessfulAppInitializerAppStandalone = getStandaloneBootstrapFn (
1115+ createMyServerApp ( true ) ,
1116+ SuccessfulAppInitializerProviders ,
1117+ ) ;
1118+
1119+ const options = { document : doc } ;
1120+ const bootstrap = isStandalone
1121+ ? renderApplication ( ServerSuccessfulAppInitializerAppStandalone , options )
1122+ : renderModule ( ServerSuccessfulAppInitializerModule , options ) ;
1123+ await bootstrap ;
1124+
1125+ expect ( getPlatform ( ) ) . withContext ( 'PlatformRef should be destroyed' ) . toBeNull ( ) ;
1126+ expect ( wasServiceNgOnDestroyCalled )
1127+ . withContext ( 'DestroyableService.ngOnDestroy() should be called' )
1128+ . toBeTrue ( ) ;
1129+ } ,
1130+ ) ;
1131+
1132+ it (
1133+ `should call onOnDestroy of a service after some APP_INITIALIZER fails ` +
1134+ `(standalone: ${ isStandalone } )` ,
1135+ async ( ) => {
1136+ let wasServiceNgOnDestroyCalled = false ;
1137+
1138+ @Injectable ( { providedIn : 'root' } )
1139+ class DestroyableService {
1140+ ngOnDestroy ( ) {
1141+ wasServiceNgOnDestroyCalled = true ;
1142+ }
1143+ }
1144+
1145+ const FailingAppInitializerProviders = [
1146+ {
1147+ provide : APP_INITIALIZER ,
1148+ useFactory : ( ) => {
1149+ inject ( DestroyableService ) ;
1150+ return ( ) => Promise . reject ( 'Error in APP_INITIALIZER' ) ;
1151+ } ,
1152+ multi : true ,
1153+ } ,
1154+ ] ;
1155+
1156+ @NgModule ( {
1157+ providers : FailingAppInitializerProviders ,
1158+ imports : [ MyServerAppModule , ServerModule ] ,
1159+ bootstrap : [ MyServerApp ] ,
1160+ } )
1161+ class ServerFailingAppInitializerModule { }
1162+
1163+ const ServerFailingAppInitializerAppStandalone = getStandaloneBootstrapFn (
1164+ createMyServerApp ( true ) ,
1165+ FailingAppInitializerProviders ,
1166+ ) ;
1167+
1168+ const options = { document : doc } ;
1169+ const bootstrap = isStandalone
1170+ ? renderApplication ( ServerFailingAppInitializerAppStandalone , options )
1171+ : renderModule ( ServerFailingAppInitializerModule , options ) ;
1172+ await expectAsync ( bootstrap ) . toBeRejectedWith ( 'Error in APP_INITIALIZER' ) ;
1173+
1174+ expect ( getPlatform ( ) ) . withContext ( 'PlatformRef should be destroyed' ) . toBeNull ( ) ;
1175+ expect ( wasServiceNgOnDestroyCalled )
1176+ . withContext ( 'DestroyableService.ngOnDestroy() should be called' )
1177+ . toBeTrue ( ) ;
1178+ } ,
1179+ ) ;
1180+
1181+ it (
1182+ `should call onOnDestroy of a service after an error happens in a root component's constructor ` +
1183+ `(standalone: ${ isStandalone } )` ,
1184+ async ( ) => {
1185+ let wasServiceNgOnDestroyCalled = false ;
1186+
1187+ @Injectable ( { providedIn : 'root' } )
1188+ class DestroyableService {
1189+ ngOnDestroy ( ) {
1190+ wasServiceNgOnDestroyCalled = true ;
1191+ }
1192+ }
1193+
1194+ @Component ( {
1195+ standalone : isStandalone ,
1196+ selector : 'app' ,
1197+ template : `Works!` ,
1198+ } )
1199+ class MyServerFailingConstructorApp {
1200+ constructor ( ) {
1201+ inject ( DestroyableService ) ;
1202+ throw 'Error in constructor of the root component' ;
1203+ }
1204+ }
1205+
1206+ @NgModule ( {
1207+ declarations : [ MyServerFailingConstructorApp ] ,
1208+ imports : [ MyServerAppModule , ServerModule ] ,
1209+ bootstrap : [ MyServerFailingConstructorApp ] ,
1210+ } )
1211+ class MyServerFailingConstructorAppModule { }
1212+
1213+ const MyServerFailingConstructorAppStandalone = getStandaloneBootstrapFn (
1214+ MyServerFailingConstructorApp ,
1215+ ) ;
1216+ const options = { document : doc } ;
1217+ const bootstrap = isStandalone
1218+ ? renderApplication ( MyServerFailingConstructorAppStandalone , options )
1219+ : renderModule ( MyServerFailingConstructorAppModule , options ) ;
1220+ await expectAsync ( bootstrap ) . toBeRejectedWith (
1221+ 'Error in constructor of the root component' ,
1222+ ) ;
1223+ expect ( getPlatform ( ) ) . withContext ( 'PlatformRef should be destroyed' ) . toBeNull ( ) ;
1224+ expect ( wasServiceNgOnDestroyCalled )
1225+ . withContext ( 'DestroyableService.ngOnDestroy() should be called' )
1226+ . toBeTrue ( ) ;
1227+ } ,
1228+ ) ;
10791229 } ) ;
10801230 } ) ;
10811231
0 commit comments