fix(ivy): properly destroy views created by ComponentFactory (#27676)
PR Close #27676
This commit is contained in:

committed by
Miško Hevery

parent
f1c9d6a81f
commit
b00aeeff37
@ -1104,77 +1104,70 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
||||
});
|
||||
|
||||
describe('ngOnDestroy', () => {
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
.it('should be called on view destruction', fakeAsync(() => {
|
||||
const ctx = createCompFixture('<div testDirective="dir"></div>');
|
||||
ctx.detectChanges(false);
|
||||
it('should be called on view destruction', fakeAsync(() => {
|
||||
const ctx = createCompFixture('<div testDirective="dir"></div>');
|
||||
ctx.detectChanges(false);
|
||||
|
||||
ctx.destroy();
|
||||
ctx.destroy();
|
||||
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']);
|
||||
}));
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']);
|
||||
}));
|
||||
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
.it('should be called after processing the content and view children', fakeAsync(() => {
|
||||
TestBed.overrideComponent(AnotherComponent, {
|
||||
set: new Component({
|
||||
selector: 'other-cmp',
|
||||
template: '<div testDirective="viewChild"></div>'
|
||||
})
|
||||
});
|
||||
it('should be called after processing the content and view children', fakeAsync(() => {
|
||||
TestBed.overrideComponent(AnotherComponent, {
|
||||
set: new Component(
|
||||
{selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'})
|
||||
});
|
||||
|
||||
const ctx = createCompFixture(
|
||||
'<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' +
|
||||
'<other-cmp></other-cmp></div>',
|
||||
TestComponent);
|
||||
const ctx = createCompFixture(
|
||||
'<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' +
|
||||
'<other-cmp></other-cmp></div>',
|
||||
TestComponent);
|
||||
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy',
|
||||
'viewChild.ngOnDestroy', 'parent.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy',
|
||||
'parent.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
.it('should be called in reverse order so the child is always notified before the parent',
|
||||
fakeAsync(() => {
|
||||
const ctx = createCompFixture(
|
||||
'<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>');
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
fakeAsync(() => {
|
||||
const ctx = createCompFixture(
|
||||
'<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>');
|
||||
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
.it('should deliver synchronous events to parent', fakeAsync(() => {
|
||||
const ctx =
|
||||
createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>');
|
||||
it('should deliver synchronous events to parent', fakeAsync(() => {
|
||||
const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>');
|
||||
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
|
||||
expect(ctx.componentInstance.a).toEqual('destroyed');
|
||||
}));
|
||||
expect(ctx.componentInstance.a).toEqual('destroyed');
|
||||
}));
|
||||
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
.it('should call ngOnDestroy on pipes', fakeAsync(() => {
|
||||
const ctx = createCompFixture('{{true | pipeWithOnDestroy }}');
|
||||
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
it('should call ngOnDestroy on pipes', fakeAsync(() => {
|
||||
const ctx = createCompFixture('{{true | pipeWithOnDestroy }}');
|
||||
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'pipeWithOnDestroy.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
|
||||
fixmeIvy('FW-763: LView tree not properly constructed / destroyed')
|
||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||
'pipeWithOnDestroy.ngOnDestroy'
|
||||
]);
|
||||
}));
|
||||
|
||||
fixmeIvy('FW-848: ngOnDestroy hooks are not called on providers')
|
||||
.it('should call ngOnDestroy on an injectable class', fakeAsync(() => {
|
||||
TestBed.overrideDirective(
|
||||
TestDirective, {set: {providers: [InjectableWithLifecycle]}});
|
||||
|
@ -768,37 +768,35 @@ function declareTests(config?: {useJit: boolean}) {
|
||||
expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective);
|
||||
});
|
||||
|
||||
fixmeIvy(
|
||||
'FW-763: LView tree not properly constructed / destroyed for dynamically inserted components')
|
||||
.it('should support events via EventEmitter on regular elements', async(() => {
|
||||
TestBed.configureTestingModule(
|
||||
{declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent]});
|
||||
const template = '<div emitter listener></div>';
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
it('should support events via EventEmitter on regular elements', async(() => {
|
||||
TestBed.configureTestingModule(
|
||||
{declarations: [MyComp, DirectiveEmittingEvent, DirectiveListeningEvent]});
|
||||
const template = '<div emitter listener></div>';
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
const tc = fixture.debugElement.children[0];
|
||||
const emitter = tc.injector.get(DirectiveEmittingEvent);
|
||||
const listener = tc.injector.get(DirectiveListeningEvent);
|
||||
const tc = fixture.debugElement.children[0];
|
||||
const emitter = tc.injector.get(DirectiveEmittingEvent);
|
||||
const listener = tc.injector.get(DirectiveListeningEvent);
|
||||
|
||||
expect(listener.msg).toEqual('');
|
||||
let eventCount = 0;
|
||||
expect(listener.msg).toEqual('');
|
||||
let eventCount = 0;
|
||||
|
||||
emitter.event.subscribe({
|
||||
next: () => {
|
||||
eventCount++;
|
||||
if (eventCount === 1) {
|
||||
expect(listener.msg).toEqual('fired !');
|
||||
fixture.destroy();
|
||||
emitter.fireEvent('fired again !');
|
||||
} else {
|
||||
expect(listener.msg).toEqual('fired !');
|
||||
}
|
||||
}
|
||||
});
|
||||
emitter.event.subscribe({
|
||||
next: () => {
|
||||
eventCount++;
|
||||
if (eventCount === 1) {
|
||||
expect(listener.msg).toEqual('fired !');
|
||||
fixture.destroy();
|
||||
emitter.fireEvent('fired again !');
|
||||
} else {
|
||||
expect(listener.msg).toEqual('fired !');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
emitter.fireEvent('fired !');
|
||||
}));
|
||||
emitter.fireEvent('fired !');
|
||||
}));
|
||||
|
||||
fixmeIvy(
|
||||
'FW-665: Discovery util fails with Unable to find the given context data for the given target')
|
||||
|
@ -616,9 +616,8 @@ describe('Query API', () => {
|
||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']);
|
||||
});
|
||||
|
||||
fixmeIvy(
|
||||
'FW-763 - LView tree not properly constructed / destroyed for dynamically inserted components')
|
||||
.it('should remove manually projected templates if their parent view is destroyed', () => {
|
||||
fixmeIvy('unknown').it(
|
||||
'should remove manually projected templates if their parent view is destroyed', () => {
|
||||
const template = `
|
||||
<manual-projecting #q><ng-template #tpl><div text="1"></div></ng-template></manual-projecting>
|
||||
<div *ngIf="shouldShow">
|
||||
|
Reference in New Issue
Block a user