|  | 
| 6 | 6 |  * found in the LICENSE file at https://angular.io/license | 
| 7 | 7 |  */ | 
| 8 | 8 | 
 | 
| 9 |  | -import {COMPILER_OPTIONS, Component, destroyPlatform, NgModule, ViewEncapsulation} from '@angular/core'; | 
|  | 9 | +import {ApplicationRef, COMPILER_OPTIONS, Component, destroyPlatform, NgModule, TestabilityRegistry, ViewEncapsulation} from '@angular/core'; | 
|  | 10 | +import {expect} from '@angular/core/testing/src/testing_internal'; | 
| 10 | 11 | import {BrowserModule} from '@angular/platform-browser'; | 
| 11 | 12 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | 
| 12 | 13 | import {onlyInIvy, withBody} from '@angular/private/testing'; | 
| @@ -151,6 +152,81 @@ describe('bootstrap', () => { | 
| 151 | 152 |          ngModuleRef.destroy(); | 
| 152 | 153 |        })); | 
| 153 | 154 | 
 | 
|  | 155 | +    describe('ApplicationRef cleanup', () => { | 
|  | 156 | +      it('should cleanup ApplicationRef when Injector is destroyed', | 
|  | 157 | +         withBody('<my-app></my-app>', async () => { | 
|  | 158 | +           const TestModule = createComponentAndModule(); | 
|  | 159 | + | 
|  | 160 | +           const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); | 
|  | 161 | +           const appRef = ngModuleRef.injector.get(ApplicationRef); | 
|  | 162 | +           const testabilityRegistry = ngModuleRef.injector.get(TestabilityRegistry); | 
|  | 163 | + | 
|  | 164 | +           expect(appRef.components.length).toBe(1); | 
|  | 165 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(1); | 
|  | 166 | + | 
|  | 167 | +           ngModuleRef.destroy();  // also destroys an Injector instance. | 
|  | 168 | + | 
|  | 169 | +           expect(appRef.components.length).toBe(0); | 
|  | 170 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(0); | 
|  | 171 | +         })); | 
|  | 172 | + | 
|  | 173 | +      it('should cleanup ApplicationRef when ComponentRef is destroyed', | 
|  | 174 | +         withBody('<my-app></my-app>', async () => { | 
|  | 175 | +           const TestModule = createComponentAndModule(); | 
|  | 176 | + | 
|  | 177 | +           const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); | 
|  | 178 | +           const appRef = ngModuleRef.injector.get(ApplicationRef); | 
|  | 179 | +           const testabilityRegistry = ngModuleRef.injector.get(TestabilityRegistry); | 
|  | 180 | +           const componentRef = appRef.components[0]; | 
|  | 181 | + | 
|  | 182 | +           expect(appRef.components.length).toBe(1); | 
|  | 183 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(1); | 
|  | 184 | + | 
|  | 185 | +           componentRef.destroy(); | 
|  | 186 | + | 
|  | 187 | +           expect(appRef.components.length).toBe(0); | 
|  | 188 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(0); | 
|  | 189 | +         })); | 
|  | 190 | + | 
|  | 191 | +      it('should not throw in case ComponentRef is destroyed and Injector is destroyed after that', | 
|  | 192 | +         withBody('<my-app></my-app>', async () => { | 
|  | 193 | +           const TestModule = createComponentAndModule(); | 
|  | 194 | + | 
|  | 195 | +           const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); | 
|  | 196 | +           const appRef = ngModuleRef.injector.get(ApplicationRef); | 
|  | 197 | +           const testabilityRegistry = ngModuleRef.injector.get(TestabilityRegistry); | 
|  | 198 | +           const componentRef = appRef.components[0]; | 
|  | 199 | + | 
|  | 200 | +           expect(appRef.components.length).toBe(1); | 
|  | 201 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(1); | 
|  | 202 | + | 
|  | 203 | +           componentRef.destroy(); | 
|  | 204 | +           ngModuleRef.destroy();  // also destroys an Injector instance. | 
|  | 205 | + | 
|  | 206 | +           expect(appRef.components.length).toBe(0); | 
|  | 207 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(0); | 
|  | 208 | +         })); | 
|  | 209 | + | 
|  | 210 | +      it('should not throw in case Injector is destroyed and ComponentRef is destroyed after that', | 
|  | 211 | +         withBody('<my-app></my-app>', async () => { | 
|  | 212 | +           const TestModule = createComponentAndModule(); | 
|  | 213 | + | 
|  | 214 | +           const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); | 
|  | 215 | +           const appRef = ngModuleRef.injector.get(ApplicationRef); | 
|  | 216 | +           const testabilityRegistry = ngModuleRef.injector.get(TestabilityRegistry); | 
|  | 217 | +           const componentRef = appRef.components[0]; | 
|  | 218 | + | 
|  | 219 | +           expect(appRef.components.length).toBe(1); | 
|  | 220 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(1); | 
|  | 221 | + | 
|  | 222 | +           ngModuleRef.destroy();  // also destroys an Injector instance. | 
|  | 223 | +           componentRef.destroy(); | 
|  | 224 | + | 
|  | 225 | +           expect(appRef.components.length).toBe(0); | 
|  | 226 | +           expect(testabilityRegistry.getAllRootElements().length).toBe(0); | 
|  | 227 | +         })); | 
|  | 228 | +    }); | 
|  | 229 | + | 
| 154 | 230 |     onlyInIvy('options cannot be changed in Ivy').describe('changing bootstrap options', () => { | 
| 155 | 231 |       beforeEach(() => { | 
| 156 | 232 |         spyOn(console, 'error'); | 
|  | 
0 commit comments