refactor: move angular source to /packages rather than modules/@angular
This commit is contained in:
52
packages/upgrade/test/common/component_info_spec.ts
Normal file
52
packages/upgrade/test/common/component_info_spec.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @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 {PropertyBinding} from '@angular/upgrade/src/common/component_info';
|
||||
|
||||
export function main() {
|
||||
describe('PropertyBinding', () => {
|
||||
it('should process a simple binding', () => {
|
||||
const binding = new PropertyBinding('someBinding');
|
||||
expect(binding.binding).toEqual('someBinding');
|
||||
expect(binding.prop).toEqual('someBinding');
|
||||
expect(binding.attr).toEqual('someBinding');
|
||||
expect(binding.bracketAttr).toEqual('[someBinding]');
|
||||
expect(binding.bracketParenAttr).toEqual('[(someBinding)]');
|
||||
expect(binding.parenAttr).toEqual('(someBinding)');
|
||||
expect(binding.onAttr).toEqual('onSomeBinding');
|
||||
expect(binding.bindAttr).toEqual('bindSomeBinding');
|
||||
expect(binding.bindonAttr).toEqual('bindonSomeBinding');
|
||||
});
|
||||
|
||||
it('should process a two-part binding', () => {
|
||||
const binding = new PropertyBinding('someProp:someAttr');
|
||||
expect(binding.binding).toEqual('someProp:someAttr');
|
||||
expect(binding.prop).toEqual('someProp');
|
||||
expect(binding.attr).toEqual('someAttr');
|
||||
expect(binding.bracketAttr).toEqual('[someAttr]');
|
||||
expect(binding.bracketParenAttr).toEqual('[(someAttr)]');
|
||||
expect(binding.parenAttr).toEqual('(someAttr)');
|
||||
expect(binding.onAttr).toEqual('onSomeAttr');
|
||||
expect(binding.bindAttr).toEqual('bindSomeAttr');
|
||||
expect(binding.bindonAttr).toEqual('bindonSomeAttr');
|
||||
});
|
||||
|
||||
it('should cope with whitespace', () => {
|
||||
const binding = new PropertyBinding(' someProp : someAttr ');
|
||||
expect(binding.binding).toEqual(' someProp : someAttr ');
|
||||
expect(binding.prop).toEqual('someProp');
|
||||
expect(binding.attr).toEqual('someAttr');
|
||||
expect(binding.bracketAttr).toEqual('[someAttr]');
|
||||
expect(binding.bracketParenAttr).toEqual('[(someAttr)]');
|
||||
expect(binding.parenAttr).toEqual('(someAttr)');
|
||||
expect(binding.onAttr).toEqual('onSomeAttr');
|
||||
expect(binding.bindAttr).toEqual('bindSomeAttr');
|
||||
expect(binding.bindonAttr).toEqual('bindonSomeAttr');
|
||||
});
|
||||
});
|
||||
}
|
25
packages/upgrade/test/common/downgrade_injectable_spec.ts
Normal file
25
packages/upgrade/test/common/downgrade_injectable_spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @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 {INJECTOR_KEY} from '@angular/upgrade/src/common/constants';
|
||||
import {downgradeInjectable} from '@angular/upgrade/src/common/downgrade_injectable';
|
||||
|
||||
export function main() {
|
||||
describe('downgradeInjectable', () => {
|
||||
it('should return an AngularJS annotated factory for the token', () => {
|
||||
const factory = downgradeInjectable('someToken');
|
||||
expect(factory).toEqual(jasmine.any(Function));
|
||||
expect((factory as any).$inject).toEqual([INJECTOR_KEY]);
|
||||
|
||||
const injector = {get: jasmine.createSpy('get').and.returnValue('service value')};
|
||||
const value = factory(injector);
|
||||
expect(injector.get).toHaveBeenCalledWith('someToken');
|
||||
expect(value).toEqual('service value');
|
||||
});
|
||||
});
|
||||
}
|
25
packages/upgrade/test/common/test_helpers.ts
Normal file
25
packages/upgrade/test/common/test_helpers.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export function html(html: string): Element {
|
||||
// Don't return `body` itself, because using it as a `$rootElement` for ng1
|
||||
// will attach `$injector` to it and that will affect subsequent tests.
|
||||
const body = document.body;
|
||||
body.innerHTML = `<div>${html.trim()}</div>`;
|
||||
const div = document.body.firstChild as Element;
|
||||
|
||||
if (div.childNodes.length === 1 && div.firstChild instanceof HTMLElement) {
|
||||
return div.firstChild;
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
export function multiTrim(text: string): string {
|
||||
return text.replace(/\n/g, '').replace(/\s\s+/g, ' ').trim();
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @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 {DynamicContentProjectionHelper} from '@angular/upgrade/src/dynamic/content_projection_helper';
|
||||
import {nodes} from './test_helpers';
|
||||
|
||||
|
||||
export function main() {
|
||||
describe('groupNodesBySelector', () => {
|
||||
let groupNodesBySelector: (ngContentSelectors: string[], nodes: Node[]) => Node[][];
|
||||
|
||||
beforeEach(() => {
|
||||
const projectionHelper = new DynamicContentProjectionHelper();
|
||||
groupNodesBySelector = projectionHelper.groupNodesBySelector.bind(projectionHelper);
|
||||
});
|
||||
|
||||
|
||||
it('should return an array of node collections for each selector', () => {
|
||||
const contentNodes = nodes(
|
||||
'<div class="x"><span>div-1 content</span></div>' +
|
||||
'<input type="number" name="myNum">' +
|
||||
'<input type="date" name="myDate">' +
|
||||
'<span>span content</span>' +
|
||||
'<div class="x"><span>div-2 content</span></div>');
|
||||
|
||||
const selectors = ['input[type=date]', 'span', '.x'];
|
||||
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
||||
|
||||
expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">'));
|
||||
expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>'));
|
||||
expect(projectableNodes[2])
|
||||
.toEqual(nodes(
|
||||
'<div class="x"><span>div-1 content</span></div>' +
|
||||
'<div class="x"><span>div-2 content</span></div>'));
|
||||
});
|
||||
|
||||
it('should collect up unmatched nodes for the wildcard selector', () => {
|
||||
const contentNodes = nodes(
|
||||
'<div class="x"><span>div-1 content</span></div>' +
|
||||
'<input type="number" name="myNum">' +
|
||||
'<input type="date" name="myDate">' +
|
||||
'<span>span content</span>' +
|
||||
'<div class="x"><span>div-2 content</span></div>');
|
||||
|
||||
const selectors = ['.x', '*', 'input[type=date]'];
|
||||
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
||||
|
||||
expect(projectableNodes[0])
|
||||
.toEqual(nodes(
|
||||
'<div class="x"><span>div-1 content</span></div>' +
|
||||
'<div class="x"><span>div-2 content</span></div>'));
|
||||
expect(projectableNodes[1])
|
||||
.toEqual(nodes(
|
||||
'<input type="number" name="myNum">' +
|
||||
'<span>span content</span>'));
|
||||
expect(projectableNodes[2]).toEqual(nodes('<input type="date" name="myDate">'));
|
||||
});
|
||||
|
||||
it('should return an array of empty arrays if there are no nodes passed in', () => {
|
||||
const selectors = ['.x', '*', 'input[type=date]'];
|
||||
const projectableNodes = groupNodesBySelector(selectors, []);
|
||||
expect(projectableNodes).toEqual([[], [], []]);
|
||||
});
|
||||
|
||||
it('should return an empty array for each selector that does not match', () => {
|
||||
const contentNodes = nodes(
|
||||
'<div class="x"><span>div-1 content</span></div>' +
|
||||
'<input type="number" name="myNum">' +
|
||||
'<input type="date" name="myDate">' +
|
||||
'<span>span content</span>' +
|
||||
'<div class="x"><span>div-2 content</span></div>');
|
||||
|
||||
const noSelectorNodes = groupNodesBySelector([], contentNodes);
|
||||
expect(noSelectorNodes).toEqual([]);
|
||||
|
||||
const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes);
|
||||
expect(noMatchSelectorNodes).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
}
|
15
packages/upgrade/test/dynamic/test_helpers.ts
Normal file
15
packages/upgrade/test/dynamic/test_helpers.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export * from '../common/test_helpers';
|
||||
|
||||
export function nodes(html: string) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = html.trim();
|
||||
return Array.prototype.slice.call(div.childNodes);
|
||||
}
|
1922
packages/upgrade/test/dynamic/upgrade_spec.ts
Normal file
1922
packages/upgrade/test/dynamic/upgrade_spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
58
packages/upgrade/test/static/angular1_providers_spec.ts
Normal file
58
packages/upgrade/test/static/angular1_providers_spec.ts
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @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 {Ng1Token} from '@angular/upgrade/src/common/angular1';
|
||||
import {compileFactory, injectorFactory, parseFactory, rootScopeFactory, setTempInjectorRef} from '@angular/upgrade/src/static/angular1_providers';
|
||||
|
||||
export function main() {
|
||||
describe('upgrade angular1_providers', () => {
|
||||
describe('compileFactory', () => {
|
||||
it('should retrieve and return `$compile`', () => {
|
||||
const services: {[key: string]: any} = {$compile: 'foo'};
|
||||
const mockInjector = {get: (name: Ng1Token): any => services[name], has: () => true};
|
||||
|
||||
expect(compileFactory(mockInjector)).toBe('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('injectorFactory', () => {
|
||||
it('should return the injector value that was previously set', () => {
|
||||
const mockInjector = {get: () => {}, has: () => false};
|
||||
setTempInjectorRef(mockInjector);
|
||||
const injector = injectorFactory();
|
||||
expect(injector).toBe(mockInjector);
|
||||
});
|
||||
|
||||
it('should unset the injector after the first call (to prevent memory leaks)', () => {
|
||||
const mockInjector = {get: () => {}, has: () => false};
|
||||
setTempInjectorRef(mockInjector);
|
||||
injectorFactory();
|
||||
const injector = injectorFactory();
|
||||
expect(injector).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseFactory', () => {
|
||||
it('should retrieve and return `$parse`', () => {
|
||||
const services: {[key: string]: any} = {$parse: 'bar'};
|
||||
const mockInjector = {get: (name: Ng1Token): any => services[name], has: () => true};
|
||||
|
||||
expect(parseFactory(mockInjector)).toBe('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rootScopeFactory', () => {
|
||||
it('should retrieve and return `$rootScope`', () => {
|
||||
const services: {[key: string]: any} = {$rootScope: 'baz'};
|
||||
const mockInjector = {get: (name: Ng1Token): any => services[name], has: () => true};
|
||||
|
||||
expect(rootScopeFactory(mockInjector)).toBe('baz');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @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, ElementRef, Injector, Input, NgModule, NgZone, SimpleChange, SimpleChanges, destroyPlatform} from '@angular/core';
|
||||
import {async} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static';
|
||||
|
||||
import {bootstrap, html} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('scope/component change-detection', () => {
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
it('should interleave scope and component expressions', async(() => {
|
||||
const log: any[] /** TODO #9100 */ = [];
|
||||
const l = (value: any /** TODO #9100 */) => {
|
||||
log.push(value);
|
||||
return value + ';';
|
||||
};
|
||||
|
||||
@Directive({selector: 'ng1a'})
|
||||
class Ng1aComponent extends UpgradeComponent {
|
||||
constructor(elementRef: ElementRef, injector: Injector) {
|
||||
super('ng1a', elementRef, injector);
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({selector: 'ng1b'})
|
||||
class Ng1bComponent extends UpgradeComponent {
|
||||
constructor(elementRef: ElementRef, injector: Injector) {
|
||||
super('ng1b', elementRef, injector);
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ng2',
|
||||
template: `{{l('2A')}}<ng1a></ng1a>{{l('2B')}}<ng1b></ng1b>{{l('2C')}}`
|
||||
})
|
||||
class Ng2Component {
|
||||
l: (value: any) => string;
|
||||
constructor() { this.l = l; }
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [Ng1aComponent, Ng1bComponent, Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module = angular.module('ng1', [])
|
||||
.directive('ng1a', () => ({template: '{{ l(\'ng1a\') }}'}))
|
||||
.directive('ng1b', () => ({template: '{{ l(\'ng1b\') }}'}))
|
||||
.directive('ng2', downgradeComponent({component: Ng2Component}))
|
||||
.run(($rootScope: any /** TODO #9100 */) => {
|
||||
$rootScope.l = l;
|
||||
$rootScope.reset = () => log.length = 0;
|
||||
});
|
||||
|
||||
const element =
|
||||
html('<div>{{reset(); l(\'1A\');}}<ng2>{{l(\'1B\')}}</ng2>{{l(\'1C\')}}</div>');
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(document.body.textContent).toEqual('1A;2A;ng1a;2B;ng1b;2C;1C;');
|
||||
// https://github.com/angular/angular.js/issues/12983
|
||||
expect(log).toEqual(['1A', '1B', '1C', '2A', '2B', '2C', 'ng1a', 'ng1b']);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should propagate changes to a downgraded component inside the ngZone', async(() => {
|
||||
let appComponent: AppComponent;
|
||||
|
||||
@Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'})
|
||||
class AppComponent {
|
||||
value: number;
|
||||
constructor() { appComponent = this; }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'my-child',
|
||||
template: '<div>{{valueFromPromise}}',
|
||||
})
|
||||
class ChildComponent {
|
||||
valueFromPromise: number;
|
||||
@Input()
|
||||
set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); }
|
||||
|
||||
constructor(private zone: NgZone) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['value'].isFirstChange()) return;
|
||||
|
||||
this.zone.onMicrotaskEmpty.subscribe(
|
||||
() => { expect(element.textContent).toEqual('5'); });
|
||||
|
||||
Promise.resolve().then(() => this.valueFromPromise = changes['value'].currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, ChildComponent],
|
||||
entryComponents: [AppComponent],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module = angular.module('ng1', []).directive(
|
||||
'myApp', downgradeComponent({component: AppComponent}));
|
||||
|
||||
|
||||
const element = html('<my-app></my-app>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
appComponent.value = 5;
|
||||
});
|
||||
}));
|
||||
|
||||
// This test demonstrates https://github.com/angular/angular/issues/6385
|
||||
// which was invalidly fixed by https://github.com/angular/angular/pull/6386
|
||||
// it('should not trigger $digest from an async operation in a watcher', async(() => {
|
||||
// @Component({selector: 'my-app', template: ''})
|
||||
// class AppComponent {
|
||||
// }
|
||||
|
||||
// @NgModule({declarations: [AppComponent], imports: [BrowserModule]})
|
||||
// class Ng2Module {
|
||||
// }
|
||||
|
||||
// const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||
// const ng1Module = angular.module('ng1', []).directive(
|
||||
// 'myApp', adapter.downgradeNg2Component(AppComponent));
|
||||
|
||||
// const element = html('<my-app></my-app>');
|
||||
|
||||
// adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||
// let doTimeout = false;
|
||||
// let timeoutId: number;
|
||||
// ref.ng1RootScope.$watch(() => {
|
||||
// if (doTimeout && !timeoutId) {
|
||||
// timeoutId = window.setTimeout(function() {
|
||||
// timeoutId = null;
|
||||
// }, 10);
|
||||
// }
|
||||
// });
|
||||
// doTimeout = true;
|
||||
// });
|
||||
// }));
|
||||
});
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @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, ElementRef, Injector, Input, NgModule, destroyPlatform} from '@angular/core';
|
||||
import {async} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static';
|
||||
|
||||
import {bootstrap, html, multiTrim} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('content projection', () => {
|
||||
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
it('should instantiate ng2 in ng1 template and project content', async(() => {
|
||||
|
||||
// the ng2 component that will be used in ng1 (downgraded)
|
||||
@Component({selector: 'ng2', template: `{{ prop }}(<ng-content></ng-content>)`})
|
||||
class Ng2Component {
|
||||
prop = 'NG2';
|
||||
ngContent = 'ng2-content';
|
||||
}
|
||||
|
||||
// our upgrade module to host the component to downgrade
|
||||
@NgModule({
|
||||
imports: [BrowserModule, UpgradeModule],
|
||||
declarations: [Ng2Component],
|
||||
entryComponents: [Ng2Component]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
// the ng1 app module that will consume the downgraded component
|
||||
const ng1Module = angular
|
||||
.module('ng1', [])
|
||||
// create an ng1 facade of the ng2 component
|
||||
.directive('ng2', downgradeComponent({component: Ng2Component}))
|
||||
.run(($rootScope: angular.IRootScopeService) => {
|
||||
$rootScope['prop'] = 'NG1';
|
||||
$rootScope['ngContent'] = 'ng1-content';
|
||||
});
|
||||
|
||||
const element = html('<div>{{ \'ng1[\' }}<ng2>~{{ ngContent }}~</ng2>{{ \']\' }}</div>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(document.body.textContent).toEqual('ng1[NG2(~ng1-content~)]');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should correctly project structural directives', async(() => {
|
||||
@Component({selector: 'ng2', template: 'ng2-{{ itemId }}(<ng-content></ng-content>)'})
|
||||
class Ng2Component {
|
||||
@Input() itemId: string;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, UpgradeModule],
|
||||
declarations: [Ng2Component],
|
||||
entryComponents: [Ng2Component]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module =
|
||||
angular.module('ng1', [])
|
||||
.directive(
|
||||
'ng2', downgradeComponent({component: Ng2Component, inputs: ['itemId']}))
|
||||
.run(($rootScope: angular.IRootScopeService) => {
|
||||
$rootScope['items'] = [
|
||||
{id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]},
|
||||
{id: 'c', subitems: [7, 8, 9]}
|
||||
];
|
||||
});
|
||||
|
||||
const element = html(`
|
||||
<ng2 ng-repeat="item in items" [item-id]="item.id">
|
||||
<div ng-repeat="subitem in item.subitems">{{ subitem }}</div>
|
||||
</ng2>
|
||||
`);
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => {
|
||||
expect(multiTrim(document.body.textContent))
|
||||
.toBe('ng2-a( 123 )ng2-b( 456 )ng2-c( 789 )');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should instantiate ng1 in ng2 template and project content', async(() => {
|
||||
|
||||
@Component({
|
||||
selector: 'ng2',
|
||||
template: `{{ 'ng2(' }}<ng1>{{ transclude }}</ng1>{{ ')' }}`,
|
||||
})
|
||||
class Ng2Component {
|
||||
prop = 'ng2';
|
||||
transclude = 'ng2-transclude';
|
||||
}
|
||||
|
||||
@Directive({selector: 'ng1'})
|
||||
class Ng1WrapperComponent extends UpgradeComponent {
|
||||
constructor(elementRef: ElementRef, injector: Injector) {
|
||||
super('ng1', elementRef, injector);
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [Ng1WrapperComponent, Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module =
|
||||
angular.module('ng1', [])
|
||||
.directive('ng1', () => ({
|
||||
transclude: true,
|
||||
template: '{{ prop }}(<ng-transclude></ng-transclude>)'
|
||||
}))
|
||||
.directive('ng2', downgradeComponent({component: Ng2Component}))
|
||||
.run(($rootScope: angular.IRootScopeService) => {
|
||||
$rootScope['prop'] = 'ng1';
|
||||
$rootScope['transclude'] = 'ng1-transclude';
|
||||
});
|
||||
|
||||
const element = html('<div>{{ \'ng1(\' }}<ng2></ng2>{{ \')\' }}</div>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(document.body.textContent).toEqual('ng1(ng2(ng1(ng2-transclude)))');
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
@ -0,0 +1,371 @@
|
||||
/**
|
||||
* @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, EventEmitter, NgModule, OnChanges, OnDestroy, SimpleChanges, destroyPlatform} from '@angular/core';
|
||||
import {async} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {UpgradeModule, downgradeComponent} from '@angular/upgrade/static';
|
||||
|
||||
import {$apply, bootstrap, html, multiTrim} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('downgrade ng2 component', () => {
|
||||
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
it('should bind properties, events', async(() => {
|
||||
const ng1Module =
|
||||
angular.module('ng1', []).value('$exceptionHandler', (err: any) => {
|
||||
throw err;
|
||||
}).run(($rootScope: angular.IScope) => {
|
||||
$rootScope['name'] = 'world';
|
||||
$rootScope['dataA'] = 'A';
|
||||
$rootScope['dataB'] = 'B';
|
||||
$rootScope['modelA'] = 'initModelA';
|
||||
$rootScope['modelB'] = 'initModelB';
|
||||
$rootScope['eventA'] = '?';
|
||||
$rootScope['eventB'] = '?';
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'ng2',
|
||||
inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'],
|
||||
outputs: [
|
||||
'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', 'twoWayBEmitter: twoWayBChange'
|
||||
],
|
||||
template: 'ignore: {{ignore}}; ' +
|
||||
'literal: {{literal}}; interpolate: {{interpolate}}; ' +
|
||||
'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' +
|
||||
'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})'
|
||||
})
|
||||
class Ng2Component implements OnChanges {
|
||||
ngOnChangesCount = 0;
|
||||
ignore = '-';
|
||||
literal = '?';
|
||||
interpolate = '?';
|
||||
oneWayA = '?';
|
||||
oneWayB = '?';
|
||||
twoWayA = '?';
|
||||
twoWayB = '?';
|
||||
eventA = new EventEmitter();
|
||||
eventB = new EventEmitter();
|
||||
twoWayAEmitter = new EventEmitter();
|
||||
twoWayBEmitter = new EventEmitter();
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
const assert = (prop: string, value: any) => {
|
||||
const propVal = (this as any)[prop];
|
||||
if (propVal != value) {
|
||||
throw new Error(`Expected: '${prop}' to be '${value}' but was '${propVal}'`);
|
||||
}
|
||||
};
|
||||
|
||||
const assertChange = (prop: string, value: any) => {
|
||||
assert(prop, value);
|
||||
if (!changes[prop]) {
|
||||
throw new Error(`Changes record for '${prop}' not found.`);
|
||||
}
|
||||
const actualValue = changes[prop].currentValue;
|
||||
if (actualValue != value) {
|
||||
throw new Error(
|
||||
`Expected changes record for'${prop}' to be '${value}' but was '${actualValue}'`);
|
||||
}
|
||||
};
|
||||
|
||||
switch (this.ngOnChangesCount++) {
|
||||
case 0:
|
||||
assert('ignore', '-');
|
||||
assertChange('literal', 'Text');
|
||||
assertChange('interpolate', 'Hello world');
|
||||
assertChange('oneWayA', 'A');
|
||||
assertChange('oneWayB', 'B');
|
||||
assertChange('twoWayA', 'initModelA');
|
||||
assertChange('twoWayB', 'initModelB');
|
||||
|
||||
this.twoWayAEmitter.emit('newA');
|
||||
this.twoWayBEmitter.emit('newB');
|
||||
this.eventA.emit('aFired');
|
||||
this.eventB.emit('bFired');
|
||||
break;
|
||||
case 1:
|
||||
assertChange('twoWayA', 'newA');
|
||||
assertChange('twoWayB', 'newB');
|
||||
break;
|
||||
case 2:
|
||||
assertChange('interpolate', 'Hello everyone');
|
||||
break;
|
||||
default:
|
||||
throw new Error('Called too many times! ' + JSON.stringify(changes));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ng1Module.directive(
|
||||
'ng2', downgradeComponent({
|
||||
component: Ng2Component,
|
||||
inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'],
|
||||
outputs: [
|
||||
'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange',
|
||||
'twoWayBEmitter: twoWayBChange'
|
||||
]
|
||||
}));
|
||||
|
||||
@NgModule({
|
||||
declarations: [Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const element = html(`
|
||||
<div>
|
||||
<ng2 literal="Text" interpolate="Hello {{name}}"
|
||||
bind-one-way-a="dataA" [one-way-b]="dataB"
|
||||
bindon-two-way-a="modelA" [(two-way-b)]="modelB"
|
||||
on-event-a='eventA=$event' (event-b)="eventB=$event"></ng2>
|
||||
| modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}};
|
||||
</div>`);
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(multiTrim(document.body.textContent))
|
||||
.toEqual(
|
||||
'ignore: -; ' +
|
||||
'literal: Text; interpolate: Hello world; ' +
|
||||
'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' +
|
||||
'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;');
|
||||
|
||||
$apply(upgrade, 'name = "everyone"');
|
||||
expect(multiTrim(document.body.textContent))
|
||||
.toEqual(
|
||||
'ignore: -; ' +
|
||||
'literal: Text; interpolate: Hello everyone; ' +
|
||||
'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | ' +
|
||||
'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should bind to ng-model', async(() => {
|
||||
const ng1Module = angular.module('ng1', []).run(
|
||||
($rootScope: angular.IScope) => { $rootScope['modelA'] = 'A'; });
|
||||
|
||||
let ng2Instance: Ng2;
|
||||
@Component({selector: 'ng2', template: '<span>{{_value}}</span>'})
|
||||
class Ng2 {
|
||||
private _value: any = '';
|
||||
private _onChangeCallback: (_: any) => void = () => {};
|
||||
constructor() { ng2Instance = this; }
|
||||
writeValue(value: any) { this._value = value; }
|
||||
registerOnChange(fn: any) { this._onChangeCallback = fn; }
|
||||
doChange(newValue: string) {
|
||||
this._value = newValue;
|
||||
this._onChangeCallback(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
ng1Module.directive('ng2', downgradeComponent({component: Ng2}));
|
||||
|
||||
const element = html(`<div><ng2 ng-model="modelA"></ng2> | {{modelA}}</div>`);
|
||||
|
||||
@NgModule(
|
||||
{declarations: [Ng2], entryComponents: [Ng2], imports: [BrowserModule, UpgradeModule]})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(Ng2Module).then((ref) => {
|
||||
const adapter = ref.injector.get(UpgradeModule) as UpgradeModule;
|
||||
adapter.bootstrap(element, [ng1Module.name]);
|
||||
const $rootScope = adapter.$injector.get('$rootScope');
|
||||
|
||||
expect(multiTrim(document.body.textContent)).toEqual('A | A');
|
||||
|
||||
$rootScope.modelA = 'B';
|
||||
$rootScope.$apply();
|
||||
expect(multiTrim(document.body.textContent)).toEqual('B | B');
|
||||
|
||||
ng2Instance.doChange('C');
|
||||
expect($rootScope.modelA).toBe('C');
|
||||
expect(multiTrim(document.body.textContent)).toEqual('C | C');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should properly run cleanup when ng1 directive is destroyed', async(() => {
|
||||
|
||||
let destroyed = false;
|
||||
@Component({selector: 'ng2', template: 'test'})
|
||||
class Ng2Component implements OnDestroy {
|
||||
ngOnDestroy() { destroyed = true; }
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module =
|
||||
angular.module('ng1', [])
|
||||
.directive(
|
||||
'ng1',
|
||||
() => { return {template: '<div ng-if="!destroyIt"><ng2></ng2></div>'}; })
|
||||
.directive('ng2', downgradeComponent({component: Ng2Component}));
|
||||
const element = html('<ng1></ng1>');
|
||||
platformBrowserDynamic().bootstrapModule(Ng2Module).then((ref) => {
|
||||
const adapter = ref.injector.get(UpgradeModule) as UpgradeModule;
|
||||
adapter.bootstrap(element, [ng1Module.name]);
|
||||
expect(element.textContent).toContain('test');
|
||||
expect(destroyed).toBe(false);
|
||||
|
||||
const $rootScope = adapter.$injector.get('$rootScope');
|
||||
$rootScope.$apply('destroyIt = true');
|
||||
|
||||
expect(element.textContent).not.toContain('test');
|
||||
expect(destroyed).toBe(true);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should work when compiled outside the dom (by fallback to the root ng2.injector)',
|
||||
async(() => {
|
||||
|
||||
@Component({selector: 'ng2', template: 'test'})
|
||||
class Ng2Component {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module =
|
||||
angular.module('ng1', [])
|
||||
.directive(
|
||||
'ng1',
|
||||
[
|
||||
'$compile',
|
||||
($compile: angular.ICompileService) => {
|
||||
return {
|
||||
link: function(
|
||||
$scope: angular.IScope, $element: angular.IAugmentedJQuery,
|
||||
$attrs: angular.IAttributes) {
|
||||
// here we compile some HTML that contains a downgraded component
|
||||
// since it is not currently in the DOM it is not able to "require"
|
||||
// an ng2 injector so it should use the `moduleInjector` instead.
|
||||
const compiled = $compile('<ng2></ng2>');
|
||||
const template = compiled($scope);
|
||||
$element.append(template);
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
.directive('ng2', downgradeComponent({component: Ng2Component}));
|
||||
|
||||
const element = html('<ng1></ng1>');
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
// the fact that the body contains the correct text means that the
|
||||
// downgraded component was able to access the moduleInjector
|
||||
// (since there is no other injector in this system)
|
||||
expect(multiTrim(document.body.textContent)).toEqual('test');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should allow attribute selectors for downgraded components', async(() => {
|
||||
@Component({selector: '[itWorks]', template: 'It works'})
|
||||
class WorksComponent {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [WorksComponent],
|
||||
entryComponents: [WorksComponent],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module = angular.module('ng1', []).directive(
|
||||
'worksComponent', downgradeComponent({component: WorksComponent}));
|
||||
|
||||
const element = html('<works-component></works-component>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(multiTrim(document.body.textContent)).toBe('It works');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should allow attribute selectors for components in ng2', async(() => {
|
||||
@Component({selector: '[itWorks]', template: 'It works'})
|
||||
class WorksComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'root-component', template: '<span itWorks></span>!'})
|
||||
class RootComponent {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [RootComponent, WorksComponent],
|
||||
entryComponents: [RootComponent],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module = angular.module('ng1', []).directive(
|
||||
'rootComponent', downgradeComponent({component: RootComponent}));
|
||||
|
||||
const element = html('<root-component></root-component>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
expect(multiTrim(document.body.textContent)).toBe('It works!');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should respect hierarchical dependency injection for ng2', async(() => {
|
||||
@Component({selector: 'parent', template: 'parent(<ng-content></ng-content>)'})
|
||||
class ParentComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'child', template: 'child'})
|
||||
class ChildComponent {
|
||||
constructor(parent: ParentComponent) {}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [ParentComponent, ChildComponent],
|
||||
entryComponents: [ParentComponent, ChildComponent],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
const ng1Module =
|
||||
angular.module('ng1', [])
|
||||
.directive('parent', downgradeComponent({component: ParentComponent}))
|
||||
.directive('child', downgradeComponent({component: ChildComponent}));
|
||||
|
||||
const element = html('<parent><child></child></parent>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => {
|
||||
expect(multiTrim(document.body.textContent)).toBe('parent(child)');
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
89
packages/upgrade/test/static/integration/examples_spec.ts
Normal file
89
packages/upgrade/test/static/integration/examples_spec.ts
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @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, ElementRef, Injector, Input, NgModule, destroyPlatform} from '@angular/core';
|
||||
import {async} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static';
|
||||
|
||||
import {bootstrap, html, multiTrim} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('examples', () => {
|
||||
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
it('should have AngularJS loaded', () => expect(angular.version.major).toBe(1));
|
||||
|
||||
it('should verify UpgradeAdapter example', async(() => {
|
||||
|
||||
// This is wrapping (upgrading) an AngularJS component to be used in an Angular
|
||||
// component
|
||||
@Directive({selector: 'ng1'})
|
||||
class Ng1Component extends UpgradeComponent {
|
||||
@Input() title: string;
|
||||
|
||||
constructor(elementRef: ElementRef, injector: Injector) {
|
||||
super('ng1', elementRef, injector);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an Angular component that will be downgraded
|
||||
@Component({
|
||||
selector: 'ng2',
|
||||
template: 'ng2[<ng1 [title]="nameProp">transclude</ng1>](<ng-content></ng-content>)'
|
||||
})
|
||||
class Ng2Component {
|
||||
@Input('name') nameProp: string;
|
||||
}
|
||||
|
||||
// This module represents the Angular pieces of the application
|
||||
@NgModule({
|
||||
declarations: [Ng1Component, Ng2Component],
|
||||
entryComponents: [Ng2Component],
|
||||
imports: [BrowserModule, UpgradeModule]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() { /* this is a placeholder to stop the boostrapper from complaining */
|
||||
}
|
||||
}
|
||||
|
||||
// This module represents the AngularJS pieces of the application
|
||||
const ng1Module =
|
||||
angular
|
||||
.module('myExample', [])
|
||||
// This is an AngularJS component that will be upgraded
|
||||
.directive(
|
||||
'ng1',
|
||||
() => {
|
||||
return {
|
||||
scope: {title: '='},
|
||||
transclude: true,
|
||||
template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
|
||||
};
|
||||
})
|
||||
// This is wrapping (downgrading) an Angular component to be used in AngularJS
|
||||
.directive(
|
||||
'ng2',
|
||||
downgradeComponent({component: Ng2Component, inputs: ['nameProp: name']}));
|
||||
|
||||
// This is the (AngularJS) application bootstrap element
|
||||
// Notice that it is actually a downgraded Angular component
|
||||
const element = html('<ng2 name="World">project</ng2>');
|
||||
|
||||
// Let's use a helper function to make this simpler
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => {
|
||||
expect(multiTrim(element.textContent))
|
||||
.toBe('ng2[ng1[Hello World!](transclude)](project)');
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
103
packages/upgrade/test/static/integration/injection_spec.ts
Normal file
103
packages/upgrade/test/static/integration/injection_spec.ts
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @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 {InjectionToken, Injector, NgModule, destroyPlatform} from '@angular/core';
|
||||
import {async} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {$INJECTOR, INJECTOR_KEY} from '@angular/upgrade/src/common/constants';
|
||||
import {UpgradeModule, downgradeInjectable} from '@angular/upgrade/static';
|
||||
|
||||
import {bootstrap, html} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('injection', () => {
|
||||
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
it('should downgrade ng2 service to ng1', async(() => {
|
||||
// Tokens used in ng2 to identify services
|
||||
const Ng2Service = new InjectionToken('ng2-service');
|
||||
|
||||
// Sample ng1 NgModule for tests
|
||||
@NgModule({
|
||||
imports: [BrowserModule, UpgradeModule],
|
||||
providers: [
|
||||
{provide: Ng2Service, useValue: 'ng2 service value'},
|
||||
]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
// create the ng1 module that will import an ng2 service
|
||||
const ng1Module =
|
||||
angular.module('ng1Module', []).factory('ng2Service', downgradeInjectable(Ng2Service));
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, html('<div>'), ng1Module)
|
||||
.then((upgrade) => {
|
||||
const ng1Injector = upgrade.$injector;
|
||||
expect(ng1Injector.get('ng2Service')).toBe('ng2 service value');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should upgrade ng1 service to ng2', async(() => {
|
||||
// Tokens used in ng2 to identify services
|
||||
const Ng1Service = new InjectionToken('ng1-service');
|
||||
|
||||
// Sample ng1 NgModule for tests
|
||||
@NgModule({
|
||||
imports: [BrowserModule, UpgradeModule],
|
||||
providers: [
|
||||
// the following line is the "upgrade" of an AngularJS service
|
||||
{
|
||||
provide: Ng1Service,
|
||||
useFactory: (i: angular.IInjectorService) => i.get('ng1Service'),
|
||||
deps: ['$injector']
|
||||
}
|
||||
]
|
||||
})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
// create the ng1 module that will import an ng2 service
|
||||
const ng1Module = angular.module('ng1Module', []).value('ng1Service', 'ng1 service value');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, html('<div>'), ng1Module)
|
||||
.then((upgrade) => {
|
||||
const ng2Injector = upgrade.injector;
|
||||
expect(ng2Injector.get(Ng1Service)).toBe('ng1 service value');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should initialize the upgraded injector before application run blocks are executed',
|
||||
async(() => {
|
||||
let runBlockTriggered = false;
|
||||
|
||||
const ng1Module = angular.module('ng1Module', []).run([
|
||||
INJECTOR_KEY,
|
||||
function(injector: Injector) {
|
||||
runBlockTriggered = true;
|
||||
expect(injector.get($INJECTOR)).toBeDefined();
|
||||
}
|
||||
]);
|
||||
|
||||
@NgModule({imports: [BrowserModule, UpgradeModule]})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, html('<div>'), ng1Module).then(() => {
|
||||
expect(runBlockTriggered).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
77
packages/upgrade/test/static/integration/testability_spec.ts
Normal file
77
packages/upgrade/test/static/integration/testability_spec.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @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 {NgModule, Testability, destroyPlatform} from '@angular/core';
|
||||
import {NgZone} from '@angular/core/src/zone/ng_zone';
|
||||
import {fakeAsync, tick} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {UpgradeModule} from '@angular/upgrade/static';
|
||||
|
||||
import {bootstrap, html} from '../test_helpers';
|
||||
|
||||
export function main() {
|
||||
describe('testability', () => {
|
||||
|
||||
beforeEach(() => destroyPlatform());
|
||||
afterEach(() => destroyPlatform());
|
||||
|
||||
@NgModule({imports: [BrowserModule, UpgradeModule]})
|
||||
class Ng2Module {
|
||||
ngDoBootstrap() {}
|
||||
}
|
||||
|
||||
it('should handle deferred bootstrap', fakeAsync(() => {
|
||||
let applicationRunning = false;
|
||||
let stayedInTheZone: boolean;
|
||||
const ng1Module = angular.module('ng1', []).run(() => {
|
||||
applicationRunning = true;
|
||||
stayedInTheZone = NgZone.isInAngularZone();
|
||||
});
|
||||
|
||||
const element = html('<div></div>');
|
||||
window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module);
|
||||
|
||||
setTimeout(() => { (<any>window).angular.resumeBootstrap(); }, 100);
|
||||
|
||||
expect(applicationRunning).toEqual(false);
|
||||
tick(100);
|
||||
expect(applicationRunning).toEqual(true);
|
||||
expect(stayedInTheZone).toEqual(true);
|
||||
}));
|
||||
|
||||
it('should wait for ng2 testability', fakeAsync(() => {
|
||||
const ng1Module = angular.module('ng1', []);
|
||||
const element = html('<div></div>');
|
||||
|
||||
bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => {
|
||||
|
||||
const ng2Testability: Testability = upgrade.injector.get(Testability);
|
||||
ng2Testability.increasePendingRequestCount();
|
||||
let ng2Stable = false;
|
||||
let ng1Stable = false;
|
||||
|
||||
angular.getTestability(element).whenStable(() => { ng1Stable = true; });
|
||||
|
||||
setTimeout(() => {
|
||||
ng2Stable = true;
|
||||
ng2Testability.decreasePendingRequestCount();
|
||||
}, 100);
|
||||
|
||||
expect(ng1Stable).toEqual(false);
|
||||
expect(ng2Stable).toEqual(false);
|
||||
tick(100);
|
||||
expect(ng1Stable).toEqual(true);
|
||||
expect(ng2Stable).toEqual(true);
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
3263
packages/upgrade/test/static/integration/upgrade_component_spec.ts
Normal file
3263
packages/upgrade/test/static/integration/upgrade_component_spec.ts
Normal file
File diff suppressed because it is too large
Load Diff
35
packages/upgrade/test/static/test_helpers.ts
Normal file
35
packages/upgrade/test/static/test_helpers.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @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 {PlatformRef, Type} from '@angular/core';
|
||||
import * as angular from '@angular/upgrade/src/common/angular1';
|
||||
import {$ROOT_SCOPE} from '@angular/upgrade/src/common/constants';
|
||||
import {UpgradeModule} from '@angular/upgrade/static';
|
||||
|
||||
export * from '../common/test_helpers';
|
||||
|
||||
export function bootstrap(
|
||||
platform: PlatformRef, Ng2Module: Type<{}>, element: Element, ng1Module: angular.IModule) {
|
||||
// We bootstrap the Angular module first; then when it is ready (async)
|
||||
// We bootstrap the AngularJS module on the bootstrap element
|
||||
return platform.bootstrapModule(Ng2Module).then(ref => {
|
||||
const upgrade = ref.injector.get(UpgradeModule) as UpgradeModule;
|
||||
upgrade.bootstrap(element, [ng1Module.name]);
|
||||
return upgrade;
|
||||
});
|
||||
}
|
||||
|
||||
export function $apply(adapter: UpgradeModule, exp: angular.Ng1Expression) {
|
||||
const $rootScope = adapter.$injector.get($ROOT_SCOPE) as angular.IRootScopeService;
|
||||
$rootScope.$apply(exp);
|
||||
}
|
||||
|
||||
export function $digest(adapter: UpgradeModule) {
|
||||
const $rootScope = adapter.$injector.get($ROOT_SCOPE) as angular.IRootScopeService;
|
||||
$rootScope.$digest();
|
||||
}
|
Reference in New Issue
Block a user