test(ivy): move some local ref tests to use TestBed infrastructure. (#28534)

When we first started writing tests for Ivy, we did not yet have a
compatible compiler. For this reason, we set up the Ivy runtime tests
to run with generated code that we wrote by hand (instead of real code
generated by the compiler).

Now that we have a working Ivy compiler and TestBed infrastructure
that is compatible with Ivy, we should start writing integration
tests that leverage them (no more handwritten generated code!). This
will prevent bugs where the compiler code and runtime code become
out of sync (which is easy if they are tested separately). And
eventually, we should migrate all the existing runtime tests in
"core/test/render3" to TestBed and ngtsc.

To kick off this effort, this commit migrates some existing tests
from "core/test/render3/exports_spec.ts" and saves them in a new file
with the same name in the "core/test/acceptance" folder.

PR Close #28534
This commit is contained in:
Kara Erickson 2019-02-04 20:42:30 -08:00 committed by Matias Niemelä
parent baf103c98f
commit 8f15cdbc7c
3 changed files with 118 additions and 134 deletions

View File

@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:private"])
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
ts_library(
name = "acceptance_lib",
testonly = True,
srcs = glob(
["**/*.ts"],
),
deps = [
"//packages/common",
"//packages/compiler",
"//packages/compiler/testing",
"//packages/core",
"//packages/core/testing",
"//packages/platform-browser",
"//packages/platform-browser-dynamic",
"//packages/platform-browser/testing",
"//packages/private/testing",
"@ngdeps//zone.js",
],
)
jasmine_node_test(
name = "acceptance",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
deps = [
":acceptance_lib",
"//tools/testing:node",
"@ngdeps//base64-js",
"@ngdeps//source-map",
"@ngdeps//zone.js",
],
)

View File

@ -0,0 +1,82 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Component, Directive, Input, Type} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {onlyInIvy} from '@angular/private/testing';
describe('exports', () => {
beforeEach(() => {
TestBed.configureTestingModule(
{declarations: [AppComp, ComponentToReference, DirToReference, DirWithCompInput]});
});
it('should support export of DOM element', () => {
const fixture = initWithTemplate(AppComp, '<input value="one" #myInput> {{ myInput.value }}');
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('<input value="one"> one');
});
it('should support basic export of component', () => {
const fixture =
initWithTemplate(AppComp, '<comp-to-ref #myComp></comp-to-ref> {{ myComp.name }}');
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('<comp-to-ref></comp-to-ref> Nancy');
});
it('should work with directives with exportAs set', () => {
const fixture = initWithTemplate(AppComp, '<div dir #myDir="dir"></div> {{ myDir.name }}');
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('<div dir=""></div> Drew');
});
onlyInIvy('Different error message is thrown in View Engine')
.it('should throw if export name is not found', () => {
expect(() => {
const fixture = initWithTemplate(AppComp, '<div #myDir="dir"></div>');
fixture.detectChanges();
}).toThrowError(/Export of name 'dir' not found!/);
});
it('should support component instance fed into directive', () => {
const fixture = initWithTemplate(
AppComp, '<comp-to-ref #myComp></comp-to-ref> <div [dirWithInput]="myComp"></div>');
fixture.detectChanges();
const myComp = fixture.debugElement.children[0].injector.get(ComponentToReference);
const dirWithInput = fixture.debugElement.children[1].injector.get(DirWithCompInput);
expect(dirWithInput.comp).toEqual(myComp);
});
});
function initWithTemplate(compType: Type<any>, template: string) {
TestBed.overrideComponent(compType, {set: new Component({template})});
return TestBed.createComponent(compType);
}
@Component({selector: 'comp-to-ref', template: ''})
class ComponentToReference {
name = 'Nancy';
}
@Component({selector: 'app-comp', template: ``})
class AppComp {
}
@Directive({selector: '[dir]', exportAs: 'dir'})
class DirToReference {
name = 'Drew';
}
@Directive({selector: '[dirWithInput]'})
class DirWithCompInput {
@Input('dirWithInput') comp: ComponentToReference|null = null;
}

View File

@ -14,140 +14,7 @@ import {NgIf} from './common_with_def';
import {ComponentFixture, createComponent, renderToHtml} from './render_util';
describe('exports', () => {
it('should support export of DOM element', () => {
/** <input value="one" #myInput> {{ myInput.value }} */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'input', ['value', 'one'], ['myInput', '']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}, 3, 1);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<input value="one">one');
});
it('should support basic export of component', () => {
class MyComponent {
name = 'Nancy';
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
vars: 0,
template: function() {},
factory: () => new MyComponent
});
}
/** <comp #myComp></comp> {{ myComp.name }} */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', null, ['myComp', '']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, tmp.name);
}
}, 3, 1, [MyComponent]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<comp></comp>Nancy');
});
it('should support component instance fed into directive', () => {
let myComponent: MyComponent;
let myDir: MyDir;
class MyComponent {
constructor() { myComponent = this; }
static ngComponentDef = defineComponent({
type: MyComponent,
selectors: [['comp']],
consts: 0,
vars: 0,
template: function() {},
factory: () => new MyComponent
});
}
class MyDir {
// TODO(issue/24571): remove '!'.
myDir !: MyComponent;
constructor() { myDir = this; }
static ngDirectiveDef = defineDirective({
type: MyDir,
selectors: [['', 'myDir', '']],
factory: () => new MyDir,
inputs: {myDir: 'myDir'}
});
}
const defs = [MyComponent, MyDir];
/** <comp #myComp></comp> <div [myDir]="myComp"></div> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'comp', null, ['myComp', '']);
element(2, 'div', ['myDir', '']);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
elementProperty(2, 'myDir', bind(tmp));
}
}, 3, 1, defs);
const fixture = new ComponentFixture(App);
expect(myDir !.myDir).toEqual(myComponent !);
});
it('should work with directives with exportAs set', () => {
class SomeDir {
name = 'Drew';
static ngDirectiveDef = defineDirective({
type: SomeDir,
selectors: [['', 'someDir', '']],
factory: () => new SomeDir,
exportAs: ['someDir']
});
}
/** <div someDir #myDir="someDir"></div> {{ myDir.name }} */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', ['someDir', ''], ['myDir', 'someDir']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.name));
}
}, 3, 1, [SomeDir]);
const fixture = new ComponentFixture(App);
expect(fixture.html).toEqual('<div somedir=""></div>Drew');
});
it('should throw if export name is not found', () => {
/** <div #myDir="someDir"></div> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'div', null, ['myDir', 'someDir']);
}
}, 1);
expect(() => {
const fixture = new ComponentFixture(App);
}).toThrowError(/Export of name 'someDir' not found!/);
});
// For basic use cases, see core/test/acceptance/exports_spec.ts.
describe('forward refs', () => {
it('should work with basic text bindings', () => {