test(ivy): update root causes for @angular/core TestBed failures (#27419)

PR Close #27419
This commit is contained in:
Pawel Kozlowski 2018-12-03 16:11:51 +01:00 committed by Igor Minar
parent f5f323dae0
commit a1470c94a6
8 changed files with 297 additions and 314 deletions

View File

@ -74,7 +74,7 @@ class SomeComponent {
return MyModule; return MyModule;
} }
fixmeIvy('unknown') && fixmeIvy('FW-776: Cannot bootstrap as there are still asynchronous initializers running') &&
it('should bootstrap a component from a child module', it('should bootstrap a component from a child module',
async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => {
@Component({ @Component({
@ -103,7 +103,7 @@ class SomeComponent {
expect(component.injector.get('hello')).toEqual('component'); expect(component.injector.get('hello')).toEqual('component');
}))); })));
fixmeIvy('unknown') && fixmeIvy('FW-776: Cannot bootstrap as there are still asynchronous initializers running') &&
it('should bootstrap a component with a custom selector', it('should bootstrap a component with a custom selector',
async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => {
@Component({ @Component({
@ -176,12 +176,13 @@ class SomeComponent {
}); });
}); });
fixmeIvy('unknown') && it('should be called when a component is bootstrapped', fixmeIvy('FW-776: Cannot bootstrap as there are still asynchronous initializers running') &&
inject([ApplicationRef], (ref: ApplicationRef) => { it('should be called when a component is bootstrapped',
createRootEl(); inject([ApplicationRef], (ref: ApplicationRef) => {
const compRef = ref.bootstrap(SomeComponent); createRootEl();
expect(capturedCompRefs).toEqual([compRef]); const compRef = ref.bootstrap(SomeComponent);
})); expect(capturedCompRefs).toEqual([compRef]);
}));
}); });
describe('bootstrap', () => { describe('bootstrap', () => {

View File

@ -10,46 +10,42 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit,
import {Component, Directive} from '@angular/core/src/metadata'; import {Component, Directive} from '@angular/core/src/metadata';
import {TestBed, inject} from '@angular/core/testing'; import {TestBed, inject} from '@angular/core/testing';
import {Log} from '@angular/core/testing/src/testing_internal'; import {Log} from '@angular/core/testing/src/testing_internal';
import {fixmeIvy} from '@angular/private/testing';
{ describe('directive lifecycle integration spec', () => {
describe('directive lifecycle integration spec', () => { let log: Log;
let log: Log;
beforeEach(() => { beforeEach(() => {
TestBed TestBed
.configureTestingModule({ .configureTestingModule({
declarations: [ declarations: [
LifecycleCmp, LifecycleCmp,
LifecycleDir, LifecycleDir,
MyComp5, MyComp5,
], ],
providers: [Log] providers: [Log]
}) })
.overrideComponent(MyComp5, {set: {template: '<div [field]="123" lifecycle></div>'}}); .overrideComponent(MyComp5, {set: {template: '<div [field]="123" lifecycle></div>'}});
});
beforeEach(inject([Log], (_log: any) => { log = _log; }));
fixmeIvy('unknown') &&
it('should invoke lifecycle methods ngOnChanges > ngOnInit > ngDoCheck > ngAfterContentChecked',
() => {
const fixture = TestBed.createComponent(MyComp5);
fixture.detectChanges();
expect(log.result())
.toEqual(
'ngOnChanges; ngOnInit; ngDoCheck; ngAfterContentInit; ngAfterContentChecked; child_ngDoCheck; ' +
'ngAfterViewInit; ngAfterViewChecked');
log.clear();
fixture.detectChanges();
expect(log.result())
.toEqual('ngDoCheck; ngAfterContentChecked; child_ngDoCheck; ngAfterViewChecked');
});
}); });
}
beforeEach(inject([Log], (_log: any) => { log = _log; }));
it('should invoke lifecycle methods ngOnChanges > ngOnInit > ngDoCheck > ngAfterContentChecked',
() => {
const fixture = TestBed.createComponent(MyComp5);
fixture.detectChanges();
expect(log.result())
.toEqual(
'ngOnChanges; ngOnInit; ngDoCheck; ngAfterContentInit; ngAfterContentChecked; child_ngDoCheck; ' +
'ngAfterViewInit; ngAfterViewChecked');
log.clear();
fixture.detectChanges();
expect(log.result())
.toEqual('ngDoCheck; ngAfterContentChecked; child_ngDoCheck; ngAfterViewChecked');
});
});
@Directive({selector: '[lifecycle-dir]'}) @Directive({selector: '[lifecycle-dir]'})

View File

@ -12,20 +12,18 @@ import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy} from '@angular/private/testing'; import {fixmeIvy} from '@angular/private/testing';
{ describe('forwardRef integration', function() {
describe('forwardRef integration', function() { beforeEach(() => { TestBed.configureTestingModule({imports: [Module], declarations: [App]}); });
beforeEach(() => { TestBed.configureTestingModule({imports: [Module], declarations: [App]}); });
fixmeIvy('unknown') && fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') &&
it('should instantiate components which are declared using forwardRef', () => { it('should instantiate components which are declared using forwardRef', () => {
const a = const a =
TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App); TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App);
a.detectChanges(); a.detectChanges();
expect(asNativeElements(a.debugElement.children)).toHaveText('frame(lock)'); expect(asNativeElements(a.debugElement.children)).toHaveText('frame(lock)');
expect(TestBed.get(ModuleFrame)).toBeDefined(); expect(TestBed.get(ModuleFrame)).toBeDefined();
}); });
}); });
}
@NgModule({ @NgModule({
imports: [CommonModule], imports: [CommonModule],

View File

@ -13,13 +13,11 @@ import {TestBed} from '@angular/core/testing';
import {fixmeIvy} from '@angular/private/testing'; import {fixmeIvy} from '@angular/private/testing';
{ if (ivyEnabled) {
if (ivyEnabled) { describe('ivy', () => { declareTests(); });
describe('ivy', () => { declareTests(); }); } else {
} else { describe('jit', () => { declareTests({useJit: true}); });
describe('jit', () => { declareTests({useJit: true}); }); describe('no jit', () => { declareTests({useJit: false}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
} }
class DummyConsole implements Console { class DummyConsole implements Console {

View File

@ -13,13 +13,11 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy, polyfillGoogGetMsg} from '@angular/private/testing'; import {fixmeIvy, polyfillGoogGetMsg} from '@angular/private/testing';
{ if (ivyEnabled) {
if (ivyEnabled) { describe('ivy', () => { declareTests(); });
describe('ivy', () => { declareTests(); }); } else {
} else { describe('jit', () => { declareTests({useJit: true}); });
describe('jit', () => { declareTests({useJit: true}); }); describe('no jit', () => { declareTests({useJit: false}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
} }
function declareTests(config?: {useJit: boolean}) { function declareTests(config?: {useJit: boolean}) {

View File

@ -142,8 +142,8 @@ function declareTests(config?: {useJit: boolean}) {
return new ComponentFixture(comp, null !, false); return new ComponentFixture(comp, null !, false);
} }
fixmeIvy('FW-682: Compiler error handling') && // describe('errors', () => {
describe('errors', () => { fixmeIvy('FW-682: Compiler error handling') &&
it('should error when exporting a directive that was neither declared nor imported', () => { it('should error when exporting a directive that was neither declared nor imported', () => {
@NgModule({exports: [SomeDirective]}) @NgModule({exports: [SomeDirective]})
class SomeModule { class SomeModule {
@ -154,6 +154,7 @@ function declareTests(config?: {useJit: boolean}) {
`Can't export directive ${stringify(SomeDirective)} from ${stringify(SomeModule)} as it was neither declared nor imported!`); `Can't export directive ${stringify(SomeDirective)} from ${stringify(SomeModule)} as it was neither declared nor imported!`);
}); });
fixmeIvy('FW-682: Compiler error handling') &&
it('should error when exporting a pipe that was neither declared nor imported', () => { it('should error when exporting a pipe that was neither declared nor imported', () => {
@NgModule({exports: [SomePipe]}) @NgModule({exports: [SomePipe]})
class SomeModule { class SomeModule {
@ -164,6 +165,7 @@ function declareTests(config?: {useJit: boolean}) {
`Can't export pipe ${stringify(SomePipe)} from ${stringify(SomeModule)} as it was neither declared nor imported!`); `Can't export pipe ${stringify(SomePipe)} from ${stringify(SomeModule)} as it was neither declared nor imported!`);
}); });
fixmeIvy('FW-682: Compiler error handling') &&
it('should error if a directive is declared in more than 1 module', () => { it('should error if a directive is declared in more than 1 module', () => {
@NgModule({declarations: [SomeDirective]}) @NgModule({declarations: [SomeDirective]})
class Module1 { class Module1 {
@ -182,6 +184,7 @@ function declareTests(config?: {useJit: boolean}) {
`You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); `You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
}); });
fixmeIvy('FW-682: Compiler error handling') &&
it('should error if a directive is declared in more than 1 module also if the module declaring it is imported', it('should error if a directive is declared in more than 1 module also if the module declaring it is imported',
() => { () => {
@NgModule({declarations: [SomeDirective], exports: [SomeDirective]}) @NgModule({declarations: [SomeDirective], exports: [SomeDirective]})
@ -199,6 +202,7 @@ function declareTests(config?: {useJit: boolean}) {
`You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); `You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
}); });
fixmeIvy('FW-682: Compiler error handling') &&
it('should error if a pipe is declared in more than 1 module', () => { it('should error if a pipe is declared in more than 1 module', () => {
@NgModule({declarations: [SomePipe]}) @NgModule({declarations: [SomePipe]})
class Module1 { class Module1 {
@ -217,6 +221,7 @@ function declareTests(config?: {useJit: boolean}) {
`You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); `You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
}); });
fixmeIvy('FW-682: Compiler error handling') &&
it('should error if a pipe is declared in more than 1 module also if the module declaring it is imported', it('should error if a pipe is declared in more than 1 module also if the module declaring it is imported',
() => { () => {
@NgModule({declarations: [SomePipe], exports: [SomePipe]}) @NgModule({declarations: [SomePipe], exports: [SomePipe]})
@ -234,7 +239,7 @@ function declareTests(config?: {useJit: boolean}) {
`You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); `You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`);
}); });
}); });
describe('schemas', () => { describe('schemas', () => {
fixmeIvy('FW-682: Compiler error handling') && fixmeIvy('FW-682: Compiler error handling') &&
@ -1048,7 +1053,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(created).toBe(false); expect(created).toBe(false);
}); });
fixmeIvy('ngOnDestroy not running') && fixmeIvy('FW-739: TestBed: destroy on NgModuleRef is not being called') &&
it('should support ngOnDestroy on any provider', () => { it('should support ngOnDestroy on any provider', () => {
let destroyed = false; let destroyed = false;
@ -1068,7 +1073,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(destroyed).toBe(true); expect(destroyed).toBe(true);
}); });
fixmeIvy('ngOnDestroy not running') && fixmeIvy('FW-739: TestBed: destroy on NgModuleRef is not being called') &&
it('should support ngOnDestroy for lazy providers', () => { it('should support ngOnDestroy for lazy providers', () => {
let created = false; let created = false;
let destroyed = false; let destroyed = false;
@ -1330,7 +1335,7 @@ function declareTests(config?: {useJit: boolean}) {
}); });
describe('tree shakable providers', () => { describe('tree shakable providers', () => {
fixmeIvy('providersByKey is not defined') && fixmeIvy('unknown') &&
it('definition should not persist across NgModuleRef instances', () => { it('definition should not persist across NgModuleRef instances', () => {
@NgModule() @NgModule()
class SomeModule { class SomeModule {

View File

@ -12,19 +12,17 @@ import {BrowserModule, By, DOCUMENT} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy} from '@angular/private/testing'; import {fixmeIvy, modifiedInIvy} from '@angular/private/testing';
{ if (ivyEnabled) {
if (ivyEnabled) { describe('ivy', () => { declareTests(); });
describe('ivy', () => { declareTests(); }); } else {
} else { describe('jit', () => { declareTests({useJit: true}); });
describe('jit', () => { declareTests({useJit: true}); }); describe('no jit', () => { declareTests({useJit: false}); });
describe('no jit', () => { declareTests({useJit: false}); });
}
declareTestsUsingBootstrap();
} }
declareTestsUsingBootstrap();
function declareTests(config?: {useJit: boolean}) { function declareTests(config?: {useJit: boolean}) {
// Place to put reproductions for regressions // Place to put reproductions for regressions
describe('regressions', () => { describe('regressions', () => {
@ -162,14 +160,13 @@ function declareTests(config?: {useJit: boolean}) {
expect(injector.get(token)).toEqual(tokenValue); expect(injector.get(token)).toEqual(tokenValue);
}); });
fixmeIvy('FW-646: Directive providers don\'t support primitive types as DI tokens') && it('should support providers with string token with a `.` in it', () => {
it('should support providers with string token with a `.` in it', () => { const token = 'a.b';
const token = 'a.b'; const tokenValue = 1;
const tokenValue = 1; const injector = createInjector([{provide: token, useValue: tokenValue}]);
const injector = createInjector([{provide: token, useValue: tokenValue}]);
expect(injector.get(token)).toEqual(tokenValue); expect(injector.get(token)).toEqual(tokenValue);
}); });
it('should support providers with an anonymous function as token', () => { it('should support providers with an anonymous function as token', () => {
const token = () => true; const token = () => true;
@ -191,15 +188,14 @@ function declareTests(config?: {useJit: boolean}) {
expect(injector.get(token2)).toEqual(tokenValue2); expect(injector.get(token2)).toEqual(tokenValue2);
}); });
fixmeIvy('FW-646: Directive providers don\'t support primitive types as DI tokens') && it('should support providers that have a `name` property with a number value', () => {
it('should support providers that have a `name` property with a number value', () => { class TestClass {
class TestClass { constructor(public name: number) {}
constructor(public name: number) {} }
} const data = [new TestClass(1), new TestClass(2)];
const data = [new TestClass(1), new TestClass(2)]; const injector = createInjector([{provide: 'someToken', useValue: data}]);
const injector = createInjector([{provide: 'someToken', useValue: data}]); expect(injector.get('someToken')).toEqual(data);
expect(injector.get('someToken')).toEqual(data); });
});
describe('ANALYZE_FOR_ENTRY_COMPONENTS providers', () => { describe('ANALYZE_FOR_ENTRY_COMPONENTS providers', () => {
@ -337,21 +333,22 @@ function declareTests(config?: {useJit: boolean}) {
expect(fixture.debugElement.childNodes.length).toBe(0); expect(fixture.debugElement.childNodes.length).toBe(0);
}); });
fixmeIvy('unknown') && it('should allow empty embedded templates', () => { modifiedInIvy('Comment node order changed') &&
@Component({template: '<ng-template [ngIf]="true"></ng-template>'}) it('should allow empty embedded templates', () => {
class MyComp { @Component({template: '<ng-template [ngIf]="true"></ng-template>'})
} class MyComp {
}
const fixture = const fixture =
TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
// Note: We always need to create at least a comment in an embedded template, // Note: We always need to create at least a comment in an embedded template,
// so we can append other templates after it. // so we can append other templates after it.
// 1 comment for the anchor, // 1 comment for the anchor,
// 1 comment for the empty embedded template. // 1 comment for the empty embedded template.
expect(fixture.debugElement.childNodes.length).toBe(2); expect(fixture.debugElement.childNodes.length).toBe(2);
}); });
}); });
fixmeIvy('unknown') && fixmeIvy('unknown') &&

View File

@ -1608,216 +1608,206 @@ describe('ViewContainerRef', () => {
}); });
} }
fixmeIvy(`Hooks don't run`) && it('should call all hooks in correct order when creating with createEmbeddedView', () => {
it('should call all hooks in correct order when creating with createEmbeddedView', () => { function SomeComponent_Template_0(rf: RenderFlags, ctx: any) {
function SomeComponent_Template_0(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) {
if (rf & RenderFlags.Create) { element(0, 'hooks');
element(0, 'hooks'); }
} if (rf & RenderFlags.Update) {
if (rf & RenderFlags.Update) { elementProperty(0, 'name', bind('C'));
elementProperty(0, 'name', bind('C')); }
} }
}
@Component({ @Component({
template: ` template: `
<ng-template #foo> <ng-template #foo>
<hooks [name]="'C'"></hooks> <hooks [name]="'C'"></hooks>
</ng-template> </ng-template>
<hooks vcref [tplRef]="foo" [name]="'A'"></hooks> <hooks vcref [tplRef]="foo" [name]="'A'"></hooks>
<hooks [name]="'B'"></hooks> <hooks [name]="'B'"></hooks>
` `
}) })
class SomeComponent { class SomeComponent {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponent, type: SomeComponent,
selectors: [['some-comp']], selectors: [['some-comp']],
factory: () => new SomeComponent(), factory: () => new SomeComponent(),
consts: 4, consts: 4,
vars: 3, vars: 3,
template: (rf: RenderFlags, cmp: SomeComponent) => { template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
template( template(
0, SomeComponent_Template_0, 1, 1, null, [], ['foo', ''], 0, SomeComponent_Template_0, 1, 1, null, [], ['foo', ''], templateRefExtractor);
templateRefExtractor); element(2, 'hooks', ['vcref', '']);
element(2, 'hooks', ['vcref', '']); element(3, 'hooks');
element(3, 'hooks'); }
} if (rf & RenderFlags.Update) {
if (rf & RenderFlags.Update) { const tplRef = reference(1);
const tplRef = reference(1); elementProperty(2, 'tplRef', bind(tplRef));
elementProperty(2, 'tplRef', bind(tplRef)); elementProperty(2, 'name', bind('A'));
elementProperty(2, 'name', bind('A')); elementProperty(3, 'name', bind('B'));
elementProperty(3, 'name', bind('B')); }
} },
}, directives: [ComponentWithHooks, DirectiveWithVCRef]
directives: [ComponentWithHooks, DirectiveWithVCRef]
});
}
log.length = 0;
const fixture = new ComponentFixture(SomeComponent);
expect(log).toEqual([
'onChanges-A', 'onInit-A', 'doCheck-A', 'onChanges-B', 'onInit-B', 'doCheck-B',
'afterContentInit-A', 'afterContentChecked-A', 'afterContentInit-B',
'afterContentChecked-B', 'afterViewInit-A', 'afterViewChecked-A', 'afterViewInit-B',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.createEmbeddedView(
directiveInstance !.tplRef, fixture.component);
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks></hooks><hooks>B</hooks>');
expect(log).toEqual([]);
log.length = 0;
fixture.update();
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks>C</hooks><hooks>B</hooks>');
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'onChanges-C', 'onInit-C', 'doCheck-C', 'afterContentInit-C',
'afterContentChecked-C', 'afterViewInit-C', 'afterViewChecked-C',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-C', 'afterContentChecked-C', 'afterViewChecked-C',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
const viewRef = directiveInstance !.vcref.detach(0);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.insert(viewRef !);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-C', 'afterContentChecked-C', 'afterViewChecked-C',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.remove(0);
fixture.update();
expect(log).toEqual([
'onDestroy-C', 'doCheck-A', 'doCheck-B', 'afterContentChecked-A',
'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
}); });
}
fixmeIvy(`Hooks don't run`) && log.length = 0;
it('should call all hooks in correct order when creating with createComponent', () => {
@Component({ const fixture = new ComponentFixture(SomeComponent);
template: ` expect(log).toEqual([
'onChanges-A', 'onInit-A', 'doCheck-A', 'onChanges-B', 'onInit-B', 'doCheck-B',
'afterContentInit-A', 'afterContentChecked-A', 'afterContentInit-B',
'afterContentChecked-B', 'afterViewInit-A', 'afterViewChecked-A', 'afterViewInit-B',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.createEmbeddedView(directiveInstance !.tplRef, fixture.component);
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks></hooks><hooks>B</hooks>');
expect(log).toEqual([]);
log.length = 0;
fixture.update();
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks>C</hooks><hooks>B</hooks>');
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'onChanges-C', 'onInit-C', 'doCheck-C', 'afterContentInit-C',
'afterContentChecked-C', 'afterViewInit-C', 'afterViewChecked-C', 'afterContentChecked-A',
'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-C', 'afterContentChecked-C', 'afterViewChecked-C',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
const viewRef = directiveInstance !.vcref.detach(0);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.insert(viewRef !);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-C', 'afterContentChecked-C', 'afterViewChecked-C',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.remove(0);
fixture.update();
expect(log).toEqual([
'onDestroy-C', 'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
});
it('should call all hooks in correct order when creating with createComponent', () => {
@Component({
template: `
<hooks vcref [name]="'A'"></hooks> <hooks vcref [name]="'A'"></hooks>
<hooks [name]="'B'"></hooks> <hooks [name]="'B'"></hooks>
` `
}) })
class SomeComponent { class SomeComponent {
static ngComponentDef = defineComponent({ static ngComponentDef = defineComponent({
type: SomeComponent, type: SomeComponent,
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
selectors: [['some-comp']], selectors: [['some-comp']],
factory: () => new SomeComponent(), factory: () => new SomeComponent(),
consts: 2, consts: 2,
vars: 2, vars: 2,
template: (rf: RenderFlags, cmp: SomeComponent) => { template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) { if (rf & RenderFlags.Create) {
element(0, 'hooks', ['vcref', '']); element(0, 'hooks', ['vcref', '']);
element(1, 'hooks'); element(1, 'hooks');
} }
if (rf & RenderFlags.Update) { if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind('A')); elementProperty(0, 'name', bind('A'));
elementProperty(1, 'name', bind('B')); elementProperty(1, 'name', bind('B'));
} }
}, },
directives: [ComponentWithHooks, DirectiveWithVCRef] directives: [ComponentWithHooks, DirectiveWithVCRef]
});
}
log.length = 0;
const fixture = new ComponentFixture(SomeComponent);
expect(log).toEqual([
'onChanges-A', 'onInit-A', 'doCheck-A', 'onChanges-B', 'onInit-B', 'doCheck-B',
'afterContentInit-A', 'afterContentChecked-A', 'afterContentInit-B',
'afterContentChecked-B', 'afterViewInit-A', 'afterViewChecked-A', 'afterViewInit-B',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
const componentRef = directiveInstance !.vcref.createComponent(
directiveInstance !.cfr.resolveComponentFactory(ComponentWithHooks));
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks></hooks><hooks>B</hooks>');
expect(log).toEqual([]);
componentRef.instance.name = 'D';
log.length = 0;
fixture.update();
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks>D</hooks><hooks>B</hooks>');
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'onChanges-D', 'onInit-D', 'doCheck-D', 'afterContentInit-D',
'afterContentChecked-D', 'afterViewInit-D', 'afterViewChecked-D',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-D', 'afterContentChecked-D', 'afterViewChecked-D',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
const viewRef = directiveInstance !.vcref.detach(0);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.insert(viewRef !);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-D', 'afterContentChecked-D', 'afterViewChecked-D',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A',
'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.remove(0);
fixture.update();
expect(log).toEqual([
'onDestroy-D', 'doCheck-A', 'doCheck-B', 'afterContentChecked-A',
'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
}); });
}
log.length = 0;
const fixture = new ComponentFixture(SomeComponent);
expect(log).toEqual([
'onChanges-A', 'onInit-A', 'doCheck-A', 'onChanges-B', 'onInit-B', 'doCheck-B',
'afterContentInit-A', 'afterContentChecked-A', 'afterContentInit-B',
'afterContentChecked-B', 'afterViewInit-A', 'afterViewChecked-A', 'afterViewInit-B',
'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
const componentRef = directiveInstance !.vcref.createComponent(
directiveInstance !.cfr.resolveComponentFactory(ComponentWithHooks));
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks></hooks><hooks>B</hooks>');
expect(log).toEqual([]);
componentRef.instance.name = 'D';
log.length = 0;
fixture.update();
expect(fixture.html).toEqual('<hooks vcref="">A</hooks><hooks>D</hooks><hooks>B</hooks>');
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'onChanges-D', 'onInit-D', 'doCheck-D', 'afterContentInit-D',
'afterContentChecked-D', 'afterViewInit-D', 'afterViewChecked-D', 'afterContentChecked-A',
'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-D', 'afterContentChecked-D', 'afterViewChecked-D',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
const viewRef = directiveInstance !.vcref.detach(0);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.insert(viewRef !);
fixture.update();
expect(log).toEqual([
'doCheck-A', 'doCheck-B', 'doCheck-D', 'afterContentChecked-D', 'afterViewChecked-D',
'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B'
]);
log.length = 0;
directiveInstance !.vcref.remove(0);
fixture.update();
expect(log).toEqual([
'onDestroy-D', 'doCheck-A', 'doCheck-B', 'afterContentChecked-A', 'afterContentChecked-B',
'afterViewChecked-A', 'afterViewChecked-B'
]);
});
}); });
describe('host bindings', () => { describe('host bindings', () => {