fix(ivy): properly destroy views created by ComponentFactory (#27676)

PR Close #27676
This commit is contained in:
Pawel Kozlowski
2018-12-14 15:11:14 +01:00
committed by Miško Hevery
parent f1c9d6a81f
commit b00aeeff37
5 changed files with 83 additions and 89 deletions

View File

@ -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]}});

View File

@ -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')

View File

@ -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">