test(ivy): move discovery_utils tests to acceptance (#30416)

Rewrites the discovery util tests to use `TestBed`.

PR Close #30416
This commit is contained in:
Kristiyan Kostadinov 2019-05-11 08:50:12 -04:00 committed by Alex Rickabaugh
parent 96baff3a85
commit cc2f175617
1 changed files with 95 additions and 264 deletions

View File

@ -5,16 +5,15 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {StaticInjector} from '../../src/di/injector';
import {createInjector} from '../../src/di/r3_injector';
import {AttributeMarker, RenderFlags, getHostElement, ɵɵProvidersFeature, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵi18n, ɵɵi18nApply, ɵɵi18nExp, ɵɵselect} from '../../src/render3/index';
import {markDirty, ɵɵbind, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵlistener, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
import {CommonModule} from '@angular/common';
import {Component, Directive, InjectionToken, ViewChild} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {onlyInIvy} from '@angular/private/testing';
import {getHostElement, markDirty} from '../../src/render3/index';
import {getComponent, getContext, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/util/discovery_utils';
import {NgIf} from './common_with_def';
import {ComponentFixture} from './render_util';
describe('discovery utils', () => {
onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
let fixture: ComponentFixture<MyApp>;
let myApp: MyApp;
let dirA: DirectiveA[];
@ -29,115 +28,46 @@ describe('discovery utils', () => {
log = [];
dirA = [];
childComponent = [];
fixture = new ComponentFixture(
MyApp, {injector: createInjector(null, null, [{provide: String, useValue: 'Module'}])});
child = fixture.hostElement.querySelectorAll('child');
span = fixture.hostElement.querySelectorAll('span');
div = fixture.hostElement.querySelectorAll('div');
p = fixture.hostElement.querySelectorAll('p');
TestBed.configureTestingModule({
imports: [CommonModule],
declarations: [MyApp, DirectiveA, Child],
providers: [{provide: String, useValue: 'Module'}]
});
fixture = TestBed.createComponent(MyApp);
fixture.detectChanges();
child = fixture.nativeElement.querySelectorAll('child');
span = fixture.nativeElement.querySelectorAll('span');
div = fixture.nativeElement.querySelectorAll('div');
p = fixture.nativeElement.querySelectorAll('p');
});
/**
* For all tests assume this set up
*
* ```
* <my-app>
* <#VIEW>
* <span (click)=" log.push($event) ">{{text}}</span>
* <div dirA #div #foo="dirA"></div>
* <child>
* <#VIEW>
* <p></p>
* <VIEW>
* </child>
* <child dirA #child>
* <#VIEW>
* <p></p>
* <VIEW>
* </child>
* <child dirA *ngIf="true">
* <#VIEW>
* <p></p>
* <VIEW>
* </child>
* <i18n>ICU expression</i18n>
* </#VIEW>
* </my-app>
* ```
*/
@Component(
{selector: 'child', template: '<p></p>', providers: [{provide: String, useValue: 'Child'}]})
class Child {
constructor() { childComponent.push(this); }
static ngComponentDef = ɵɵdefineComponent({
type: Child,
selectors: [['child']],
factory: () => new Child(),
consts: 1,
vars: 0,
template: (rf: RenderFlags, ctx: Child) => {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'p');
}
},
features: [ɵɵProvidersFeature([{provide: String, useValue: 'Child'}])]
});
}
@Directive({selector: '[dirA]', exportAs: 'dirA'})
class DirectiveA {
constructor() { dirA.push(this); }
static ngDirectiveDef = ɵɵdefineDirective({
type: DirectiveA,
selectors: [['', 'dirA', '']],
exportAs: ['dirA'],
factory: () => new DirectiveA(),
});
}
const MSG_DIV = `{<7B>0<EFBFBD>, select,
other {ICU expression}
}`;
@Component({
selector: 'my-app',
template: `
<span (click)="log($event)">{{text}}</span>
<div dirA #div #foo="dirA"></div>
<child></child>
<child dirA #child></child>
<child dirA *ngIf="true"></child>
<ng-container><p></p></ng-container>
`
})
class MyApp {
text: string = 'INIT';
constructor() { myApp = this; }
static ngComponentDef = ɵɵdefineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(),
consts: 13,
vars: 1,
directives: [Child, DirectiveA, NgIf],
template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'span');
ɵɵlistener('click', $event => log.push($event));
ɵɵtext(1);
ɵɵelementEnd();
ɵɵelement(2, 'div', ['dirA', ''], ['div', '', 'foo', 'dirA']);
ɵɵelement(5, 'child');
ɵɵelement(6, 'child', ['dirA', ''], ['child', '']);
ɵɵtemplate(8, function(rf: RenderFlags, ctx: never) {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'child');
}
}, 1, 0, 'child', ['dirA', AttributeMarker.Template, 'ngIf']);
ɵɵelementStart(9, 'i18n');
ɵɵi18n(10, MSG_DIV);
ɵɵelementEnd();
ɵɵelementContainerStart(11);
{ ɵɵtext(12, 'content'); }
ɵɵelementContainerEnd();
}
if (rf & RenderFlags.Update) {
ɵɵtextBinding(1, ɵɵbind(ctx.text));
ɵɵelementProperty(8, 'ngIf', ɵɵbind(true));
ɵɵi18nExp(ɵɵbind(ctx.text));
ɵɵi18nApply(10);
}
}
});
log(event: any) { log.push(event); }
}
describe('getComponent', () => {
@ -151,7 +81,7 @@ describe('discovery utils', () => {
expect(() => getComponent(dirA[1] as any)).toThrowError(/Expecting instance of DOM Node/);
});
it('should return component from element', () => {
expect(getComponent<MyApp>(fixture.hostElement)).toEqual(myApp);
expect(getComponent<MyApp>(fixture.nativeElement)).toEqual(myApp);
expect(getComponent<Child>(child[0])).toEqual(childComponent[0]);
expect(getComponent<Child>(child[1])).toEqual(childComponent[1]);
});
@ -171,7 +101,7 @@ describe('discovery utils', () => {
describe('getHostElement', () => {
it('should return element on component', () => {
expect(getHostElement(myApp)).toEqual(fixture.hostElement);
expect(getHostElement(myApp)).toEqual(fixture.nativeElement);
expect(getHostElement(childComponent[0])).toEqual(child[0]);
expect(getHostElement(childComponent[1])).toEqual(child[1]);
});
@ -186,7 +116,7 @@ describe('discovery utils', () => {
describe('getInjector', () => {
it('should return node-injector from element', () => {
expect(getInjector(fixture.hostElement).get(String)).toEqual('Module');
expect(getInjector(fixture.nativeElement).get(String)).toEqual('Module');
expect(getInjector(child[0]).get(String)).toEqual('Child');
expect(getInjector(p[0]).get(String)).toEqual('Child');
});
@ -203,7 +133,7 @@ describe('discovery utils', () => {
describe('getDirectives', () => {
it('should return empty array if no directives', () => {
expect(getDirectives(fixture.hostElement)).toEqual([]);
expect(getDirectives(fixture.nativeElement)).toEqual([]);
expect(getDirectives(span[0])).toEqual([]);
expect(getDirectives(child[0])).toEqual([]);
});
@ -215,7 +145,7 @@ describe('discovery utils', () => {
describe('getViewComponent', () => {
it('should return null when called on root component', () => {
expect(getViewComponent(fixture.hostElement)).toEqual(null);
expect(getViewComponent(fixture.nativeElement)).toEqual(null);
expect(getViewComponent(myApp)).toEqual(null);
});
it('should return containing component of child component', () => {
@ -242,7 +172,7 @@ describe('discovery utils', () => {
describe('getLocalRefs', () => {
it('should retrieve empty map', () => {
expect(getLocalRefs(fixture.hostElement)).toEqual({});
expect(getLocalRefs(fixture.nativeElement)).toEqual({});
expect(getLocalRefs(myApp)).toEqual({});
expect(getLocalRefs(span[0])).toEqual({});
expect(getLocalRefs(child[0])).toEqual({});
@ -274,7 +204,7 @@ describe('discovery utils', () => {
describe('getListeners', () => {
it('should return no listeners', () => {
expect(getListeners(fixture.hostElement)).toEqual([]);
expect(getListeners(fixture.nativeElement)).toEqual([]);
expect(getListeners(child[0])).toEqual([]);
});
it('should return the listeners', () => {
@ -290,7 +220,7 @@ describe('discovery utils', () => {
describe('getInjectionTokens', () => {
it('should retrieve tokens', () => {
expect(getInjectionTokens(fixture.hostElement)).toEqual([MyApp]);
expect(getInjectionTokens(fixture.nativeElement)).toEqual([MyApp]);
expect(getInjectionTokens(child[0])).toEqual([String, Child]);
expect(getInjectionTokens(child[1])).toEqual([String, Child, DirectiveA]);
});
@ -301,7 +231,7 @@ describe('discovery utils', () => {
expect(span[0].textContent).toEqual('INIT');
myApp.text = 'WORKS';
markDirty(myApp);
fixture.requestAnimationFrame.flush();
fixture.detectChanges();
expect(span[0].textContent).toEqual('WORKS');
});
});
@ -314,23 +244,15 @@ describe('discovery utils', () => {
});
it('should work on templates', () => {
const templateComment = Array.from(fixture.hostElement.childNodes)
const templateComment = Array.from(fixture.nativeElement.childNodes)
.find((node: ChildNode) => node.nodeType === Node.COMMENT_NODE) !;
const lContext = loadLContext(templateComment);
expect(lContext).toBeDefined();
expect(lContext.native as any).toBe(templateComment);
});
it('should work on ICU expressions', () => {
const icuComment = Array.from(fixture.hostElement.querySelector('i18n') !.childNodes)
.find((node: ChildNode) => node.nodeType === Node.COMMENT_NODE) !;
const lContext = loadLContext(icuComment);
expect(lContext).toBeDefined();
expect(lContext.native as any).toBe(icuComment);
});
it('should work on ng-container', () => {
const ngContainerComment = Array.from(fixture.hostElement.childNodes)
const ngContainerComment = Array.from(fixture.nativeElement.childNodes)
.find(
(node: ChildNode) => node.nodeType === Node.COMMENT_NODE &&
node.textContent === `ng-container`) !;
@ -341,50 +263,26 @@ describe('discovery utils', () => {
});
});
describe('discovery utils deprecated', () => {
onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => {
describe('getRootComponents()', () => {
it('should return a list of the root components of the application from an element', () => {
let innerComp: InnerComp;
@Component({selector: 'inner-comp', template: '<div></div>'})
class InnerComp {
static ngComponentDef = ɵɵdefineComponent({
type: InnerComp,
selectors: [['inner-comp']],
factory: () => innerComp = new InnerComp(),
consts: 1,
vars: 0,
template: (rf: RenderFlags, ctx: InnerComp) => {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'div');
}
}
});
}
@Component({selector: 'comp', template: '<inner-comp></inner-comp>'})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 1,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'inner-comp');
}
},
directives: [InnerComp]
});
}
const fixture = new ComponentFixture(Comp);
fixture.update();
TestBed.configureTestingModule({declarations: [Comp, InnerComp]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
const hostElm = fixture.hostElement;
const hostElm = fixture.nativeElement;
const innerElm = hostElm.querySelector('inner-comp') !;
const divElm = hostElm.querySelector('div') !;
const component = fixture.component;
const component = fixture.componentInstance;
expect(getRootComponents(hostElm) !).toEqual([component]);
expect(getRootComponents(innerElm) !).toEqual([component]);
@ -394,65 +292,46 @@ describe('discovery utils deprecated', () => {
describe('getDirectives()', () => {
it('should return a list of the directives that are on the given element', () => {
let myDir1Instance: MyDir1|null = null;
let myDir2Instance: MyDir2|null = null;
let myDir3Instance: MyDir2|null = null;
@Directive({selector: '[my-dir-1]'})
class MyDir1 {
static ngDirectiveDef = ɵɵdefineDirective({
type: MyDir1,
selectors: [['', 'my-dir-1', '']],
factory: () => myDir1Instance = new MyDir1()
});
}
@Directive({selector: '[my-dir-2]'})
class MyDir2 {
static ngDirectiveDef = ɵɵdefineDirective({
type: MyDir2,
selectors: [['', 'my-dir-2', '']],
factory: () => myDir2Instance = new MyDir2()
});
}
@Directive({selector: '[my-dir-3]'})
class MyDir3 {
static ngDirectiveDef = ɵɵdefineDirective({
type: MyDir3,
selectors: [['', 'my-dir-3', '']],
factory: () => myDir3Instance = new MyDir2()
});
}
@Component({
selector: 'comp',
template: `
<div my-dir-1 my-dir-2></div>
<div my-dir-3></div>
`
})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 2,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'div', ['my-dir-1', '', 'my-dir-2', '']);
ɵɵelement(1, 'div', ['my-dir-3']);
}
},
directives: [MyDir1, MyDir2, MyDir3]
});
@ViewChild(MyDir1) myDir1Instance !: MyDir1;
@ViewChild(MyDir2) myDir2Instance !: MyDir2;
@ViewChild(MyDir3) myDir3Instance !: MyDir3;
}
const fixture = new ComponentFixture(Comp);
fixture.update();
TestBed.configureTestingModule({declarations: [Comp, MyDir1, MyDir2, MyDir3]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
const hostElm = fixture.hostElement;
const hostElm = fixture.nativeElement;
const elements = hostElm.querySelectorAll('div');
const elm1 = elements[0];
const elm1Dirs = getDirectives(elm1);
expect(elm1Dirs).toContain(myDir1Instance !);
expect(elm1Dirs).toContain(myDir2Instance !);
expect(elm1Dirs).toContain(fixture.componentInstance.myDir1Instance !);
expect(elm1Dirs).toContain(fixture.componentInstance.myDir2Instance !);
const elm2 = elements[1];
const elm2Dirs = getDirectives(elm2);
expect(elm2Dirs).toContain(myDir3Instance !);
expect(elm2Dirs).toContain(fixture.componentInstance.myDir3Instance !);
});
});
@ -460,81 +339,48 @@ describe('discovery utils deprecated', () => {
it('should return an injector that can return directive instances', () => {
@Component({template: ''})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 0,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {}
});
}
const fixture = new ComponentFixture(Comp);
fixture.update();
const nodeInjector = getInjector(fixture.hostElement);
TestBed.configureTestingModule({declarations: [Comp]});
const fixture = TestBed.createComponent(Comp);
const nodeInjector = getInjector(fixture.nativeElement);
expect(nodeInjector.get(Comp)).toEqual(jasmine.any(Comp));
});
it('should return an injector that falls-back to a module injector', () => {
@Component({template: ''})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 0,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {}
});
}
class TestToken {}
const token = new InjectionToken<TestToken>('test token');
const staticInjector = new StaticInjector([{provide: TestToken, useValue: new TestToken()}]);
const fixture = new ComponentFixture(Comp, {injector: staticInjector});
fixture.update();
const nodeInjector = getInjector(fixture.hostElement);
expect(nodeInjector.get(TestToken)).toEqual(jasmine.any(TestToken));
TestBed.configureTestingModule(
{declarations: [Comp], providers: [{provide: token, useValue: new TestToken()}]});
const fixture = TestBed.createComponent(Comp);
const nodeInjector = getInjector(fixture.nativeElement);
expect(nodeInjector.get(token)).toEqual(jasmine.any(TestToken));
});
});
describe('getLocalRefs', () => {
it('should return a map of local refs for an element', () => {
@Directive({selector: '[myDir]', exportAs: 'myDir'})
class MyDir {
static ngDirectiveDef = ɵɵdefineDirective({
type: MyDir,
selectors: [['', 'myDir', '']],
exportAs: ['myDir'],
factory: () => new MyDir()
});
}
@Component({template: '<div myDir #elRef #dirRef="myDir"></div>'})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 3,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {
if (rf & RenderFlags.Create) {
// <div myDir #elRef #dirRef="myDir">
ɵɵelement(0, 'div', ['myDir'], ['elRef', '', 'dirRef', 'myDir']);
}
},
directives: [MyDir]
});
}
const fixture = new ComponentFixture(Comp);
fixture.update();
TestBed.configureTestingModule({declarations: [Comp, MyDir]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
const divEl = fixture.hostElement.querySelector('div') !;
const divEl = fixture.nativeElement.querySelector('div') !;
const localRefs = getLocalRefs(divEl);
expect(localRefs.elRef.tagName.toLowerCase()).toBe('div');
@ -542,31 +388,16 @@ describe('discovery utils deprecated', () => {
});
it('should return a map of local refs for an element with styling context', () => {
@Component({template: '<div #elRef class="fooClass" [style.color]="color"></div>'})
class Comp {
static ngComponentDef = ɵɵdefineComponent({
type: Comp,
selectors: [['comp']],
factory: () => new Comp(),
consts: 2,
vars: 0,
template: (rf: RenderFlags, ctx: Comp) => {
if (rf & RenderFlags.Create) {
// <div #elRef class="fooClass">
ɵɵelementStart(0, 'div', null, ['elRef', '']);
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵselect(0);
ɵɵstylingApply();
}
}
});
color = 'red';
}
const fixture = new ComponentFixture(Comp);
fixture.update();
TestBed.configureTestingModule({declarations: [Comp]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
const divEl = fixture.hostElement.querySelector('div') !;
const divEl = fixture.nativeElement.querySelector('div') !;
const localRefs = getLocalRefs(divEl);
expect(localRefs.elRef.tagName.toLowerCase()).toBe('div');