refactor(ivy): cleanup di tests from render3 (#32165)
The tests were already migrated to acceptance with `ngFor`/`ngIf`, but were leftover in case JS blocks ended up supported in Ivy. PR Close #32165
This commit is contained in:
parent
60f963986f
commit
c8b065524e
|
@ -6,157 +6,33 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, Host, InjectFlags, Injector, Optional, Renderer2, Self, ViewContainerRef} from '@angular/core';
|
import {InjectFlags, Optional, Renderer2, Self} from '@angular/core';
|
||||||
import {createLView, createTView, getOrCreateTNode} from '@angular/core/src/render3/instructions/shared';
|
import {createLView, createTView, getOrCreateTNode} from '@angular/core/src/render3/instructions/shared';
|
||||||
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
||||||
|
|
||||||
import {ɵɵdefineComponent} from '../../src/render3/definition';
|
import {ɵɵdefineComponent} from '../../src/render3/definition';
|
||||||
import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
||||||
import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵreference, ɵɵselect, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate2} from '../../src/render3/index';
|
import {ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵtext} from '../../src/render3/index';
|
||||||
import {TNODE} from '../../src/render3/interfaces/injector';
|
import {TNODE} from '../../src/render3/interfaces/injector';
|
||||||
import {TNodeType} from '../../src/render3/interfaces/node';
|
import {TNodeType} from '../../src/render3/interfaces/node';
|
||||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||||
import {LViewFlags, TVIEW} from '../../src/render3/interfaces/view';
|
import {LViewFlags, TVIEW} from '../../src/render3/interfaces/view';
|
||||||
import {selectView} from '../../src/render3/state';
|
import {selectView} from '../../src/render3/state';
|
||||||
import {ViewRef} from '../../src/render3/view_ref';
|
|
||||||
|
|
||||||
import {getRendererFactory2} from './imported_renderer2';
|
import {getRendererFactory2} from './imported_renderer2';
|
||||||
import {ComponentFixture, createComponent, createDirective, getDirectiveOnNode, renderComponent, toHtml} from './render_util';
|
import {ComponentFixture, createComponent, createDirective} from './render_util';
|
||||||
|
|
||||||
describe('di', () => {
|
describe('di', () => {
|
||||||
describe('directive injection', () => {
|
describe('directive injection', () => {
|
||||||
let log: string[] = [];
|
|
||||||
|
|
||||||
class DirB {
|
class DirB {
|
||||||
value = 'DirB';
|
value = 'DirB';
|
||||||
constructor() { log.push(this.value); }
|
|
||||||
|
|
||||||
static ngFactoryDef = () => new DirB();
|
static ngFactoryDef = () => new DirB();
|
||||||
static ngDirectiveDef =
|
static ngDirectiveDef =
|
||||||
ɵɵdefineDirective({selectors: [['', 'dirB', '']], type: DirB, inputs: {value: 'value'}});
|
ɵɵdefineDirective({selectors: [['', 'dirB', '']], type: DirB, inputs: {value: 'value'}});
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => log = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test needs to be moved to acceptance/di_spec.ts
|
|
||||||
* when Ivy compiler supports inline views.
|
|
||||||
*/
|
|
||||||
it('should inject directives in the correct order in a for loop', () => {
|
|
||||||
class DirA {
|
|
||||||
constructor(dir: DirB) { log.push(`DirA (dep: ${dir.value})`); }
|
|
||||||
|
|
||||||
static ngFactoryDef = () => new DirA(ɵɵdirectiveInject(DirB));
|
|
||||||
static ngDirectiveDef = ɵɵdefineDirective({selectors: [['', 'dirA', '']], type: DirA});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* % for(let i = 0; i < 3; i++) {
|
|
||||||
* <div dirA dirB></div>
|
|
||||||
* % }
|
|
||||||
*/
|
|
||||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵcontainer(0);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(0);
|
|
||||||
{
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
if (ɵɵembeddedViewStart(0, 1, 0)) {
|
|
||||||
ɵɵelement(0, 'div', ['dirA', '', 'dirB', '']);
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
}, 1, 0, [DirA, DirB]);
|
|
||||||
|
|
||||||
new ComponentFixture(App);
|
|
||||||
expect(log).toEqual(
|
|
||||||
['DirB', 'DirA (dep: DirB)', 'DirB', 'DirA (dep: DirB)', 'DirB', 'DirA (dep: DirB)']);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dependencies in parent views', () => {
|
|
||||||
|
|
||||||
class DirA {
|
|
||||||
injector: Injector;
|
|
||||||
constructor(public dirB: DirB, public vcr: ViewContainerRef) {
|
|
||||||
this.injector = vcr.injector;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ngFactoryDef = () => new DirA(
|
|
||||||
ɵɵdirectiveInject(DirB), ɵɵdirectiveInject(ViewContainerRef as any))
|
|
||||||
|
|
||||||
static ngDirectiveDef =
|
|
||||||
ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']], exportAs: ['dirA']});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test needs to be moved to acceptance/di_spec.ts
|
|
||||||
* when Ivy compiler supports inline views.
|
|
||||||
*/
|
|
||||||
it('should find dependencies of directives nested deeply in inline views', () => {
|
|
||||||
/**
|
|
||||||
* <div dirB>
|
|
||||||
* % if (!skipContent) {
|
|
||||||
* % if (!skipContent2) {
|
|
||||||
* <div dirA #dir="dirA"> {{ dir.dirB.value }} </div>
|
|
||||||
* % }
|
|
||||||
* % }
|
|
||||||
* </div>
|
|
||||||
*/
|
|
||||||
const App = createComponent('app', (rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵelementStart(0, 'div', ['dirB', '']);
|
|
||||||
{ ɵɵcontainer(1); }
|
|
||||||
ɵɵelementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(1);
|
|
||||||
{
|
|
||||||
if (!ctx.skipContent) {
|
|
||||||
let rf1 = ɵɵembeddedViewStart(0, 1, 0);
|
|
||||||
{
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
ɵɵcontainer(0);
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(0);
|
|
||||||
{
|
|
||||||
if (!ctx.skipContent2) {
|
|
||||||
let rf2 = ɵɵembeddedViewStart(0, 3, 1);
|
|
||||||
{
|
|
||||||
if (rf2 & RenderFlags.Create) {
|
|
||||||
ɵɵelementStart(0, 'div', ['dirA', ''], ['dir', 'dirA']);
|
|
||||||
{ ɵɵtext(2); }
|
|
||||||
ɵɵelementEnd();
|
|
||||||
}
|
|
||||||
if (rf2 & RenderFlags.Update) {
|
|
||||||
const dir = ɵɵreference(1) as DirA;
|
|
||||||
ɵɵselect(2);
|
|
||||||
ɵɵtextInterpolate(dir.dirB.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
}, 2, 0, [DirA, DirB]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(App);
|
|
||||||
expect(fixture.hostElement.textContent).toEqual(`DirB`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('flags', () => {
|
describe('flags', () => {
|
||||||
|
|
||||||
class DirB {
|
class DirB {
|
||||||
|
@ -228,182 +104,7 @@ describe('di', () => {
|
||||||
(DirA as any)['__NG_ELEMENT_ID__'] = 1;
|
(DirA as any)['__NG_ELEMENT_ID__'] = 1;
|
||||||
(DirC as any)['__NG_ELEMENT_ID__'] = 257;
|
(DirC as any)['__NG_ELEMENT_ID__'] = 257;
|
||||||
new ComponentFixture(App);
|
new ComponentFixture(App);
|
||||||
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB\]/);
|
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB]/);
|
||||||
});
|
|
||||||
|
|
||||||
describe('@Host', () => {
|
|
||||||
let dirA: DirA|null = null;
|
|
||||||
|
|
||||||
beforeEach(() => { dirA = null; });
|
|
||||||
|
|
||||||
class DirA {
|
|
||||||
constructor(@Host() public dirB: DirB) {}
|
|
||||||
|
|
||||||
static ngFactoryDef = () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Host));
|
|
||||||
static ngDirectiveDef = ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']]});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test needs to be moved to acceptance/di_spec.ts
|
|
||||||
* when Ivy compiler supports inline views.
|
|
||||||
*/
|
|
||||||
it('should not find providers on the host itself if in inline view', () => {
|
|
||||||
let comp !: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* % if (showing) {
|
|
||||||
* <div dirA></div>
|
|
||||||
* % }
|
|
||||||
*/
|
|
||||||
const Comp = createComponent('comp', function(rf: RenderFlags, ctx: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵcontainer(0);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(0);
|
|
||||||
{
|
|
||||||
if (ctx.showing) {
|
|
||||||
let rf1 = ɵɵembeddedViewStart(0, 1, 0);
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
ɵɵelement(0, 'div', ['dirA', '']);
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
}, 1, 0, [DirA, DirB]);
|
|
||||||
|
|
||||||
/* <comp dirB></comp> */
|
|
||||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵelement(0, 'comp', ['dirB', '']);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
comp = getDirectiveOnNode(0);
|
|
||||||
}
|
|
||||||
}, 1, 0, [Comp, DirB]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(App);
|
|
||||||
expect(() => {
|
|
||||||
comp.showing = true;
|
|
||||||
fixture.update();
|
|
||||||
}).toThrowError(/NodeInjector: NOT_FOUND \[DirB\]/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Special tokens', () => {
|
|
||||||
|
|
||||||
describe('ChangeDetectorRef', () => {
|
|
||||||
let dir: Directive;
|
|
||||||
let dirSameInstance: DirectiveSameInstance;
|
|
||||||
let comp: MyComp;
|
|
||||||
|
|
||||||
class MyComp {
|
|
||||||
constructor(public cdr: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
static ngFactoryDef = () => comp = new MyComp(ɵɵdirectiveInject(ChangeDetectorRef as any));
|
|
||||||
static ngComponentDef = ɵɵdefineComponent({
|
|
||||||
type: MyComp,
|
|
||||||
selectors: [['my-comp']],
|
|
||||||
consts: 1,
|
|
||||||
vars: 0,
|
|
||||||
template: function(rf: RenderFlags, ctx: MyComp) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵprojectionDef();
|
|
||||||
ɵɵprojection(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Directive {
|
|
||||||
value: string;
|
|
||||||
|
|
||||||
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
|
|
||||||
|
|
||||||
static ngFactoryDef =
|
|
||||||
() => {
|
|
||||||
dir = new Directive(ɵɵdirectiveInject(ChangeDetectorRef as any));
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ngDirectiveDef =
|
|
||||||
ɵɵdefineDirective({type: Directive, selectors: [['', 'dir', '']], exportAs: ['dir']});
|
|
||||||
}
|
|
||||||
|
|
||||||
class DirectiveSameInstance {
|
|
||||||
constructor(public cdr: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
static ngFactoryDef = () => dirSameInstance =
|
|
||||||
new DirectiveSameInstance(ɵɵdirectiveInject(ChangeDetectorRef as any))
|
|
||||||
|
|
||||||
static ngDirectiveDef = ɵɵdefineDirective(
|
|
||||||
{type: DirectiveSameInstance, selectors: [['', 'dirSame', '']]});
|
|
||||||
}
|
|
||||||
|
|
||||||
const directives = [MyComp, Directive, DirectiveSameInstance];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test needs to be moved to acceptance/di_spec.ts
|
|
||||||
* when Ivy compiler supports inline views.
|
|
||||||
*/
|
|
||||||
it('should inject host component ChangeDetectorRef into directives in embedded views', () => {
|
|
||||||
|
|
||||||
class MyApp {
|
|
||||||
showing = true;
|
|
||||||
|
|
||||||
constructor(public cdr: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
static ngFactoryDef = () => new MyApp(ɵɵdirectiveInject(ChangeDetectorRef as any));
|
|
||||||
static ngComponentDef = ɵɵdefineComponent({
|
|
||||||
type: MyApp,
|
|
||||||
selectors: [['my-app']],
|
|
||||||
consts: 1,
|
|
||||||
vars: 0,
|
|
||||||
/**
|
|
||||||
* % if (showing) {
|
|
||||||
* <div dir dirSame #dir="dir"> {{ dir.value }} </div>
|
|
||||||
* % }
|
|
||||||
*/
|
|
||||||
template: function(rf: RenderFlags, ctx: MyApp) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵcontainer(0);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(0);
|
|
||||||
{
|
|
||||||
if (ctx.showing) {
|
|
||||||
let rf1 = ɵɵembeddedViewStart(0, 3, 1);
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
ɵɵelementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
|
|
||||||
{ ɵɵtext(2); }
|
|
||||||
ɵɵelementEnd();
|
|
||||||
}
|
|
||||||
if (rf1 & RenderFlags.Update) {
|
|
||||||
const tmp = ɵɵreference(1) as any;
|
|
||||||
ɵɵselect(2);
|
|
||||||
ɵɵtextInterpolate(tmp.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
directives: directives
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const app = renderComponent(MyApp);
|
|
||||||
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
|
|
||||||
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
|
|
||||||
|
|
||||||
// Each ChangeDetectorRef instance should be unique
|
|
||||||
expect(dir !.cdr).not.toBe(app.cdr);
|
|
||||||
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -513,76 +214,6 @@ describe('di', () => {
|
||||||
expect(bloomHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
|
expect(bloomHasToken(bloomHash(Dir231) as number, 0, mockTView.data)).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* This test needs to be moved to acceptance/di_spec.ts when Ivy compiler supports inline views.
|
|
||||||
*/
|
|
||||||
it('should inject from parent view', () => {
|
|
||||||
const ParentDirective = createDirective('parentDir');
|
|
||||||
|
|
||||||
class ChildDirective {
|
|
||||||
value: string;
|
|
||||||
constructor(public parent: any) { this.value = (parent.constructor as any).name; }
|
|
||||||
static ngFactoryDef = () => new ChildDirective(ɵɵdirectiveInject(ParentDirective));
|
|
||||||
static ngDirectiveDef = ɵɵdefineDirective(
|
|
||||||
{type: ChildDirective, selectors: [['', 'childDir', '']], exportAs: ['childDir']});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Child2Directive {
|
|
||||||
value: boolean;
|
|
||||||
constructor(parent: any, child: ChildDirective) { this.value = parent === child.parent; }
|
|
||||||
static ngFactoryDef = () => new Child2Directive(
|
|
||||||
ɵɵdirectiveInject(ParentDirective), ɵɵdirectiveInject(ChildDirective))
|
|
||||||
|
|
||||||
static ngDirectiveDef = ɵɵdefineDirective({
|
|
||||||
selectors: [['', 'child2Dir', '']],
|
|
||||||
type: Child2Directive,
|
|
||||||
exportAs: ['child2Dir']
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <div parentDir>
|
|
||||||
* % if (...) {
|
|
||||||
* <span childDir child2Dir #child1="childDir" #child2="child2Dir">
|
|
||||||
* {{ child1.value }} - {{ child2.value }}
|
|
||||||
* </span>
|
|
||||||
* % }
|
|
||||||
* </div>
|
|
||||||
*/
|
|
||||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ɵɵelementStart(0, 'div', ['parentDir', '']);
|
|
||||||
{ ɵɵcontainer(1); }
|
|
||||||
ɵɵelementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ɵɵcontainerRefreshStart(1);
|
|
||||||
{
|
|
||||||
let rf1 = ɵɵembeddedViewStart(0, 4, 2);
|
|
||||||
if (rf1 & RenderFlags.Create) {
|
|
||||||
ɵɵelementStart(
|
|
||||||
0, 'span', ['childDir', '', 'child2Dir', ''],
|
|
||||||
['child1', 'childDir', 'child2', 'child2Dir']);
|
|
||||||
{ ɵɵtext(3); }
|
|
||||||
ɵɵelementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
const tmp1 = ɵɵreference(1) as any;
|
|
||||||
const tmp2 = ɵɵreference(2) as any;
|
|
||||||
ɵɵselect(3);
|
|
||||||
ɵɵtextInterpolate2('', tmp1.value, '-', tmp2.value, '');
|
|
||||||
}
|
|
||||||
ɵɵembeddedViewEnd();
|
|
||||||
}
|
|
||||||
ɵɵcontainerRefreshEnd();
|
|
||||||
}
|
|
||||||
}, 2, 0, [ChildDirective, Child2Directive, ParentDirective]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(App);
|
|
||||||
expect(fixture.html)
|
|
||||||
.toEqual('<div parentdir=""><span child2dir="" childdir="">Directive-true</span></div>');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getOrCreateNodeInjector', () => {
|
describe('getOrCreateNodeInjector', () => {
|
||||||
|
|
Loading…
Reference in New Issue