import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
it,
xdescribe,
xit,
} from 'angular2/test_lib';
import {Component, View, Inject, EventEmitter} from 'angular2/angular2';
import {createUpgradeModule, UpgradeModule} from 'upgrade/upgrade';
export function main() {
describe('upgrade: ng1 to ng2', () => {
it('should have angular 1 loaded', () => expect(angular.version.major).toBe(1));
it('should instantiate ng2 in ng1 template and project content',
inject([AsyncTestCompleter], (async) => {
var Ng2 = Component({selector: 'ng2'})
.View({template: `{{ 'NG2' }}()`})
.Class({constructor: function() {}});
var element = html("
{{ 'ng1[' }}~{{ 'ng-content' }}~{{ ']' }}
");
var upgradeModule: UpgradeModule = createUpgradeModule();
upgradeModule.importNg2Component(Ng2);
upgradeModule.bootstrap(element).ready(() => {
expect(document.body.textContent).toEqual("ng1[NG2(~ng-content~)]");
async.done();
});
}));
it('should instantiate ng1 in ng2 template and project content',
inject([AsyncTestCompleter], (async) => {
var upgrMod: UpgradeModule = createUpgradeModule();
var Ng2 = Component({selector: 'ng2-1'})
.View({
template: `{{ 'ng2(' }}{{'transclude'}}{{ ')' }}`,
directives: [upgrMod.exportAsNg2Component('ng1')]
})
.Class({constructor: function() {}});
upgrMod.ng1Module.directive('ng1', () => {
return {transclude: true, template: '{{ "ng1" }}()'};
});
upgrMod.importNg2Component(Ng2);
var element = html("{{'ng1('}}{{')'}}
");
upgrMod.bootstrap(element).ready(() => {
expect(document.body.textContent).toEqual("ng1(ng2(ng1(transclude)))");
async.done();
});
}));
describe('scope/component change-detection', () => {
it('should interleave scope and component expressions',
inject([AsyncTestCompleter], (async) => {
var log = [];
var l = function(value) {
log.push(value);
return value + ';';
};
var upgrMod: UpgradeModule = createUpgradeModule();
upgrMod.ng1Module.directive('ng1a', () => { return {template: "{{ l('ng1a') }}"}; });
upgrMod.ng1Module.directive('ng1b', () => { return {template: "{{ l('ng1b') }}"}; });
upgrMod.ng1Module.run(($rootScope) => {
$rootScope.l = l;
$rootScope.reset = () => log.length = 0;
});
upgrMod.importNg2Component(
Component({selector: 'ng2'})
.View({
template: `{{l('2A')}}{{l('2B')}}{{l('2C')}}`,
directives: [
upgrMod.exportAsNg2Component('ng1a'),
upgrMod.exportAsNg2Component('ng1b')
]
})
.Class({constructor: function() { this.l = l; }}));
var element = html("{{reset(); l('1A');}}{{l('1B')}}{{l('1C')}}
");
upgrMod.bootstrap(element).ready(() => {
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']);
async.done();
});
}));
});
describe('binding from ng1 to ng2', () => {
it('should bind properties, events', inject([AsyncTestCompleter], (async) => {
var upgrMod: UpgradeModule = createUpgradeModule();
upgrMod.ng1Module.run(($rootScope) => {
$rootScope.dataA = 'A';
$rootScope.dataB = 'B';
$rootScope.modelA = 'initModelA';
$rootScope.modelB = 'initModelB';
$rootScope.eventA = '?';
$rootScope.eventB = '?';
});
upgrMod.importNg2Component(
Component({
selector: 'ng2',
inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'],
outputs: [
'eventA',
'eventB',
'twoWayAEmitter: twoWayAChange',
'twoWayBEmitter: twoWayBChange'
]
})
.View({
template:
"ignore: {{ignore}}; " +
"literal: {{literal}}; interpolate: {{interpolate}}; " +
"oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; " +
"twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{onChangesCount}})"
})
.Class({
constructor: function() {
this.onChangesCount = 0;
this.ignore = '-';
this.literal = '?';
this.interpolate = '?';
this.oneWayA = '?';
this.oneWayB = '?';
this.twoWayA = '?';
this.twoWayB = '?';
this.eventA = new EventEmitter();
this.eventB = new EventEmitter();
this.twoWayAEmitter = new EventEmitter();
this.twoWayBEmitter = new EventEmitter();
},
onChanges: function(changes) {
var assert = (prop, value) => {
if (this[prop] != value) {
throw new Error(
`Expected: '${prop}' to be '${value}' but was '${this[prop]}'`);
}
};
var assertChange = (prop, value) => {
assert(prop, value);
if (!changes[prop]) {
throw new Error(`Changes record for '${prop}' not found.`);
}
var actValue = changes[prop].currentValue;
if (actValue != value) {
throw new Error(
`Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`);
}
};
switch (this.onChangesCount++) {
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.next('newA');
this.twoWayBEmitter.next('newB');
this.eventA.next('aFired');
this.eventB.next('bFired');
break;
case 1:
assertChange('twoWayA', 'newA');
break;
case 2:
assertChange('twoWayB', 'newB');
break;
default:
throw new Error('Called too many times! ' + JSON.stringify(changes));
}
}
}));
var element = html(`
| modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}};
`);
upgrMod.bootstrap(element).ready(() => {
expect(multiTrim(document.body.textContent))
.toEqual(
"ignore: -; " + "literal: Text; interpolate: Hello world; " +
"oneWayA: A; oneWayB: B; twoWayA: initModelA; twoWayB: initModelB; (1) | " +
"modelA: initModelA; modelB: initModelB; eventA: ?; eventB: ?;");
setTimeout(() => {
// we need to do setTimeout, because the EventEmitter uses setTimeout to schedule
// events, and so without this we would not see the events processed.
expect(multiTrim(document.body.textContent))
.toEqual("ignore: -; " + "literal: Text; interpolate: Hello world; " +
"oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | " +
"modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;");
async.done();
});
});
}));
});
describe('binding from ng2 to ng1', () => {
it('should bind properties, events', inject([AsyncTestCompleter], (async) => {
var upgrMod = createUpgradeModule();
var ng1 = function() {
return {
template: 'Hello {{fullName}}; A: {{dataA}}; B: {{dataB}}; | ',
scope: {fullName: '@', modelA: '=dataA', modelB: '=dataB', event: '&'},
link: function(scope) {
scope.$watch('dataB', (v) => {
if (v == 'Savkin') {
scope.dataB = 'SAVKIN';
scope.event('WORKS');
// Should not update becaus [model-a] is uni directional
scope.dataA = 'VICTOR';
}
})
}
}
};
upgrMod.ng1Module.directive('ng1', ng1);
var ng2 =
Component({selector: 'ng2'})
.View({
template:
'' +
'' +
'{{event}}-{{last}}, {{first}}',
directives: [upgrMod.exportAsNg2Component('ng1')]
})
.Class({
constructor: function() {
this.first = 'Victor';
this.last = 'Savkin';
this.event = '?';
}
});
upgrMod.importNg2Component(ng2);
var element = html(`
`);
upgrMod.bootstrap(element).ready(() => {
// we need to do setTimeout, because the EventEmitter uses setTimeout to schedule
// events, and so without this we would not see the events processed.
setTimeout(() => {
expect(multiTrim(document.body.textContent))
.toEqual(
"Hello SAVKIN, Victor; A: VICTOR; B: SAVKIN; | Hello TEST; A: First; B: Last; | WORKS-SAVKIN, Victor");
async.done();
}, 0);
});
}));
});
});
}
function multiTrim(text: string): string {
return text.replace(/\n/g, '').replace(/\s\s+/g, ' ').trim();
}
function html(html: string): Element {
var body = document.body;
body.innerHTML = html;
if (body.childNodes.length == 1 && body.firstChild instanceof HTMLElement)
return body.firstChild;
return body;
}