diff --git a/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts b/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts index f52e178640..66a188576f 100644 --- a/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts +++ b/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, DoCheck, ElementRef, EventEmitter, Inject, Injector, OnChanges, OnInit, SimpleChange, SimpleChanges, Type} from '@angular/core'; +import {Directive, DoCheck, ElementRef, EventEmitter, Inject, Injector, OnChanges, OnDestroy, OnInit, SimpleChange, SimpleChanges, Type} from '@angular/core'; import * as angular from '../common/angular1'; import {$SCOPE} from '../common/constants'; @@ -46,23 +46,14 @@ export class UpgradeNg1ComponentAdapterBuilder { const directive = {selector: selector, inputs: this.inputsRename, outputs: this.outputsRename}; @Directive({jit: true, ...directive}) - class MyClass { - // TODO(issue/24571): remove '!'. - directive !: angular.IDirective; + class MyClass extends UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck, + OnDestroy { constructor( @Inject($SCOPE) scope: angular.IScope, injector: Injector, elementRef: ElementRef) { - const helper = new UpgradeHelper(injector, name, elementRef, this.directive); - return new UpgradeNg1ComponentAdapter( - helper, scope, self.template, self.inputs, self.outputs, self.propertyOutputs, - self.checkProperties, self.propertyMap) as any; - } - ngOnInit() { /* needs to be here for ng2 to properly detect it */ - } - ngOnChanges() { /* needs to be here for ng2 to properly detect it */ - } - ngDoCheck() { /* needs to be here for ng2 to properly detect it */ - } - ngOnDestroy() { /* needs to be here for ng2 to properly detect it */ + super( + new UpgradeHelper(injector, name, elementRef, self.directive || undefined), scope, + self.template, self.inputs, self.outputs, self.propertyOutputs, self.checkProperties, + self.propertyMap) as any; } } this.type = MyClass; @@ -149,7 +140,7 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck { private controllerInstance: IControllerInstance|null = null; destinationObj: IBindingDestination|null = null; checkLastValues: any[] = []; - private directive: angular.IDirective; + directive: angular.IDirective; element: Element; $element: any = null; componentScope: angular.IScope; diff --git a/packages/upgrade/test/dynamic/upgrade_spec.ts b/packages/upgrade/test/dynamic/upgrade_spec.ts index 672ac9a29d..cb25b76046 100644 --- a/packages/upgrade/test/dynamic/upgrade_spec.ts +++ b/packages/upgrade/test/dynamic/upgrade_spec.ts @@ -56,40 +56,36 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should instantiate ng1 in ng2 template and project content', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); + it('should instantiate ng1 in ng2 template and project content', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); - @Component({ - selector: 'ng2', - template: `{{ 'ng2(' }}{{'transclude'}}{{ ')' }}`, - }) - class Ng2 { - } + @Component({ + selector: 'ng2', + template: `{{ 'ng2(' }}{{'transclude'}}{{ ')' }}`, + }) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng1', () => { - return { - transclude: true, - template: '{{ "ng1" }}()' - }; - }); - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + ng1Module.directive('ng1', () => { + return {transclude: true, template: '{{ "ng1" }}()'}; + }); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html('
{{\'ng1(\'}}{{\')\'}}
'); + const element = html('
{{\'ng1(\'}}{{\')\'}}
'); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(document.body.textContent).toEqual('ng1(ng2(ng1(transclude)))'); - ref.dispose(); - }); - })); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(document.body.textContent).toEqual('ng1(ng2(ng1(transclude)))'); + ref.dispose(); + }); + })); it('supports the compilerOptions argument', async(() => { const platformRef = platformBrowserDynamic(); @@ -657,49 +653,48 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-713: ngDestroy not being called when downgraded ng2 component is destroyed') - .it('should properly run cleanup with multiple levels of nesting', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let destroyed = false; + it('should properly run cleanup with multiple levels of nesting', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let destroyed = false; - @Component( - {selector: 'ng2-outer', template: '
'}) - class Ng2OuterComponent { - @Input() destroyIt = false; - } + @Component( + {selector: 'ng2-outer', template: '
'}) + class Ng2OuterComponent { + @Input() destroyIt = false; + } - @Component({selector: 'ng2-inner', template: 'test'}) - class Ng2InnerComponent implements OnDestroy { - ngOnDestroy() { destroyed = true; } - } + @Component({selector: 'ng2-inner', template: 'test'}) + class Ng2InnerComponent implements OnDestroy { + ngOnDestroy() { destroyed = true; } + } - @NgModule({ - imports: [BrowserModule], - declarations: - [Ng2InnerComponent, Ng2OuterComponent, adapter.upgradeNg1Component('ng1')], - schemas: [NO_ERRORS_SCHEMA], - }) - class Ng2Module { - } + @NgModule({ + imports: [BrowserModule], + declarations: + [Ng2InnerComponent, Ng2OuterComponent, adapter.upgradeNg1Component('ng1')], + schemas: [NO_ERRORS_SCHEMA], + }) + class Ng2Module { + } - const ng1Module = - angular.module('ng1', []) - .directive('ng1', () => ({template: ''})) - .directive('ng2Inner', adapter.downgradeNg2Component(Ng2InnerComponent)) - .directive('ng2Outer', adapter.downgradeNg2Component(Ng2OuterComponent)); + const ng1Module = + angular.module('ng1', []) + .directive('ng1', () => ({template: ''})) + .directive('ng2Inner', adapter.downgradeNg2Component(Ng2InnerComponent)) + .directive('ng2Outer', adapter.downgradeNg2Component(Ng2OuterComponent)); - const element = html(''); + const element = html(''); - adapter.bootstrap(element, [ng1Module.name]).ready(ref => { - expect(element.textContent).toBe('test'); - expect(destroyed).toBe(false); + adapter.bootstrap(element, [ng1Module.name]).ready(ref => { + expect(element.textContent).toBe('test'); + expect(destroyed).toBe(false); - $apply(ref, 'destroyIt = true'); + $apply(ref, 'destroyIt = true'); - expect(element.textContent).toBe(''); - expect(destroyed).toBe(true); - }); - })); + expect(element.textContent).toBe(''); + expect(destroyed).toBe(true); + }); + })); it('should fallback to the root ng2.injector when compiled outside the dom', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -1035,61 +1030,59 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support `&` bindings', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + it('should support `&` bindings', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: 'Inside: -', - bindings: {outputA: '&outputAttrA', outputB: '&'} - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: 'Inside: -', + bindings: {outputA: '&outputAttrA', outputB: '&'} + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` | Outside: {{ dataA }}, {{ dataB }} ` - }) - class Ng2Component { - dataA = 'foo'; - dataB = 'bar'; - } + }) + class Ng2Component { + dataA = 'foo'; + dataB = 'bar'; + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - imports: [BrowserModule] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + imports: [BrowserModule] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - const ng1 = element.querySelector('ng1') !; - const ng1Controller = angular.element(ng1).controller !('ng1'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + const ng1 = element.querySelector('ng1') !; + const ng1Controller = angular.element(ng1).controller !('ng1'); - expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar'); + expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar'); - ng1Controller.outputA('baz'); - ng1Controller.outputB('qux'); - $digest(ref); + ng1Controller.outputA('baz'); + ng1Controller.outputB('qux'); + $digest(ref); - expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: baz, qux'); + expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: baz, qux'); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); fixmeIvy('FW-724: upgraded ng1 components are not being rendered') .it('should bind properties, events', async(() => { @@ -1294,65 +1287,63 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support templateUrl fetched from $httpBackend', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); - ng1Module.value( - '$httpBackend', (method: string, url: string, post: any, cbFn: Function) => { - cbFn(200, `${method}:${url}`); - }); + it('should support templateUrl fetched from $httpBackend', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); + ng1Module.value( + '$httpBackend', (method: string, url: string, post: any, cbFn: Function) => { + cbFn(200, `${method}:${url}`); + }); - const ng1 = () => { return {templateUrl: 'url.html'}; }; - ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + const ng1 = () => { return {templateUrl: 'url.html'}; }; + ng1Module.directive('ng1', ng1); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('GET:url.html'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('GET:url.html'); + ref.dispose(); + }); + })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support templateUrl as a function', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); - ng1Module.value( - '$httpBackend', (method: string, url: string, post: any, cbFn: Function) => { - cbFn(200, `${method}:${url}`); - }); + it('should support templateUrl as a function', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); + ng1Module.value( + '$httpBackend', (method: string, url: string, post: any, cbFn: Function) => { + cbFn(200, `${method}:${url}`); + }); - const ng1 = () => { return {templateUrl() { return 'url.html'; }}; }; - ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + const ng1 = () => { return {templateUrl() { return 'url.html'; }}; }; + ng1Module.directive('ng1', ng1); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('GET:url.html'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('GET:url.html'); + ref.dispose(); + }); + })); it('should support empty template', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -1406,81 +1397,76 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support templateUrl fetched from $templateCache', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); - ng1Module.run(($templateCache: any) => $templateCache.put('url.html', 'WORKS')); + it('should support templateUrl fetched from $templateCache', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); + ng1Module.run(($templateCache: any) => $templateCache.put('url.html', 'WORKS')); - const ng1 = () => { return {templateUrl: 'url.html'}; }; - ng1Module.directive('ng1', ng1); + const ng1 = () => { return {templateUrl: 'url.html'}; }; + ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('WORKS'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('WORKS'); + ref.dispose(); + }); + })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support controller with controllerAs', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); + it('should support controller with controllerAs', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); - const ng1 = () => { - return { - scope: true, - template: - '{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}', - controllerAs: 'ctl', - controller: class { - scope: any; hasElement: string; $element: any; isClass: any; - constructor($scope: any, $element: any) { - this.verifyIAmAClass(); - this.scope = - $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope'; - this.hasElement = $element[0].nodeName; - this.$element = $element; - } verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() { - return this.$element.controller('ng1') == this ? 'published' : - 'not-published'; - } - } - }; - }; - ng1Module.directive('ng1', ng1); + const ng1 = () => { + return { + scope: true, + template: + '{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}', + controllerAs: 'ctl', + controller: class { + scope: any; hasElement: string; $element: any; isClass: any; + constructor($scope: any, $element: any) { + this.verifyIAmAClass(); + this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope'; + this.hasElement = $element[0].nodeName; + this.$element = $element; + } verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() { + return this.$element.controller('ng1') == this ? 'published' : 'not-published'; + } + } + }; + }; + ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)) - .toEqual('scope; isClass; NG1; published'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('scope; isClass; NG1; published'); + ref.dispose(); + }); + })); fixmeIvy('FW-724: upgraded ng1 components are not being rendered') .it('should support bindToController', async(() => { @@ -1552,140 +1538,136 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support single require in linking fn', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); + it('should support single require in linking fn', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); - const ng1 = ($rootScope: any) => { - return { - scope: {title: '@'}, - bindToController: true, - template: '{{ctl.status}}', - require: 'ng1', - controllerAs: 'ctrl', - controller: class {status = 'WORKS';}, - link: function(scope: any, element: any, attrs: any, linkController: any) { - expect(scope.$root).toEqual($rootScope); - expect(element[0].nodeName).toEqual('NG1'); - expect(linkController.status).toEqual('WORKS'); - scope.ctl = linkController; - } - }; - }; - ng1Module.directive('ng1', ng1); + const ng1 = ($rootScope: any) => { + return { + scope: {title: '@'}, + bindToController: true, + template: '{{ctl.status}}', + require: 'ng1', + controllerAs: 'ctrl', + controller: class {status = 'WORKS';}, + link: function(scope: any, element: any, attrs: any, linkController: any) { + expect(scope.$root).toEqual($rootScope); + expect(element[0].nodeName).toEqual('NG1'); + expect(linkController.status).toEqual('WORKS'); + scope.ctl = linkController; + } + }; + }; + ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('WORKS'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('WORKS'); + ref.dispose(); + }); + })); - fixmeIvy('FW-724: upgraded ng1 components are not being rendered') - .it('should support array require in linking fn', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); + it('should support array require in linking fn', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); - const parent = () => { return {controller: class {parent = 'PARENT';}}; }; - const ng1 = () => { - return { - scope: {title: '@'}, - bindToController: true, - template: '{{parent.parent}}:{{ng1.status}}', - require: ['ng1', '^parent', '?^^notFound'], - controllerAs: 'ctrl', - controller: class {status = 'WORKS';}, - link: function(scope: any, element: any, attrs: any, linkControllers: any) { - expect(linkControllers[0].status).toEqual('WORKS'); - expect(linkControllers[1].parent).toEqual('PARENT'); - expect(linkControllers[2]).toBe(undefined); - scope.ng1 = linkControllers[0]; - scope.parent = linkControllers[1]; - } - }; - }; - ng1Module.directive('parent', parent); - ng1Module.directive('ng1', ng1); + const parent = () => { return {controller: class {parent = 'PARENT';}}; }; + const ng1 = () => { + return { + scope: {title: '@'}, + bindToController: true, + template: '{{parent.parent}}:{{ng1.status}}', + require: ['ng1', '^parent', '?^^notFound'], + controllerAs: 'ctrl', + controller: class {status = 'WORKS';}, + link: function(scope: any, element: any, attrs: any, linkControllers: any) { + expect(linkControllers[0].status).toEqual('WORKS'); + expect(linkControllers[1].parent).toEqual('PARENT'); + expect(linkControllers[2]).toBe(undefined); + scope.ng1 = linkControllers[0]; + scope.parent = linkControllers[1]; + } + }; + }; + ng1Module.directive('parent', parent); + ng1Module.directive('ng1', ng1); - @Component({selector: 'ng2', template: ''}) - class Ng2 { - } + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('PARENT:WORKS'); - ref.dispose(); - }); - })); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('PARENT:WORKS'); + ref.dispose(); + }); + })); describe('with life-cycle hooks', () => { - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should call `$onInit()` on controller', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const $onInitSpyA = jasmine.createSpy('$onInitA'); - const $onInitSpyB = jasmine.createSpy('$onInitB'); + it('should call `$onInit()` on controller', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const $onInitSpyA = jasmine.createSpy('$onInitA'); + const $onInitSpyB = jasmine.createSpy('$onInitB'); - @Component({selector: 'ng2', template: ' | '}) - class Ng2Component { - } + @Component({selector: 'ng2', template: ' | '}) + class Ng2Component { + } - angular.module('ng1', []) - .directive('ng1A', () => ({ - template: '', - scope: {}, - bindToController: true, - controllerAs: '$ctrl', - controller: class {$onInit() { $onInitSpyA(); }} - })) - .directive('ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function() { this.$onInit = $onInitSpyB; } - })) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + angular.module('ng1', []) + .directive('ng1A', () => ({ + template: '', + scope: {}, + bindToController: true, + controllerAs: '$ctrl', + controller: class {$onInit() { $onInitSpyA(); }} + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function() { this.$onInit = $onInitSpyB; } + })) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [ - adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), - Ng2Component - ], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [ + adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), + Ng2Component + ], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect($onInitSpyA).toHaveBeenCalled(); - expect($onInitSpyB).toHaveBeenCalled(); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect($onInitSpyA).toHaveBeenCalled(); + expect($onInitSpyB).toHaveBeenCalled(); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); it('should not call `$onInit()` on scope', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -1733,61 +1715,59 @@ withEachNg1Version(() => { }); })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should call `$doCheck()` on controller', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const $doCheckSpyA = jasmine.createSpy('$doCheckA'); - const $doCheckSpyB = jasmine.createSpy('$doCheckB'); - let changeDetector: ChangeDetectorRef; + it('should call `$doCheck()` on controller', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const $doCheckSpyA = jasmine.createSpy('$doCheckA'); + const $doCheckSpyB = jasmine.createSpy('$doCheckB'); + let changeDetector: ChangeDetectorRef; - @Component({selector: 'ng2', template: ' | '}) - class Ng2Component { - constructor(cd: ChangeDetectorRef) { changeDetector = cd; } - } + @Component({selector: 'ng2', template: ' | '}) + class Ng2Component { + constructor(cd: ChangeDetectorRef) { changeDetector = cd; } + } - angular.module('ng1', []) - .directive('ng1A', () => ({ - template: '', - scope: {}, - bindToController: true, - controllerAs: '$ctrl', - controller: class {$doCheck() { $doCheckSpyA(); }} - })) - .directive('ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function() { this.$doCheck = $doCheckSpyB; } - })) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + angular.module('ng1', []) + .directive('ng1A', () => ({ + template: '', + scope: {}, + bindToController: true, + controllerAs: '$ctrl', + controller: class {$doCheck() { $doCheckSpyA(); }} + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function() { this.$doCheck = $doCheckSpyB; } + })) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [ - adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), - Ng2Component - ], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [ + adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), + Ng2Component + ], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect($doCheckSpyA).toHaveBeenCalled(); - expect($doCheckSpyB).toHaveBeenCalled(); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect($doCheckSpyA).toHaveBeenCalled(); + expect($doCheckSpyB).toHaveBeenCalled(); - $doCheckSpyA.calls.reset(); - $doCheckSpyB.calls.reset(); - changeDetector.detectChanges(); + $doCheckSpyA.calls.reset(); + $doCheckSpyB.calls.reset(); + changeDetector.detectChanges(); - expect($doCheckSpyA).toHaveBeenCalled(); - expect($doCheckSpyB).toHaveBeenCalled(); + expect($doCheckSpyA).toHaveBeenCalled(); + expect($doCheckSpyB).toHaveBeenCalled(); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); it('should not call `$doCheck()` on scope', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -1844,53 +1824,50 @@ withEachNg1Version(() => { }); })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should call `$postLink()` on controller', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const $postLinkSpyA = jasmine.createSpy('$postLinkA'); - const $postLinkSpyB = jasmine.createSpy('$postLinkB'); + it('should call `$postLink()` on controller', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const $postLinkSpyA = jasmine.createSpy('$postLinkA'); + const $postLinkSpyB = jasmine.createSpy('$postLinkB'); - @Component({selector: 'ng2', template: ' | '}) - class Ng2Component { - } + @Component({selector: 'ng2', template: ' | '}) + class Ng2Component { + } - angular.module('ng1', []) - .directive('ng1A', () => ({ - template: '', - scope: {}, - bindToController: true, - controllerAs: '$ctrl', - controller: class {$postLink() { $postLinkSpyA(); }} - })) - .directive( - 'ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function() { this.$postLink = $postLinkSpyB; } - })) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + angular.module('ng1', []) + .directive('ng1A', () => ({ + template: '', + scope: {}, + bindToController: true, + controllerAs: '$ctrl', + controller: class {$postLink() { $postLinkSpyA(); }} + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function() { this.$postLink = $postLinkSpyB; } + })) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [ - adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), - Ng2Component - ], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [ + adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), + Ng2Component + ], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect($postLinkSpyA).toHaveBeenCalled(); - expect($postLinkSpyB).toHaveBeenCalled(); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect($postLinkSpyA).toHaveBeenCalled(); + expect($postLinkSpyB).toHaveBeenCalled(); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); it('should not call `$postLink()` on scope', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -1939,7 +1916,7 @@ withEachNg1Version(() => { })); fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') + 'FW-844: Directive input bindings cannot be assigned after the `@Directive` decorator has been compiled') .it('should call `$onChanges()` on binding destination', fakeAsync(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const $onChangesControllerSpyA = jasmine.createSpy('$onChangesControllerA'); @@ -2035,7 +2012,7 @@ withEachNg1Version(() => { })); fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') + 'FW-843: destroy hooks are not registered on upgraded ng1 components contained in ng2 component templates under ivy') .it('should call `$onDestroy()` on controller', fakeAsync(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const $onDestroySpyA = jasmine.createSpy('$onDestroyA'); @@ -2127,540 +2104,514 @@ withEachNg1Version(() => { }); })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should not call `$onDestroy()` on scope', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const $onDestroySpy = jasmine.createSpy('$onDestroy'); - let ng2ComponentInstance: Ng2Component; + it('should not call `$onDestroy()` on scope', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const $onDestroySpy = jasmine.createSpy('$onDestroy'); + let ng2ComponentInstance: Ng2Component; - @Component({ - selector: 'ng2', - template: ` + @Component({ + selector: 'ng2', + template: `
|
` - }) - class Ng2Component { - ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + ng2Destroy: boolean = false; + constructor() { ng2ComponentInstance = this; } + } - // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), - // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be - // on - // the queue at the end of the test, causing it to fail. - // Mocking animations (via `ngAnimateMock`) avoids the issue. - angular.module('ng1', ['ngAnimateMock']) - .directive('ng1A', () => ({ - template: '', - scope: {}, - bindToController: true, - controllerAs: '$ctrl', - controller: function($scope: angular.IScope) { - Object.getPrototypeOf($scope).$onDestroy = - $onDestroySpy; - } - })) - .directive('ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function($scope: angular.IScope) { - $scope['$onDestroy'] = $onDestroySpy; - } - })) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), + // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be + // on + // the queue at the end of the test, causing it to fail. + // Mocking animations (via `ngAnimateMock`) avoids the issue. + angular.module('ng1', ['ngAnimateMock']) + .directive('ng1A', () => ({ + template: '', + scope: {}, + bindToController: true, + controllerAs: '$ctrl', + controller: function($scope: angular.IScope) { + Object.getPrototypeOf($scope).$onDestroy = $onDestroySpy; + } + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function($scope: angular.IScope) { + $scope['$onDestroy'] = $onDestroySpy; + } + })) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [ - adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), - Ng2Component - ], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [ + adapter.upgradeNg1Component('ng1A'), adapter.upgradeNg1Component('ng1B'), + Ng2Component + ], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - const $rootScope = ref.ng1RootScope as any; + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + const $rootScope = ref.ng1RootScope as any; - $rootScope.ng1Destroy = false; - tick(); - $rootScope.$digest(); + $rootScope.ng1Destroy = false; + tick(); + $rootScope.$digest(); - $rootScope.ng1Destroy = true; - tick(); - $rootScope.$digest(); + $rootScope.ng1Destroy = true; + tick(); + $rootScope.$digest(); - $rootScope.ng1Destroy = false; - tick(); - $rootScope.$digest(); + $rootScope.ng1Destroy = false; + tick(); + $rootScope.$digest(); - ng2ComponentInstance.ng2Destroy = true; - tick(); - $rootScope.$digest(); + ng2ComponentInstance.ng2Destroy = true; + tick(); + $rootScope.$digest(); - expect($onDestroySpy).not.toHaveBeenCalled(); + expect($onDestroySpy).not.toHaveBeenCalled(); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); }); describe('destroying the upgraded component', () => { - fixmeIvy('FW-713: ngDestroy not being called when downgraded ng2 component is destroyed') - .it('should destroy `componentScope`', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const scopeDestroyListener = jasmine.createSpy('scopeDestroyListener'); - let ng2ComponentInstance: Ng2Component; + it('should destroy `componentScope`', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const scopeDestroyListener = jasmine.createSpy('scopeDestroyListener'); + let ng2ComponentInstance: Ng2Component; - @Component( - {selector: 'ng2', template: '
'}) - class Ng2Component { - ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } - } + @Component({selector: 'ng2', template: '
'}) + class Ng2Component { + ng2Destroy: boolean = false; + constructor() { ng2ComponentInstance = this; } + } - // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), - // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be - // on - // the queue at the end of the test, causing it to fail. - // Mocking animations (via `ngAnimateMock`) avoids the issue. - angular.module('ng1', ['ngAnimateMock']) - .component('ng1', { - controller: function($scope: angular.IScope) { - $scope.$on('$destroy', scopeDestroyListener); - }, - }) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), + // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be + // on + // the queue at the end of the test, causing it to fail. + // Mocking animations (via `ngAnimateMock`) avoids the issue. + angular.module('ng1', ['ngAnimateMock']) + .component('ng1', { + controller: function($scope: angular.IScope) { + $scope.$on('$destroy', scopeDestroyListener); + }, + }) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(''); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - const $rootScope = ref.ng1RootScope as any; + const element = html(''); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + const $rootScope = ref.ng1RootScope as any; - expect(scopeDestroyListener).not.toHaveBeenCalled(); + expect(scopeDestroyListener).not.toHaveBeenCalled(); - ng2ComponentInstance.ng2Destroy = true; - tick(); - $rootScope.$digest(); + ng2ComponentInstance.ng2Destroy = true; + tick(); + $rootScope.$digest(); - expect(scopeDestroyListener).toHaveBeenCalledTimes(1); - }); - })); + expect(scopeDestroyListener).toHaveBeenCalledTimes(1); + }); + })); - fixmeIvy('FW-713: ngDestroy not being called when downgraded ng2 component is destroyed') - .it('should emit `$destroy` on `$element` and descendants', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const elementDestroyListener = jasmine.createSpy('elementDestroyListener'); - const descendantDestroyListener = jasmine.createSpy('descendantDestroyListener'); - let ng2ComponentInstance: Ng2Component; + it('should emit `$destroy` on `$element` and descendants', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const elementDestroyListener = jasmine.createSpy('elementDestroyListener'); + const descendantDestroyListener = jasmine.createSpy('descendantDestroyListener'); + let ng2ComponentInstance: Ng2Component; - @Component( - {selector: 'ng2', template: '
'}) - class Ng2Component { - ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } - } + @Component({selector: 'ng2', template: '
'}) + class Ng2Component { + ng2Destroy: boolean = false; + constructor() { ng2ComponentInstance = this; } + } - // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), - // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be - // on - // the queue at the end of the test, causing it to fail. - // Mocking animations (via `ngAnimateMock`) avoids the issue. - angular.module('ng1', ['ngAnimateMock']) - .component('ng1', { - controller: class { - constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - this.$element.on !('$destroy', elementDestroyListener); - this.$element.contents !().on !('$destroy', descendantDestroyListener); - } - }, - template: '
' - }) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), + // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be + // on + // the queue at the end of the test, causing it to fail. + // Mocking animations (via `ngAnimateMock`) avoids the issue. + angular.module('ng1', ['ngAnimateMock']) + .component('ng1', { + controller: class { + constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { + this.$element.on !('$destroy', elementDestroyListener); + this.$element.contents !().on !('$destroy', descendantDestroyListener); + } + }, + template: '
' + }) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(''); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - const $rootScope = ref.ng1RootScope as any; - tick(); - $rootScope.$digest(); + const element = html(''); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + const $rootScope = ref.ng1RootScope as any; + tick(); + $rootScope.$digest(); - expect(elementDestroyListener).not.toHaveBeenCalled(); - expect(descendantDestroyListener).not.toHaveBeenCalled(); + expect(elementDestroyListener).not.toHaveBeenCalled(); + expect(descendantDestroyListener).not.toHaveBeenCalled(); - ng2ComponentInstance.ng2Destroy = true; - tick(); - $rootScope.$digest(); + ng2ComponentInstance.ng2Destroy = true; + tick(); + $rootScope.$digest(); - expect(elementDestroyListener).toHaveBeenCalledTimes(1); - expect(descendantDestroyListener).toHaveBeenCalledTimes(1); - }); - })); + expect(elementDestroyListener).toHaveBeenCalledTimes(1); + expect(descendantDestroyListener).toHaveBeenCalledTimes(1); + }); + })); - fixmeIvy('FW-713: ngDestroy not being called when downgraded ng2 component is destroyed') - .it('should clear data on `$element` and descendants', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng1ComponentElement: angular.IAugmentedJQuery; - let ng2ComponentAInstance: Ng2ComponentA; + it('should clear data on `$element` and descendants', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng1ComponentElement: angular.IAugmentedJQuery; + let ng2ComponentAInstance: Ng2ComponentA; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - controller: class { - constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - this.$element.data !('test', 1); - this.$element.contents !().data !('test', 2); + // Define `ng1Component` + const ng1Component: angular.IComponent = { + controller: class { + constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { + this.$element.data !('test', 1); + this.$element.contents !().data !('test', 2); - ng1ComponentElement = this.$element; - } - }, - template: '
' - }; + ng1ComponentElement = this.$element; + } + }, + template: '
' + }; - // Define `Ng2Component` - @Component({selector: 'ng2A', template: ''}) - class Ng2ComponentA { - destroyIt = false; + // Define `Ng2Component` + @Component({selector: 'ng2A', template: ''}) + class Ng2ComponentA { + destroyIt = false; - constructor() { ng2ComponentAInstance = this; } - } + constructor() { ng2ComponentAInstance = this; } + } - @Component({selector: 'ng2B', template: ''}) - class Ng2ComponentB { - } + @Component({selector: 'ng2B', template: ''}) + class Ng2ComponentB { + } - // Define `ng1Module` - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); + // Define `ng1Module` + angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); - // Define `Ng2Module` - @NgModule({ - declarations: - [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB], - entryComponents: [Ng2ComponentA], - imports: [BrowserModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + // Define `Ng2Module` + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB], + entryComponents: [Ng2ComponentA], + imports: [BrowserModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready((ref) => { - const $rootScope = ref.ng1RootScope as any; - tick(); - $rootScope.$digest(); - expect(ng1ComponentElement.data !('test')).toBe(1); - expect(ng1ComponentElement.contents !().data !('test')).toBe(2); + adapter.bootstrap(element, ['ng1Module']).ready((ref) => { + const $rootScope = ref.ng1RootScope as any; + tick(); + $rootScope.$digest(); + expect(ng1ComponentElement.data !('test')).toBe(1); + expect(ng1ComponentElement.contents !().data !('test')).toBe(2); - ng2ComponentAInstance.destroyIt = true; - tick(); - $rootScope.$digest(); + ng2ComponentAInstance.destroyIt = true; + tick(); + $rootScope.$digest(); - expect(ng1ComponentElement.data !('test')).toBeUndefined(); - expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined(); - }); - })); + expect(ng1ComponentElement.data !('test')).toBeUndefined(); + expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined(); + }); + })); - fixmeIvy('FW-713: ngDestroy not being called when downgraded ng2 component is destroyed') - .it('should clear dom listeners on `$element` and descendants`', fakeAsync(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const elementClickListener = jasmine.createSpy('elementClickListener'); - const descendantClickListener = jasmine.createSpy('descendantClickListener'); - let ng1DescendantElement: angular.IAugmentedJQuery; - let ng2ComponentAInstance: Ng2ComponentA; + it('should clear dom listeners on `$element` and descendants`', fakeAsync(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const elementClickListener = jasmine.createSpy('elementClickListener'); + const descendantClickListener = jasmine.createSpy('descendantClickListener'); + let ng1DescendantElement: angular.IAugmentedJQuery; + let ng2ComponentAInstance: Ng2ComponentA; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - controller: class { - constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - ng1DescendantElement = this.$element.contents !(); + // Define `ng1Component` + const ng1Component: angular.IComponent = { + controller: class { + constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { + ng1DescendantElement = this.$element.contents !(); - this.$element.on !('click', elementClickListener); - ng1DescendantElement.on !('click', descendantClickListener); - } - }, - template: '
' - }; + this.$element.on !('click', elementClickListener); + ng1DescendantElement.on !('click', descendantClickListener); + } + }, + template: '
' + }; - // Define `Ng2Component` - @Component({selector: 'ng2A', template: ''}) - class Ng2ComponentA { - destroyIt = false; + // Define `Ng2Component` + @Component({selector: 'ng2A', template: ''}) + class Ng2ComponentA { + destroyIt = false; - constructor() { ng2ComponentAInstance = this; } - } + constructor() { ng2ComponentAInstance = this; } + } - @Component({selector: 'ng2B', template: ''}) - class Ng2ComponentB { - } + @Component({selector: 'ng2B', template: ''}) + class Ng2ComponentB { + } - // Define `ng1Module` - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); + // Define `ng1Module` + angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); - // Define `Ng2Module` - @NgModule({ - declarations: - [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB], - entryComponents: [Ng2ComponentA], - imports: [BrowserModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + // Define `Ng2Module` + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB], + entryComponents: [Ng2ComponentA], + imports: [BrowserModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready((ref) => { - const $rootScope = ref.ng1RootScope as any; - tick(); - $rootScope.$digest(); - (ng1DescendantElement[0] as HTMLElement).click(); - expect(elementClickListener).toHaveBeenCalledTimes(1); - expect(descendantClickListener).toHaveBeenCalledTimes(1); + adapter.bootstrap(element, ['ng1Module']).ready((ref) => { + const $rootScope = ref.ng1RootScope as any; + tick(); + $rootScope.$digest(); + (ng1DescendantElement[0] as HTMLElement).click(); + expect(elementClickListener).toHaveBeenCalledTimes(1); + expect(descendantClickListener).toHaveBeenCalledTimes(1); - ng2ComponentAInstance.destroyIt = true; - tick(); - $rootScope.$digest(); + ng2ComponentAInstance.destroyIt = true; + tick(); + $rootScope.$digest(); - (ng1DescendantElement[0] as HTMLElement).click(); - expect(elementClickListener).toHaveBeenCalledTimes(1); - expect(descendantClickListener).toHaveBeenCalledTimes(1); - }); - })); + (ng1DescendantElement[0] as HTMLElement).click(); + expect(elementClickListener).toHaveBeenCalledTimes(1); + expect(descendantClickListener).toHaveBeenCalledTimes(1); + }); + })); }); describe('linking', () => { - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should run the pre-linking after instantiating the controller', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const log: string[] = []; + it('should run the pre-linking after instantiating the controller', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const log: string[] = []; - // Define `ng1Directive` - const ng1Directive: angular.IDirective = { - template: '', - link: {pre: () => log.push('ng1-pre')}, - controller: class {constructor() { log.push('ng1-ctrl'); }} - }; + // Define `ng1Directive` + const ng1Directive: angular.IDirective = { + template: '', + link: {pre: () => log.push('ng1-pre')}, + controller: class {constructor() { log.push('ng1-ctrl'); }} + }; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1', []) - .directive('ng1', () => ng1Directive) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1', []) + .directive('ng1', () => ng1Directive) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1']).ready(() => { - setTimeout(() => expect(log).toEqual(['ng1-ctrl', 'ng1-pre']), 1000); - }); - })); + adapter.bootstrap(element, ['ng1']).ready(() => { + setTimeout(() => expect(log).toEqual(['ng1-ctrl', 'ng1-pre']), 1000); + }); + })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should run the pre-linking function before linking', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const log: string[] = []; + it('should run the pre-linking function before linking', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const log: string[] = []; - // Define `ng1Directive` - const ng1DirectiveA: angular.IDirective = { - template: '', - link: {pre: () => log.push('ng1A-pre')} - }; + // Define `ng1Directive` + const ng1DirectiveA: angular.IDirective = { + template: '', + link: {pre: () => log.push('ng1A-pre')} + }; - const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; + const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1', []) - .directive('ng1A', () => ng1DirectiveA) - .directive('ng1B', () => ng1DirectiveB) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1', []) + .directive('ng1A', () => ng1DirectiveA) + .directive('ng1B', () => ng1DirectiveB) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1']).ready(() => { - expect(log).toEqual(['ng1A-pre', 'ng1B-post']); - }); - })); + adapter.bootstrap(element, ['ng1']).ready(() => { + expect(log).toEqual(['ng1A-pre', 'ng1B-post']); + }); + })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should run the post-linking function after linking (link: object)', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const log: string[] = []; + it('should run the post-linking function after linking (link: object)', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const log: string[] = []; - // Define `ng1Directive` - const ng1DirectiveA: angular.IDirective = { - template: '', - link: {post: () => log.push('ng1A-post')} - }; + // Define `ng1Directive` + const ng1DirectiveA: angular.IDirective = { + template: '', + link: {post: () => log.push('ng1A-post')} + }; - const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; + const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1', []) - .directive('ng1A', () => ng1DirectiveA) - .directive('ng1B', () => ng1DirectiveB) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1', []) + .directive('ng1A', () => ng1DirectiveA) + .directive('ng1B', () => ng1DirectiveB) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1']).ready(() => { - expect(log).toEqual(['ng1B-post', 'ng1A-post']); - }); - })); + adapter.bootstrap(element, ['ng1']).ready(() => { + expect(log).toEqual(['ng1B-post', 'ng1A-post']); + }); + })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should run the post-linking function after linking (link: function)', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const log: string[] = []; + it('should run the post-linking function after linking (link: function)', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const log: string[] = []; - // Define `ng1Directive` - const ng1DirectiveA: angular.IDirective = { - template: '', - link: () => log.push('ng1A-post') - }; + // Define `ng1Directive` + const ng1DirectiveA: angular.IDirective = { + template: '', + link: () => log.push('ng1A-post') + }; - const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; + const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1', []) - .directive('ng1A', () => ng1DirectiveA) - .directive('ng1B', () => ng1DirectiveB) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1', []) + .directive('ng1A', () => ng1DirectiveA) + .directive('ng1B', () => ng1DirectiveB) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1A'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1']).ready(() => { - expect(log).toEqual(['ng1B-post', 'ng1A-post']); - }); - })); + adapter.bootstrap(element, ['ng1']).ready(() => { + expect(log).toEqual(['ng1B-post', 'ng1A-post']); + }); + })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should run the post-linking function before `$postLink`', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const log: string[] = []; + it('should run the post-linking function before `$postLink`', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const log: string[] = []; - // Define `ng1Directive` - const ng1Directive: angular.IDirective = { - template: '', - link: () => log.push('ng1-post'), - controller: class {$postLink() { log.push('ng1-$post'); }} - }; + // Define `ng1Directive` + const ng1Directive: angular.IDirective = { + template: '', + link: () => log.push('ng1-post'), + controller: class {$postLink() { log.push('ng1-$post'); }} + }; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1', []) - .directive('ng1', () => ng1Directive) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1', []) + .directive('ng1', () => ng1Directive) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1']).ready(() => { - expect(log).toEqual(['ng1-post', 'ng1-$post']); - }); - })); + adapter.bootstrap(element, ['ng1']).ready(() => { + expect(log).toEqual(['ng1-post', 'ng1-$post']); + }); + })); }); describe('transclusion', () => { @@ -2727,25 +2678,24 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support single-slot transclusion with fallback content', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng1ControllerInstances: any[] = []; - let ng2ComponentInstance: Ng2Component; + it('should support single-slot transclusion with fallback content', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng1ControllerInstances: any[] = []; + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: 'ng1(
{{ $ctrl.value }}
)', - transclude: true, - controller: class { - value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); } - } - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: 'ng1(
{{ $ctrl.value }}
)', + transclude: true, + controller: class { + value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); } + } + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2(
{{ value }}
| @@ -2754,58 +2704,56 @@ withEachNg1Version(() => { )` - }) - class Ng2Component { - value = 'from-ng2'; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + value = 'from-ng2'; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(from-ng2)|ng1(from-ng2)|ng1(from-ng1))'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(from-ng2)|ng1(from-ng2)|ng1(from-ng1))'); - ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-foo'); - ng2ComponentInstance.value = 'ng2-bar'; - $digest(ref); + ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-foo'); + ng2ComponentInstance.value = 'ng2-bar'; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(ng2-bar)|ng1(ng2-bar)|ng1(ng1-foo))'); - }); - })); + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(ng2-bar)|ng1(ng2-bar)|ng1(ng1-foo))'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support multi-slot transclusion', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng2ComponentInstance: Ng2Component; + it('should support multi-slot transclusion', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: - 'ng1(x(
) | y(
))', - transclude: {slotX: 'contentX', slotY: 'contentY'} - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: + 'ng1(x(
) | y(
))', + transclude: {slotX: 'contentX', slotY: 'contentY'} + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2( {{ x }}1 @@ -2814,64 +2762,60 @@ withEachNg1Version(() => { {{ y }}2 )` - }) - class Ng2Component { - x = 'foo'; - y = 'bar'; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + x = 'foo'; + y = 'bar'; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(foo1foo2)|y(bar1bar2)))'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(x(foo1foo2)|y(bar1bar2)))'); - ng2ComponentInstance.x = 'baz'; - ng2ComponentInstance.y = 'qux'; - $digest(ref); + ng2ComponentInstance.x = 'baz'; + ng2ComponentInstance.y = 'qux'; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(baz1baz2)|y(qux1qux2)))'); - }); - })); + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(x(baz1baz2)|y(qux1qux2)))'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support default slot (with fallback content)', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng1ControllerInstances: any[] = []; - let ng2ComponentInstance: Ng2Component; + it('should support default slot (with fallback content)', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng1ControllerInstances: any[] = []; + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: - 'ng1(default(
fallback-{{ $ctrl.value }}
))', - transclude: {slotX: 'contentX', slotY: 'contentY'}, - controller: class { - value = 'ng1'; constructor() { ng1ControllerInstances.push(this); } - } - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: 'ng1(default(
fallback-{{ $ctrl.value }}
))', + transclude: {slotX: 'contentX', slotY: 'contentY'}, + controller: + class {value = 'ng1'; constructor() { ng1ControllerInstances.push(this); }} + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2( ({{ x }}) @@ -2892,155 +2836,151 @@ withEachNg1Version(() => { --> {{ x }}ignored x{{ y + x }}ignored y{{ y }} )` - }) - class Ng2Component { - x = 'foo'; - y = 'bar'; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + x = 'foo'; + y = 'bar'; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(multiTrim(element.textContent, true)) - .toBe( - 'ng2(ng1(default((foo)foo-bar(bar)))|ng1(default(fallback-ng1))|ng1(default(foobarfoobar)))'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(multiTrim(element.textContent, true)) + .toBe( + 'ng2(ng1(default((foo)foo-bar(bar)))|ng1(default(fallback-ng1))|ng1(default(foobarfoobar)))'); - ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-plus'); - ng2ComponentInstance.x = 'baz'; - ng2ComponentInstance.y = 'qux'; - $digest(ref); + ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-plus'); + ng2ComponentInstance.x = 'baz'; + ng2ComponentInstance.y = 'qux'; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe( - 'ng2(ng1(default((baz)baz-qux(qux)))|ng1(default(fallback-ng1-plus))|ng1(default(bazquxbazqux)))'); - }); - })); + expect(multiTrim(element.textContent, true)) + .toBe( + 'ng2(ng1(default((baz)baz-qux(qux)))|ng1(default(fallback-ng1-plus))|ng1(default(bazquxbazqux)))'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support optional transclusion slots (with fallback content)', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng1ControllerInstances: any[] = []; - let ng2ComponentInstance: Ng2Component; + it('should support optional transclusion slots (with fallback content)', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng1ControllerInstances: any[] = []; + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: ` + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: ` ng1( x(
{{ $ctrl.x }}
) | y(
{{ $ctrl.y }}
) )`, - transclude: {slotX: '?contentX', slotY: '?contentY'}, - controller: class { - x = 'ng1X'; y = 'ng1Y'; constructor() { ng1ControllerInstances.push(this); } - } - }; + transclude: {slotX: '?contentX', slotY: '?contentY'}, + controller: class { + x = 'ng1X'; y = 'ng1Y'; constructor() { ng1ControllerInstances.push(this); } + } + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2( {{ x }} | {{ y }} )` - }) - class Ng2Component { - x = 'ng2X'; - y = 'ng2Y'; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + x = 'ng2X'; + y = 'ng2Y'; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(ng2X)|y(ng1Y))|ng1(x(ng1X)|y(ng2Y)))'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(x(ng2X)|y(ng1Y))|ng1(x(ng1X)|y(ng2Y)))'); - ng1ControllerInstances.forEach(ctrl => { - ctrl.x = 'ng1X-foo'; - ctrl.y = 'ng1Y-bar'; - }); - ng2ComponentInstance.x = 'ng2X-baz'; - ng2ComponentInstance.y = 'ng2Y-qux'; - $digest(ref); + ng1ControllerInstances.forEach(ctrl => { + ctrl.x = 'ng1X-foo'; + ctrl.y = 'ng1Y-bar'; + }); + ng2ComponentInstance.x = 'ng2X-baz'; + ng2ComponentInstance.y = 'ng2Y-qux'; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(ng2X-baz)|y(ng1Y-bar))|ng1(x(ng1X-foo)|y(ng2Y-qux)))'); - }); - })); + expect(multiTrim(element.textContent, true)) + .toBe('ng2(ng1(x(ng2X-baz)|y(ng1Y-bar))|ng1(x(ng1X-foo)|y(ng2Y-qux)))'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should throw if a non-optional slot is not filled', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let errorMessage: string; + it('should throw if a non-optional slot is not filled', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let errorMessage: string; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: '', - transclude: {slotX: '?contentX', slotY: 'contentY'} - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: '', + transclude: {slotX: '?contentX', slotY: 'contentY'} + }; - // Define `Ng2Component` - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - } + // Define `Ng2Component` + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .value($EXCEPTION_HANDLER, (error: Error) => errorMessage = error.message) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = + angular.module('ng1Module', []) + .value($EXCEPTION_HANDLER, (error: Error) => errorMessage = error.message) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(errorMessage) - .toContain('Required transclusion slot \'slotY\' on directive: ng1'); - }); - })); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(errorMessage) + .toContain('Required transclusion slot \'slotY\' on directive: ng1'); + }); + })); fixmeIvy('FW-714: ng1 projected content is not being rendered') .it('should support structural directives in transcluded content', async(() => { @@ -3114,7 +3054,7 @@ withEachNg1Version(() => { }); fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') + 'FW-844: Directive input bindings cannot be assigned after the `@Directive` decorator has been compiled') .it('should bind input properties (<) of components', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module('ng1', []); @@ -3148,39 +3088,37 @@ withEachNg1Version(() => { }); })); - fixmeIvy( - 'FW-812: Life-cycle hooks not correctly wired up for components that return a different instance from their constructor') - .it('should support ng2 > ng1 > ng2', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []); + it('should support ng2 > ng1 > ng2', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []); - const ng1 = { - template: 'ng1()', - }; - ng1Module.component('ng1', ng1); + const ng1 = { + template: 'ng1()', + }; + ng1Module.component('ng1', ng1); - @Component({selector: 'ng2a', template: 'ng2a()'}) - class Ng2a { - } - ng1Module.directive('ng2a', adapter.downgradeNg2Component(Ng2a)); + @Component({selector: 'ng2a', template: 'ng2a()'}) + class Ng2a { + } + ng1Module.directive('ng2a', adapter.downgradeNg2Component(Ng2a)); - @Component({selector: 'ng2b', template: 'ng2b'}) - class Ng2b { - } - ng1Module.directive('ng2b', adapter.downgradeNg2Component(Ng2b)); + @Component({selector: 'ng2b', template: 'ng2b'}) + class Ng2b { + } + ng1Module.directive('ng2b', adapter.downgradeNg2Component(Ng2b)); - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
`); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent)).toEqual('ng2a(ng1(ng2b))'); - }); - })); + const element = html(`
`); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual('ng2a(ng1(ng2b))'); + }); + })); }); describe('injection', () => {