Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit37bb320

Browse files
AndrewKushnirmhevery
authored andcommitted
test(core): verifyonDestroy callbacks are invoked when ComponentRef is destroyed (#39876)
This commit adds a few tests to verify that the `onDestroy` callbacks are invoked when `ComponentRef` instanceis destroyed and the logic is consistent between ViewEngine and Ivy.PRClose#39876
1 parentad93243 commit37bb320

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

‎packages/core/src/application_ref.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,6 @@ export class ApplicationRef {
779779

780780
/**@internal */
781781
ngOnDestroy(){
782-
// TODO(alxhub): Dispose of the NgZone.
783782
this._views.slice().forEach((view)=>view.destroy());
784783
}
785784

‎packages/core/test/acceptance/bootstrap_spec.ts‎

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

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';
1011
import{BrowserModule}from'@angular/platform-browser';
1112
import{platformBrowserDynamic}from'@angular/platform-browser-dynamic';
1213
import{onlyInIvy,withBody}from'@angular/private/testing';
@@ -151,6 +152,81 @@ describe('bootstrap', () => {
151152
ngModuleRef.destroy();
152153
}));
153154

155+
describe('ApplicationRef cleanup',()=>{
156+
it('should cleanup ApplicationRef when Injector is destroyed',
157+
withBody('<my-app></my-app>',async()=>{
158+
constTestModule=createComponentAndModule();
159+
160+
constngModuleRef=awaitplatformBrowserDynamic().bootstrapModule(TestModule);
161+
constappRef=ngModuleRef.injector.get(ApplicationRef);
162+
consttestabilityRegistry=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+
constTestModule=createComponentAndModule();
176+
177+
constngModuleRef=awaitplatformBrowserDynamic().bootstrapModule(TestModule);
178+
constappRef=ngModuleRef.injector.get(ApplicationRef);
179+
consttestabilityRegistry=ngModuleRef.injector.get(TestabilityRegistry);
180+
constcomponentRef=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+
constTestModule=createComponentAndModule();
194+
195+
constngModuleRef=awaitplatformBrowserDynamic().bootstrapModule(TestModule);
196+
constappRef=ngModuleRef.injector.get(ApplicationRef);
197+
consttestabilityRegistry=ngModuleRef.injector.get(TestabilityRegistry);
198+
constcomponentRef=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+
constTestModule=createComponentAndModule();
213+
214+
constngModuleRef=awaitplatformBrowserDynamic().bootstrapModule(TestModule);
215+
constappRef=ngModuleRef.injector.get(ApplicationRef);
216+
consttestabilityRegistry=ngModuleRef.injector.get(TestabilityRegistry);
217+
constcomponentRef=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+
154230
onlyInIvy('options cannot be changed in Ivy').describe('changing bootstrap options',()=>{
155231
beforeEach(()=>{
156232
spyOn(console,'error');

‎packages/core/test/acceptance/component_spec.ts‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,57 @@ describe('component', () => {
303303
expect(wrapperEls.length).toBe(2);// other elements are preserved
304304
});
305305

306+
it('should invoke `onDestroy` callbacks of dynamically created component',()=>{
307+
letwasOnDestroyCalled=false;
308+
@Component({
309+
selector:'[comp]',
310+
template:'comp content',
311+
})
312+
classDynamicComponent{
313+
}
314+
315+
@NgModule({
316+
declarations:[DynamicComponent],
317+
entryComponents:[DynamicComponent],// needed only for ViewEngine
318+
})
319+
classTestModule{
320+
}
321+
322+
@Component({
323+
selector:'button',
324+
template:'<div id="app-root" #anchor></div>',
325+
})
326+
classApp{
327+
@ViewChild('anchor',{read:ViewContainerRef})anchor!:ViewContainerRef;
328+
329+
constructor(privatecfr:ComponentFactoryResolver,privateinjector:Injector){}
330+
331+
create(){
332+
constfactory=this.cfr.resolveComponentFactory(DynamicComponent);
333+
constcomponentRef=factory.create(this.injector);
334+
componentRef.onDestroy(()=>{
335+
wasOnDestroyCalled=true;
336+
});
337+
this.anchor.insert(componentRef.hostView);
338+
}
339+
340+
clear(){
341+
this.anchor.clear();
342+
}
343+
}
344+
345+
TestBed.configureTestingModule({imports:[TestModule],declarations:[App]});
346+
constfixture=TestBed.createComponent(App);
347+
fixture.detectChanges();
348+
349+
// Add ComponentRef to ViewContainerRef instance.
350+
fixture.componentInstance.create();
351+
// Clear ViewContainerRef to invoke `onDestroy` callbacks on ComponentRef.
352+
fixture.componentInstance.clear();
353+
354+
expect(wasOnDestroyCalled).toBeTrue();
355+
});
356+
306357
describe('invalid host element',()=>{
307358
it('should throw when <ng-container> is used as a host element for a Component',()=>{
308359
@Component({

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp