From 8f15cdbc7cdc359933fb0831c6a714d62969d835 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Mon, 4 Feb 2019 20:42:30 -0800 Subject: [PATCH] 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 --- packages/core/test/acceptance/BUILD.bazel | 35 +++++ packages/core/test/acceptance/exports_spec.ts | 82 +++++++++++ packages/core/test/render3/exports_spec.ts | 135 +----------------- 3 files changed, 118 insertions(+), 134 deletions(-) create mode 100644 packages/core/test/acceptance/BUILD.bazel create mode 100644 packages/core/test/acceptance/exports_spec.ts diff --git a/packages/core/test/acceptance/BUILD.bazel b/packages/core/test/acceptance/BUILD.bazel new file mode 100644 index 0000000000..6ef8cb8dd6 --- /dev/null +++ b/packages/core/test/acceptance/BUILD.bazel @@ -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", + ], +) diff --git a/packages/core/test/acceptance/exports_spec.ts b/packages/core/test/acceptance/exports_spec.ts new file mode 100644 index 0000000000..0945171357 --- /dev/null +++ b/packages/core/test/acceptance/exports_spec.ts @@ -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, ' {{ myInput.value }}'); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML).toEqual(' one'); + }); + + it('should support basic export of component', () => { + const fixture = + initWithTemplate(AppComp, ' {{ myComp.name }}'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerHTML).toEqual(' Nancy'); + }); + + it('should work with directives with exportAs set', () => { + const fixture = initWithTemplate(AppComp, '
{{ myDir.name }}'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerHTML).toEqual('
Drew'); + }); + + onlyInIvy('Different error message is thrown in View Engine') + .it('should throw if export name is not found', () => { + expect(() => { + const fixture = initWithTemplate(AppComp, '
'); + fixture.detectChanges(); + }).toThrowError(/Export of name 'dir' not found!/); + }); + + it('should support component instance fed into directive', () => { + const fixture = initWithTemplate( + AppComp, '
'); + 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, 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; +} diff --git a/packages/core/test/render3/exports_spec.ts b/packages/core/test/render3/exports_spec.ts index da2928230c..c8cab82482 100644 --- a/packages/core/test/render3/exports_spec.ts +++ b/packages/core/test/render3/exports_spec.ts @@ -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', () => { - - /** {{ 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('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 - }); - } - - /** {{ 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('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]; - - /**
*/ - 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'] - }); - } - - /**
{{ 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('
Drew'); - }); - - it('should throw if export name is not found', () => { - - /**
*/ - 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', () => {