${_scriptStart}${_scriptEnd}`);
+ content = DOM.firstChild(parent);
+ });
+
+ it("should insert the nodes", () => {
+ var c = new Content(null, content, '');
c.insert([el("
"), el("
")])
- expect(DOM.getInnerHTML(parent)).toEqual(`${_script}
${_script}`);
+ expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}
${_scriptEnd}`);
});
it("should remove the nodes from the previous insertion", () => {
- var parent = el("
");
- var content = DOM.firstChild(parent);
-
- var c = new Content(null, new NgElement(content));
+ var c = new Content(null, content, '');
c.insert([el("
")]);
c.insert([el("
")]);
- expect(DOM.getInnerHTML(parent)).toEqual(`${_script}
${_script}`);
+ expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}
${_scriptEnd}`);
});
it("should insert empty list", () => {
- var parent = el("
");
- var content = DOM.firstChild(parent);
-
- var c = new Content(null, new NgElement(content));
+ var c = new Content(null, content, '');
c.insert([el("
")]);
c.insert([]);
- expect(DOM.getInnerHTML(parent)).toEqual(`${_script}${_script}`);
+ expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}${_scriptEnd}`);
});
});
-}
\ No newline at end of file
+}
diff --git a/modules/angular2/test/core/compiler/shadow_dom/light_dom_spec.js b/modules/angular2/test/core/compiler/shadow_dom/light_dom_spec.js
index ab6dbdc582..a017a7d19d 100644
--- a/modules/angular2/test/core/compiler/shadow_dom/light_dom_spec.js
+++ b/modules/angular2/test/core/compiler/shadow_dom/light_dom_spec.js
@@ -1,56 +1,35 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
-import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
+import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
import {LightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {View} from 'angular2/src/core/compiler/view';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
-import {ElementInjector} from 'angular2/src/core/compiler/element_injector';
-
-@proxy
-@IMPLEMENTS(ElementInjector)
-class FakeElementInjector {
- content;
- viewContainer;
- element;
-
- constructor(content = null, viewContainer = null, element = null) {
- this.content = content;
- this.viewContainer = viewContainer;
- this.element = element;
- }
-
- hasDirective(type) {
- return this.content != null;
- }
-
- hasPreBuiltObject(type) {
- return this.viewContainer != null;
- }
-
- forElement(n) {
- return this.element == n;
- }
-
- get(t) {
- if (t === Content) return this.content;
- if (t === ViewContainer) return this.viewContainer;
- return null;
- }
-
- noSuchMethod(i) {
- super.noSuchMethod(i);
- }
-}
@proxy
@IMPLEMENTS(View)
class FakeView {
- elementInjectors;
+ contentTags;
+ viewContainers;
- constructor(elementInjectors = null) {
- this.elementInjectors = elementInjectors;
+ constructor(containers = null) {
+ this.contentTags = [];
+ this.viewContainers = [];
+ if (isPresent(containers)) {
+ ListWrapper.forEach(containers, (c) => {
+ if (c instanceof FakeContentTag) {
+ ListWrapper.push(this.contentTags, c);
+ } else {
+ ListWrapper.push(this.contentTags, null);
+ }
+ if (c instanceof FakeViewContainer) {
+ ListWrapper.push(this.viewContainers, c);
+ } else {
+ ListWrapper.push(this.viewContainers, null);
+ }
+ });
+ }
}
noSuchMethod(i) {
@@ -61,10 +40,12 @@ class FakeView {
@proxy
@IMPLEMENTS(ViewContainer)
class FakeViewContainer {
+ templateElement;
_nodes;
_contentTagContainers;
- constructor(nodes = null, views = null) {
+ constructor(templateEl, nodes = null, views = null) {
+ this.templateElement = templateEl;
this._nodes = nodes;
this._contentTagContainers = views;
}
@@ -88,8 +69,10 @@ class FakeViewContainer {
class FakeContentTag {
select;
_nodes;
+ contentStartElement;
- constructor(select = null, nodes = null) {
+ constructor(contentEl, select = '', nodes = null) {
+ this.contentStartElement = contentEl;
this.select = select;
this._nodes = nodes;
}
@@ -113,69 +96,66 @@ export function main() {
var lightDomView;
beforeEach(() => {
- lightDomView = new FakeView([]);
+ lightDomView = new FakeView();
});
describe("contentTags", () => {
it("should collect content tags from element injectors", () => {
- var tag = new FakeContentTag();
- var shadowDomView = new FakeView([new FakeElementInjector(tag)]);
+ var tag = new FakeContentTag(el(''));
+ var shadowDomView = new FakeView([tag]);
- var lightDom = new LightDom(lightDomView, shadowDomView, el("
"));
+ var lightDom = new LightDom(lightDomView, shadowDomView,
+ el("
"));
expect(lightDom.contentTags()).toEqual([tag]);
});
it("should collect content tags from ViewContainers", () => {
- var tag = new FakeContentTag();
- var vp = new FakeViewContainer(null, [
- new FakeView([new FakeElementInjector(tag, null)])
+ var tag = new FakeContentTag(el(''));
+ var vc = new FakeViewContainer(null, null, [
+ new FakeView([tag])
]);
-
- var shadowDomView = new FakeView([new FakeElementInjector(null, vp)]);
-
- var lightDom = new LightDom(lightDomView, shadowDomView, el("
"));
+ var shadowDomView = new FakeView([vc]);
+ var lightDom = new LightDom(lightDomView, shadowDomView,
+ el("
"));
expect(lightDom.contentTags()).toEqual([tag]);
});
});
- describe("expanded roots", () => {
+ describe("expandedDomNodes", () => {
it("should contain root nodes", () => {
var lightDomEl = el("
")
var lightDom = new LightDom(lightDomView, new FakeView(), lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["
"]);
});
- it("should include ViewContainer nodes", () => {
- var lightDomEl = el("
")
-
- var lightDomView = new FakeView([
- new FakeElementInjector(
- null,
- new FakeViewContainer([el("
")]),
- DOM.firstChild(lightDomEl))]);
-
+ it("should include view container nodes", () => {
+ var lightDomEl = el("
");
var lightDom = new LightDom(
- lightDomView,
- new FakeView(),
+ new FakeView([
+ new FakeViewContainer(
+ DOM.firstChild(lightDomEl), // template element
+ [el('
')] // light DOM nodes of view container
+ )
+ ]),
+ null,
lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["
"]);
});
it("should include content nodes", () => {
- var lightDomEl = el("
")
-
- var lightDomView = new FakeView([
- new FakeElementInjector(
- new FakeContentTag(null, [el("
")]),
- null,
- DOM.firstChild(lightDomEl))]);
-
+ var lightDomEl = el("
");
var lightDom = new LightDom(
- lightDomView,
- new FakeView(),
+ new FakeView([
+ new FakeContentTag(
+ DOM.firstChild(lightDomEl), // content element
+ '', // selector
+ [el('
')] // light DOM nodes of content tag
+ )
+ ]),
+ null,
lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["
"]);
@@ -184,7 +164,7 @@ export function main() {
it("should work when the element injector array contains nulls", () => {
var lightDomEl = el("
")
- var lightDomView = new FakeView([null]);
+ var lightDomView = new FakeView();
var lightDom = new LightDom(
lightDomView,
@@ -197,14 +177,14 @@ export function main() {
describe("redistribute", () => {
it("should redistribute nodes between content tags with select property set", () => {
- var contentA = new FakeContentTag("a");
- var contentB = new FakeContentTag("b");
+ var contentA = new FakeContentTag(null, "a");
+ var contentB = new FakeContentTag(null, "b");
var lightDomEl = el("
")
var lightDom = new LightDom(lightDomView, new FakeView([
- new FakeElementInjector(contentA, null),
- new FakeElementInjector(contentB, null)
+ contentA,
+ contentB
]), lightDomEl);
lightDom.redistribute();
@@ -214,14 +194,14 @@ export function main() {
});
it("should support wildcard content tags", () => {
- var wildcard = new FakeContentTag(null);
- var contentB = new FakeContentTag("b");
+ var wildcard = new FakeContentTag(null, '');
+ var contentB = new FakeContentTag(null, "b");
var lightDomEl = el("
")
var lightDom = new LightDom(lightDomView, new FakeView([
- new FakeElementInjector(wildcard, null),
- new FakeElementInjector(contentB, null)
+ wildcard,
+ contentB
]), lightDomEl);
lightDom.redistribute();
diff --git a/modules/angular2/test/core/compiler/shadow_dom/shadow_css_spec.js b/modules/angular2/test/core/compiler/shadow_dom/shadow_css_spec.js
index 5439683b0c..2cbbe4732b 100644
--- a/modules/angular2/test/core/compiler/shadow_dom/shadow_css_spec.js
+++ b/modules/angular2/test/core/compiler/shadow_dom/shadow_css_spec.js
@@ -1,4 +1,4 @@
-import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
+import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, IS_NODEJS} from 'angular2/test_lib';
import {ShadowCss} from 'angular2/src/core/compiler/shadow_dom_emulation/shadow_css';
import {RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
@@ -91,13 +91,16 @@ export function main() {
expect(StringWrapper.contains(css, '#menu > .bar {;background: blue;}')).toBeTruthy();
});
- it('should support polyfill-rule', () => {
- var css = s("polyfill-rule {content: ':host.foo .bar';background: blue;}", 'a', 'a-host');
- expect(css).toEqual('[a-host].foo .bar {background: blue;}');
+ if (!IS_NODEJS) {
+ //TODO: reactivate once CSS parser is fixed: https://github.com/reworkcss/css/issues/65
+ it('should support polyfill-rule', () => {
+ var css = s("polyfill-rule {content: ':host.foo .bar';background: blue;}", 'a', 'a-host');
+ expect(css).toEqual('[a-host].foo .bar {background: blue;}');
- css = s('polyfill-rule {content: ":host.foo .bar";background: blue;}', 'a', 'a-host');
- expect(css).toEqual('[a-host].foo .bar {background: blue;}');
- });
+ css = s('polyfill-rule {content: ":host.foo .bar";background: blue;}', 'a', 'a-host');
+ expect(css).toEqual('[a-host].foo .bar {background: blue;}');
+ });
+ }
it('should handle ::shadow', () => {
var css = s('x::shadow > y {}', 'a');
diff --git a/modules/angular2/test/core/compiler/shadow_dom/shadow_dom_emulation_integration_spec.js b/modules/angular2/test/core/compiler/shadow_dom/shadow_dom_emulation_integration_spec.js
index 4aef354585..a98ff4dbd4 100644
--- a/modules/angular2/test/core/compiler/shadow_dom/shadow_dom_emulation_integration_spec.js
+++ b/modules/angular2/test/core/compiler/shadow_dom/shadow_dom_emulation_integration_spec.js
@@ -1,4 +1,16 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ IS_NODEJS,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {StringMapWrapper, List} from 'angular2/src/facade/collection';
import {Type} from 'angular2/src/facade/lang';
@@ -38,12 +50,15 @@ export function main() {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
var styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
+ var strategies = {
+ "scoped" : new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div')),
+ "unscoped" : new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, DOM.createElement('div'))
+ }
+ if (!IS_NODEJS) {
+ StringMapWrapper.set(strategies, "native", new NativeShadowDomStrategy(styleUrlResolver));
+ }
- StringMapWrapper.forEach({
- "native" : new NativeShadowDomStrategy(styleUrlResolver),
- "scoped" : new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div')),
- "unscoped" : new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, DOM.createElement('div')),
- },
+ StringMapWrapper.forEach(strategies,
(strategy, name) => {
describe(`${name} shadow dom strategy`, () => {
@@ -77,7 +92,19 @@ export function main() {
});
}
- it('should support multiple content tags', (done) => {
+ it('should support simple components', inject([AsyncTestCompleter], (async) => {
+ var temp = '
' +
+ 'A
' +
+ ' ';
+
+ compile(temp, [Simple], (view, lc) => {
+ expect(view.nodes).toHaveText('SIMPLE(A)');
+
+ async.done();
+ });
+ }));
+
+ it('should support multiple content tags', inject([AsyncTestCompleter], (async) => {
var temp = '
' +
'B
' +
'C
' +
@@ -86,11 +113,11 @@ export function main() {
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(A, BC)');
- done();
+ async.done();
});
- });
+ }));
- it('should redistribute only direct children', (done) => {
+ it('should redistribute only direct children', inject([AsyncTestCompleter], (async) => {
var temp = '' +
'' +
'C
' +
@@ -98,11 +125,11 @@ export function main() {
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
expect(view.nodes).toHaveText('(, BAC)');
- done();
+ async.done();
});
- });
+ }));
- it("should redistribute direct child viewcontainers when the light dom changes", (done) => {
+ it("should redistribute direct child viewcontainers when the light dom changes", inject([AsyncTestCompleter], (async) => {
var temp = '' +
'' +
'B
' +
@@ -123,11 +150,11 @@ export function main() {
expect(view.nodes).toHaveText('(, B)');
- done();
+ async.done();
});
- });
+ }));
- it("should redistribute when the light dom changes", (done) => {
+ it("should redistribute when the light dom changes", inject([AsyncTestCompleter], (async) => {
var temp = '' +
'A
' +
'B
' +
@@ -148,11 +175,11 @@ export function main() {
expect(view.nodes).toHaveText('(, B)');
- done();
+ async.done();
});
- });
+ }));
- it("should support nested components", (done) => {
+ it("should support nested components", inject([AsyncTestCompleter], (async) => {
var temp = '' +
'A
' +
'B
' +
@@ -161,11 +188,11 @@ export function main() {
compile(temp, [OuterWithIndirectNestedComponent], (view, lc) => {
expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))');
- done();
+ async.done();
});
- });
+ }));
- it("should support nesting with content being direct child of a nested component", (done) => {
+ it("should support nesting with content being direct child of a nested component", inject([AsyncTestCompleter], (async) => {
var temp = '' +
'A
' +
'B
' +
@@ -181,37 +208,36 @@ export function main() {
lc.tick();
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
- done();
+ async.done();
});
- });
+ }));
- // Enable once dom-write queue is implemented and onDehydrate is implemented
- //it('should redistribute when the shadow dom changes', (done) => {
- // var temp = '' +
- // 'A
' +
- // 'B
' +
- // 'C
' +
- // ' ';
- //
- //
- // compile(temp, (view, lc) => {
- // var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
- //
- // expect(view.nodes).toHaveText('(, ABC)');
- //
- // cmp.showLeft();
- // lc.tick();
- //
- // expect(view.nodes).toHaveText('(A, BC)');
- //
- // cmp.hideLeft()
- // lc.tick();
- //
- // expect(view.nodes).toHaveText('(, ABC)');
- //
- // done();
- // });
- //});
+ it('should redistribute when the shadow dom changes', inject([AsyncTestCompleter], (async) => {
+ var temp = '' +
+ 'A
' +
+ 'B
' +
+ 'C
' +
+ ' ';
+
+
+ compile(temp, [ConditionalContentComponent, AutoViewportDirective], (view, lc) => {
+ var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
+
+ expect(view.nodes).toHaveText('(, ABC)');
+
+ cmp.showLeft();
+ lc.tick();
+
+ expect(view.nodes).toHaveText('(A, BC)');
+
+ cmp.hideLeft();
+ lc.tick();
+
+ expect(view.nodes).toHaveText('(, ABC)');
+
+ async.done();
+ });
+ }));
//Implement once NgElement support changing a class
//it("should redistribute when a class has been added or removed");
@@ -297,7 +323,7 @@ class MultipleContentTagsComponent {
@Component({selector: 'conditional-content'})
@Template({
- inline: '',
+ inline: '',
directives: [AutoViewportDirective]
})
class ConditionalContentComponent {
@@ -353,6 +379,6 @@ class MyComp {
function createView(pv) {
var view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, {});
+ view.hydrate(new Injector([]), null, null, {}, null);
return view;
}
diff --git a/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js b/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js
index 65e8620cb2..e0ea87a7b5 100644
--- a/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js
+++ b/modules/angular2/test/core/compiler/shadow_dom_strategy_spec.js
@@ -1,4 +1,15 @@
-import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ SpyObject,
+} from 'angular2/test_lib';
import {
NativeShadowDomStrategy,
@@ -45,10 +56,6 @@ export function main() {
expect(shadowRoot).toHaveText('view');
});
- it('should should not transform template elements', () => {
- expect(strategy.getTemplateCompileStep(null)).toBe(null);
- });
-
it('should rewrite style urls', () => {
var step = strategy.getStyleCompileStep(null, 'http://base');
var styleElement = DOM.createStyleElement('.one {background-image: url("img.jpg");}');
@@ -87,7 +94,7 @@ export function main() {
strategy.attachTemplate(host, view);
var firstChild = DOM.firstChild(host);
- expect(DOM.tagName(firstChild)).toEqual('DIV');
+ expect(DOM.tagName(firstChild).toLowerCase()).toEqual('div');
expect(firstChild).toHaveText('view');
expect(host).toHaveText('view');
});
@@ -114,7 +121,7 @@ export function main() {
expect(styleElement).toHaveText(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
});
- it('should inline @import rules', (done) => {
+ it('should inline @import rules', inject([AsyncTestCompleter], (async) => {
xhr.reply('http://base/one.css', '.one {}');
var template = el('
');
@@ -133,9 +140,9 @@ export function main() {
expect(styleElement).toHaveText('');
parentpv.stylePromises[0].then((_) => {
expect(styleElement).toHaveText('.one[_ngcontent-0] {\n\n}');
- done();
+ async.done();
});
- });
+ }));
it('should return the same style given the same component', () => {
var template = el('
');
@@ -222,7 +229,7 @@ export function main() {
strategy.attachTemplate(host, view);
var firstChild = DOM.firstChild(host);
- expect(DOM.tagName(firstChild)).toEqual('DIV');
+ expect(DOM.tagName(firstChild).toLowerCase()).toEqual('div');
expect(firstChild).toHaveText('view');
expect(host).toHaveText('view');
});
diff --git a/modules/angular2/test/core/compiler/style_inliner_spec.js b/modules/angular2/test/core/compiler/style_inliner_spec.js
index 185389fb11..bec4c549a0 100644
--- a/modules/angular2/test/core/compiler/style_inliner_spec.js
+++ b/modules/angular2/test/core/compiler/style_inliner_spec.js
@@ -1,4 +1,16 @@
-import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ beforeEachBindings,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {isBlank} from 'angular2/src/facade/lang';
@@ -6,29 +18,26 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
-import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
-import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
+
+import {bind} from 'angular2/di';
export function main() {
describe('StyleInliner', () => {
- var xhr, inliner;
-
- beforeEach(() => {
- xhr = new FakeXHR();
- var urlResolver = new UrlResolver();
- var styleUrlResolver = new StyleUrlResolver(urlResolver);
- inliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
- });
+ beforeEachBindings(() => [
+ bind(XHR).toClass(FakeXHR),
+ ]);
describe('loading', () => {
- it('should return a string when there is no import statement', () => {
+
+ it('should return a string when there is no import statement', inject([StyleInliner], (inliner) => {
var css = '.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).not.toBePromise();
expect(loadedCss).toEqual(css);
- });
+ }));
- it('should inline @import rules', (done) => {
+ it('should inline @import rules',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
@@ -37,16 +46,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- // TODO(vicb): fix the StyleInliner
- it('should support url([unquoted url]) in @import rules', (done) => {
+ it('should support url([unquoted url]) in @import rules',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
@@ -55,15 +64,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- it('should handle @import error gracefuly', (done) => {
+ it('should handle @import error gracefuly',
+ inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
@@ -71,15 +81,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- it('should inline multiple @import rules', (done) => {
+ it('should inline multiple @import rules',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}';
@@ -89,15 +100,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.two {}\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- it('should inline nested @import rules', (done) => {
+ it('should inline nested @import rules',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}';
@@ -107,15 +119,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- it('should handle circular dependencies gracefuly', (done) => {
+ it('should handle circular dependencies gracefuly',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}';
@@ -125,15 +138,16 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
- it('should handle invalid @import fracefuly', (done) => {
+ it('should handle invalid @import fracefuly',
+ inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
@@ -142,17 +156,18 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
});
describe('media query', () => {
- it('should wrap inlined content in media query', (done) => {
+ it('should wrap inlined content in media query',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loadedCss = inliner.inlineImports(css, 'http://base/');
@@ -161,17 +176,18 @@ export function main() {
loadedCss,
function(css) {
expect(css).toEqual('@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
});
describe('url rewritting', () => {
- it('should rewrite url in inlined content', (done) => {
+ it('should rewrite url in inlined content',
+ inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css', '@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
@@ -185,13 +201,13 @@ export function main() {
".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n"
);
- done();
+ async.done();
},
function(e) {
throw 'fail;'
}
);
- });
+ }));
});
});
}
diff --git a/modules/angular2/test/core/compiler/template_loader_spec.js b/modules/angular2/test/core/compiler/template_loader_spec.js
index dc1cf5e120..0edb12fbd1 100644
--- a/modules/angular2/test/core/compiler/template_loader_spec.js
+++ b/modules/angular2/test/core/compiler/template_loader_spec.js
@@ -1,4 +1,16 @@
-import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
+import {DOM} from 'angular2/src/dom/dom_adapter';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
@@ -17,21 +29,21 @@ export function main() {
it('should load inline templates synchronously', () => {
var template = new Template({inline: 'inline template'});
- expect(loader.load(template).content).toHaveText('inline template');
+ expect(DOM.content(loader.load(template))).toHaveText('inline template');
});
- it('should load templates through XHR', (done) => {
+ it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
loader.load(template).then((el) => {
- expect(el.content).toHaveText('xhr template');
- done();
+ expect(DOM.content(el)).toHaveText('xhr template');
+ async.done();
});
xhr.flush();
- });
+ }));
- it('should cache template loaded through XHR', (done) => {
+ it('should cache template loaded through XHR', inject([AsyncTestCompleter], (async) => {
var firstEl;
xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'});
@@ -43,11 +55,11 @@ export function main() {
})
.then((el) =>{
expect(el).toBe(firstEl);
- expect(el.content).toHaveText('xhr template');
- done();
+ expect(DOM.content(el)).toHaveText('xhr template');
+ async.done();
});
xhr.flush();
- });
+ }));
it('should throw when no template is defined', () => {
var template = new Template({inline: null, url: null});
@@ -55,7 +67,7 @@ export function main() {
.toThrowError('Templates should have either their url or inline property set');
});
- it('should return a rejected Promise when xhr loading fails', (done) => {
+ it('should return a rejected Promise when xhr loading fails', inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', null);
var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
@@ -63,11 +75,11 @@ export function main() {
function(_) { throw 'Unexpected response'; },
function(error) {
expect(error).toEqual('Failed to load base/foo');
- done();
+ async.done();
}
)
xhr.flush();
- });
+ }));
});
}
diff --git a/modules/angular2/test/core/compiler/view_container_spec.js b/modules/angular2/test/core/compiler/view_container_spec.js
index 1861ee74f5..8b8c184bec 100644
--- a/modules/angular2/test/core/compiler/view_container_spec.js
+++ b/modules/angular2/test/core/compiler/view_container_spec.js
@@ -10,8 +10,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
import {DynamicProtoChangeDetector, ChangeDetector, Lexer, Parser} from 'angular2/change_detection';
function createView(nodes) {
- var view = new View(null, nodes, new DynamicProtoChangeDetector(null), MapWrapper.create());
- view.init([], [], [], [], [], [], []);
+ var view = new View(null, nodes, MapWrapper.create());
+ var cd = new DynamicProtoChangeDetector(null).instantiate(view, [], null);
+ view.init(cd, [], [], [], [], [], [], [], [], []);
return view;
}
@@ -47,7 +48,8 @@ class HydrateAwareFakeView {
return this.isHydrated;
}
- hydrate(_, __, ___) {
+
+ hydrate(_, __, ___, ____, _____) {
this.isHydrated = true;
}
@@ -71,8 +73,9 @@ export function main() {
parentView = createView([dom.childNodes[0]]);
protoView = new ProtoView(el('hi
'), new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
- elementInjector = new ElementInjector(null, null, null, null);
- viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector, null);
+ elementInjector = new ElementInjector(null, null, null);
+ viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector,
+ null);
customViewWithOneNode = createView([el('single
')]);
customViewWithTwoNodes = createView([el('one
'), el('two
')]);
});
@@ -95,7 +98,7 @@ export function main() {
}
beforeEach(() => {
- viewContainer.hydrate(new Injector([]), null);
+ viewContainer.hydrate(new Injector([]), null, null);
var fillerView = createView([el('filler ')]);
viewContainer.insert(fillerView);
});
@@ -211,11 +214,11 @@ export function main() {
var fancyView;
beforeEach(() => {
var parser = new Parser(new Lexer());
- viewContainer.hydrate(new Injector([]), null);
+ viewContainer.hydrate(new Injector([]), null, null);
var pv = new ProtoView(el('{{}}
'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
- pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindTextNode(0, parser.parseBinding('foo', null));
fancyView = pv.instantiate(null, null);
});
diff --git a/modules/angular2/test/core/compiler/view_spec.js b/modules/angular2/test/core/compiler/view_spec.js
index 0582443083..cc5aad0ccb 100644
--- a/modules/angular2/test/core/compiler/view_spec.js
+++ b/modules/angular2/test/core/compiler/view_spec.js
@@ -1,4 +1,4 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, proxy} from 'angular2/test_lib';
+import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, proxy, IS_NODEJS} from 'angular2/test_lib';
import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from 'angular2/src/core/compiler/view';
import {ProtoElementInjector, ElementInjector, DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
import {EmulatedScopedShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
@@ -6,16 +6,16 @@ import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_meta
import {Component, Decorator, Viewport, Directive, onChange} from 'angular2/src/core/annotations/annotations';
import {Lexer, Parser, DynamicProtoChangeDetector,
ChangeDetector} from 'angular2/change_detection';
-import {EventEmitter} from 'angular2/src/core/annotations/events';
+import {EventEmitter} from 'angular2/src/core/annotations/di';
import {List, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {int, IMPLEMENTS} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di';
-import {View} from 'angular2/src/core/compiler/view';
+import {View, PropertyUpdate} from 'angular2/src/core/compiler/view';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
-import {reflector} from 'angular2/src/reflection/reflection';
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
import {EventManager, DomEventsPlugin} from 'angular2/src/core/events/event_manager';
+import {reflector} from 'angular2/src/reflection/reflection';
@proxy
@IMPLEMENTS(ViewContainer)
@@ -46,7 +46,7 @@ export function main() {
function createView(protoView, eventManager: EventManager = null) {
var ctx = new MyEvaluationContext();
var view = protoView.instantiate(null, eventManager);
- view.hydrate(null, null, ctx);
+ view.hydrate(null, null, null, ctx, null);
return view;
}
@@ -69,7 +69,7 @@ export function main() {
it('should be able to be hydrated and dehydrated', () => {
var ctx = new Object();
- view.hydrate(null, null, ctx);
+ view.hydrate(null, null, null, ctx, null);
expect(view.hydrated()).toBe(true);
view.dehydrate();
@@ -78,7 +78,7 @@ export function main() {
it('should hydrate and dehydrate the change detector', () => {
var ctx = new Object();
- view.hydrate(null, null, ctx);
+ view.hydrate(null, null, null, ctx, null);
expect(view.changeDetector.hydrated()).toBe(true);
view.dehydrate();
@@ -104,7 +104,7 @@ export function main() {
it('should support setting of declared locals', () => {
view.setLocal('context-foo', 'bar');
- expect(view.context.get('template-foo')).toBe('bar');
+ expect(view.locals.get('template-foo')).toBe('bar');
});
it('should not throw on undeclared locals', () => {
@@ -114,8 +114,8 @@ export function main() {
it('when dehydrated should set locals to null', () => {
view.setLocal('context-foo', 'bar');
view.dehydrate();
- view.hydrate(null, null, new Object());
- expect(view.context.get('template-foo')).toBe(null);
+ view.hydrate(null, null, null, new Object(), null);
+ expect(view.locals.get('template-foo')).toBe(null);
});
it('should throw when trying to set on dehydrated view', () => {
@@ -136,9 +136,9 @@ export function main() {
var pv = new ProtoView(templateAwareCreateElement('
'),
new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.nodes.length).toBe(1);
- expect(view.nodes[0].getAttribute('id')).toEqual('1');
+ expect(DOM.getAttribute(view.nodes[0], 'id')).toEqual('1');
});
describe('collect elements with property bindings', () => {
@@ -146,11 +146,11 @@ export function main() {
it('should collect property bindings on the root element if it has the ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindElementProperty(parser.parseBinding('a', null), 'prop', reflector.setter('prop'));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.bindElements.length).toEqual(1);
expect(view.bindElements[0]).toBe(view.nodes[0]);
});
@@ -158,11 +158,11 @@ export function main() {
it('should collect property bindings on child elements with ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindElementProperty(parser.parseBinding('b', null), 'a', reflector.setter('a'));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.bindElements.length).toEqual(1);
expect(view.bindElements[0]).toBe(view.nodes[0].childNodes[1]);
});
@@ -174,12 +174,12 @@ export function main() {
it('should collect text nodes under the root element', () => {
var pv = new ProtoView(templateAwareCreateElement('{{}} {{}}
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindTextNode(0, parser.parseBinding('a', null));
pv.bindTextNode(2, parser.parseBinding('b', null));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.textNodes.length).toEqual(2);
expect(view.textNodes[0]).toBe(view.nodes[0].childNodes[0]);
expect(view.textNodes[1]).toBe(view.nodes[0].childNodes[2]);
@@ -188,11 +188,11 @@ export function main() {
it('should collect text nodes with bindings on child elements with ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement(' {{}}
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindTextNode(0, parser.parseBinding('b', null));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.textNodes.length).toEqual(1);
expect(view.textNodes[0]).toBe(view.nodes[0].childNodes[1].childNodes[0]);
});
@@ -207,16 +207,16 @@ export function main() {
new NativeShadowDomStrategy(null));
pv.instantiateInPlace = true;
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.nodes[0]).toBe(template);
});
it('should be off by default.', () => {
var template = el('
')
- var view = new ProtoView(template, new DynamicProtoChangeDetector(null),
+ var pv = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null))
- .instantiate(null, null);
- view.hydrate(null, null, null);
+ var view = pv.instantiate(null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.nodes[0]).not.toBe(template);
});
});
@@ -233,10 +233,10 @@ export function main() {
it('should use the directives of the ProtoElementInjector', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.elementInjectors.length).toBe(1);
expect(view.elementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
});
@@ -245,11 +245,11 @@ export function main() {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
- pv.bindElement(protoParent);
- pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
+ pv.bindElement(null, 0, protoParent);
+ pv.bindElement(null, 0, new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.elementInjectors.length).toBe(2);
expect(view.elementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
expect(view.elementInjectors[1].parent).toBe(view.elementInjectors[0]);
@@ -259,12 +259,12 @@ export function main() {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
- pv.bindElement(protoParent);
+ pv.bindElement(null, 0, protoParent);
var testProtoElementInjector = new TestProtoElementInjector(protoParent, 1, [AnotherDirective]);
- pv.bindElement(testProtoElementInjector);
+ pv.bindElement(null, 0, testProtoElementInjector);
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
- var hostInjector = hostProtoInjector.instantiate(null, null, null);
+ var hostInjector = hostProtoInjector.instantiate(null, null);
var view;
expect(() => view = pv.instantiate(hostInjector, null)).not.toThrow();
expect(testProtoElementInjector.parentElementInjector).toBe(view.elementInjectors[0]);
@@ -274,12 +274,12 @@ export function main() {
it('should pass the host injector when there is no parent injector', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
var testProtoElementInjector = new TestProtoElementInjector(null, 1, [AnotherDirective]);
- pv.bindElement(testProtoElementInjector);
+ pv.bindElement(null, 0, testProtoElementInjector);
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
- var hostInjector = hostProtoInjector.instantiate(null, null, null);
+ var hostInjector = hostProtoInjector.instantiate(null, null);
expect(() => pv.instantiate(hostInjector, null)).not.toThrow();
expect(testProtoElementInjector.parentElementInjector).toBeNull();
expect(testProtoElementInjector.hostElementInjector).toBe(hostInjector);
@@ -292,11 +292,11 @@ export function main() {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
- pv.bindElement(protoParent);
- pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
+ pv.bindElement(null, 0, protoParent);
+ pv.bindElement(null, 0, new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.rootElementInjectors.length).toBe(1);
expect(view.rootElementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
});
@@ -304,11 +304,11 @@ export function main() {
it('should collect multiple root element injectors', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
- pv.bindElement(new ProtoElementInjector(null, 2, [AnotherDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 2, [AnotherDirective]));
var view = pv.instantiate(null, null);
- view.hydrate(null, null, null);
+ view.hydrate(null, null, null, null, null);
expect(view.rootElementInjectors.length).toBe(2)
expect(view.rootElementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
expect(view.rootElementInjectors[1].get(AnotherDirective) instanceof AnotherDirective).toBe(true);
@@ -322,7 +322,7 @@ export function main() {
function createComponentWithSubPV(subProtoView) {
var pv = new ProtoView(el(' '),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
- var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
+ var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = someComponentDirective;
binder.nestedProtoView = subProtoView;
return pv;
@@ -331,7 +331,7 @@ export function main() {
function createNestedView(protoView) {
ctx = new MyEvaluationContext();
var view = protoView.instantiate(null, null);
- view.hydrate(new Injector([]), null, ctx);
+ view.hydrate(new Injector([]), null, null, ctx, null);
return view;
}
@@ -351,7 +351,7 @@ export function main() {
el('hello shadow dom
'),
new DynamicProtoChangeDetector(null),
null);
- subpv.bindElement(
+ subpv.bindElement(null, 0,
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
var pv = createComponentWithSubPV(subpv);
@@ -376,7 +376,7 @@ export function main() {
el('hello shadow dom
'),
new DynamicProtoChangeDetector(null),
null);
- subpv.bindElement(
+ subpv.bindElement(null, 0,
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
var pv = createComponentWithSubPV(subpv);
@@ -406,7 +406,7 @@ export function main() {
var pv = new ProtoView(el(' '),
new DynamicProtoChangeDetector(null), new EmulatedScopedShadowDomStrategy(null, null, null));
- var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
+ var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent);
binder.nestedProtoView = subpv;
@@ -422,7 +422,7 @@ export function main() {
el('
'), new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el(' '),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
- var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeViewport]));
+ var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeViewport]));
binder.viewportDirective = someViewportDirective;
binder.nestedProtoView = templateProtoView;
@@ -444,82 +444,98 @@ export function main() {
});
});
- describe('event handlers', () => {
- var view, ctx, called, receivedEvent, dispatchedEvent;
+ if (!IS_NODEJS) {
+ describe('event handlers', () => {
+ var view, ctx, called, receivedEvent, dispatchedEvent;
- function createViewAndContext(protoView) {
- view = createView(protoView,
- new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()));
- ctx = view.context;
- called = 0;
- receivedEvent = null;
- ctx.callMe = (event) => {
- called += 1;
- receivedEvent = event;
+ function createViewAndContext(protoView) {
+ view = createView(protoView,
+ new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()));
+ ctx = view.context;
+ called = 0;
+ receivedEvent = null;
+ ctx.callMe = (event) => {
+ called += 1;
+ receivedEvent = event;
+ }
}
- }
- function dispatchClick(el) {
- dispatchedEvent = DOM.createMouseEvent('click');
- DOM.dispatchEvent(el, dispatchedEvent);
- }
+ function dispatchClick(el) {
+ dispatchedEvent = DOM.createMouseEvent('click');
+ DOM.dispatchEvent(el, dispatchedEvent);
+ }
- function createProtoView() {
- var pv = new ProtoView(el(''),
- new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new TestProtoElementInjector(null, 0, []));
- pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
- return pv;
- }
+ function createProtoView() {
+ var pv = new ProtoView(el(''),
+ new DynamicProtoChangeDetector(null), null);
+ pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, []));
+ pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
+ return pv;
+ }
- it('should fire on non-bubbling native events', () => {
- createViewAndContext(createProtoView());
+ it('should fire on non-bubbling native events', () => {
+ createViewAndContext(createProtoView());
- dispatchClick(view.nodes[0]);
+ dispatchClick(view.nodes[0]);
- expect(called).toEqual(1);
- expect(receivedEvent).toBe(dispatchedEvent);
+ expect(called).toEqual(1);
+ expect(receivedEvent).toBe(dispatchedEvent);
+ });
+
+ it('should not fire on a bubbled native events', () => {
+ createViewAndContext(createProtoView());
+
+ dispatchClick(view.nodes[0].firstChild);
+
+ // This test passes trivially on webkit browsers due to
+ // https://bugs.webkit.org/show_bug.cgi?id=122755
+ expect(called).toEqual(0);
+ });
+
+ it('should not throw if the view is dehydrated', () => {
+ createViewAndContext(createProtoView());
+
+ view.dehydrate();
+ expect(() => dispatchClick(view.nodes[0])).not.toThrow();
+ expect(called).toEqual(0);
+ });
+
+ it('should support custom event emitters', () => {
+ var pv = new ProtoView(el(''),
+ new DynamicProtoChangeDetector(null), null);
+ pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, [EventEmitterDirective]));
+ pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
+
+ createViewAndContext(pv);
+ var dir = view.elementInjectors[0].get(EventEmitterDirective);
+
+ var dispatchedEvent = new Object();
+
+ dir.click(dispatchedEvent);
+ expect(receivedEvent).toBe(dispatchedEvent);
+ expect(called).toEqual(1);
+
+ // Should not eval the binding, because custom emitter takes over.
+ dispatchClick(view.nodes[0]);
+
+ expect(called).toEqual(1);
+ });
+
+ it('should bind to directive events', () => {
+ var pv = new ProtoView(el('
'),
+ new DynamicProtoChangeDetector(null), null);
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirectiveWithEventHandler]));
+ pv.bindEvent('click', parser.parseAction('onEvent($event)', null), 0);
+ view = createView(pv, new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()));
+
+ var directive = view.elementInjectors[0].get(SomeDirectiveWithEventHandler);
+ expect(directive.event).toEqual(null);
+
+ dispatchClick(view.nodes[0]);
+ expect(directive.event).toBe(dispatchedEvent);
+ });
});
-
- it('should not fire on a bubbled native events', () => {
- createViewAndContext(createProtoView());
-
- dispatchClick(view.nodes[0].firstChild);
-
- // This test passes trivially on webkit browsers due to
- // https://bugs.webkit.org/show_bug.cgi?id=122755
- expect(called).toEqual(0);
- });
-
- it('should not throw if the view is dehydrated', () => {
- createViewAndContext(createProtoView());
-
- view.dehydrate();
- expect(() => dispatchClick(view.nodes[0])).not.toThrow();
- expect(called).toEqual(0);
- });
-
- it('should support custom event emitters', () => {
- var pv = new ProtoView(el(''),
- new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new TestProtoElementInjector(null, 0, [EventEmitterDirective]));
- pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
-
- createViewAndContext(pv);
- var dir = view.elementInjectors[0].get(EventEmitterDirective);
-
- var dispatchedEvent = new Object();
-
- dir.click(dispatchedEvent);
- expect(receivedEvent).toBe(dispatchedEvent);
- expect(called).toEqual(1);
-
- // Should not eval the binding, because custom emitter takes over.
- dispatchClick(view.nodes[0]);
-
- expect(called).toEqual(1);
- });
- });
+ }
describe('react to record changes', () => {
var view, cd, ctx;
@@ -533,7 +549,7 @@ export function main() {
it('should consume text node changes', () => {
var pv = new ProtoView(el('{{}}
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindTextNode(0, parser.parseBinding('foo', null));
createViewAndChangeDetector(pv);
@@ -545,7 +561,7 @@ export function main() {
it('should consume element binding changes', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(null);
+ pv.bindElement(null, 0, null);
pv.bindElementProperty(parser.parseBinding('foo', null), 'id', reflector.setter('id'));
createViewAndChangeDetector(pv);
@@ -557,7 +573,7 @@ export function main() {
it('should consume directive watch expression change', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
pv.bindDirectiveProperty(0, parser.parseBinding('foo', null), 'prop', reflector.setter('prop'));
createViewAndChangeDetector(pv);
@@ -570,7 +586,7 @@ export function main() {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 0, [
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
]));
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
@@ -585,27 +601,31 @@ export function main() {
expect(directive.c).toEqual(300);
});
- it('should provide a map of updated properties', () => {
+ it('should provide a map of updated properties using onChange callback', () => {
var pv = new ProtoView(el('
'),
new DynamicProtoChangeDetector(null), null);
- pv.bindElement(new ProtoElementInjector(null, 0, [
+ pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
]));
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
pv.bindDirectiveProperty( 0, parser.parseBinding('b', null), 'b', reflector.setter('b'));
createViewAndChangeDetector(pv);
+ var directive = view.elementInjectors[0].get(DirectiveImplementingOnChange);
+
ctx.a = 0;
ctx.b = 0;
cd.detectChanges();
+ expect(directive.changes).toEqual({
+ "a" : PropertyUpdate.createWithoutPrevious(0),
+ "b" : PropertyUpdate.createWithoutPrevious(0)
+ });
+
ctx.a = 100;
cd.detectChanges();
-
- var directive = view.elementInjectors[0].get(DirectiveImplementingOnChange);
- expect(directive.changes["a"].currentValue).toEqual(100);
- expect(directive.changes["b"]).not.toBeDefined();
+ expect(directive.changes).toEqual({"a" : new PropertyUpdate(100, 0)});
});
});
});
@@ -623,7 +643,7 @@ export function main() {
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
- view.hydrate(new Injector([]), null, null);
+ view.hydrate(new Injector([]), null, null, null, null);
expect(view.rootElementInjectors[0].get(SomeComponent)).not.toBe(null);
});
@@ -632,7 +652,7 @@ export function main() {
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
- view.hydrate(new Injector([]), null, null);
+ view.hydrate(new Injector([]), null, null, null, null);
expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi');
});
});
@@ -660,7 +680,7 @@ class DirectiveImplementingOnChange {
class SomeService {}
-@Component({componentServices: [SomeService]})
+@Component({services: [SomeService]})
class SomeComponent {
service: SomeService;
constructor(service: SomeService) {
@@ -690,7 +710,6 @@ class SomeViewport {
}
}
-
class AnotherDirective {
prop:string;
constructor() {
@@ -708,6 +727,17 @@ class EventEmitterDirective {
}
}
+class SomeDirectiveWithEventHandler {
+ event;
+
+ constructor() {
+ this.event = null;
+ }
+
+ onEvent(event) {
+ this.event = event;
+ }
+}
class MyEvaluationContext {
foo:string;
@@ -727,10 +757,10 @@ class TestProtoElementInjector extends ProtoElementInjector {
super(parent, index, bindings, firstBindingIsComponent);
}
- instantiate(parent:ElementInjector, host:ElementInjector, events):ElementInjector {
+ instantiate(parent:ElementInjector, host:ElementInjector):ElementInjector {
this.parentElementInjector = parent;
this.hostElementInjector = host;
- return super.instantiate(parent, host, events);
+ return super.instantiate(parent, host);
}
}
diff --git a/modules/angular2/test/core/zone/vm_turn_zone_spec.js b/modules/angular2/test/core/zone/vm_turn_zone_spec.js
index 4353ef1d61..fe76da3c25 100644
--- a/modules/angular2/test/core/zone/vm_turn_zone_spec.js
+++ b/modules/angular2/test/core/zone/vm_turn_zone_spec.js
@@ -1,4 +1,15 @@
-import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, async, tick} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xdescribe,
+ xit,
+} from 'angular2/test_lib';
import {Log, once} from 'angular2/test_lib';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {BaseException} from 'angular2/src/facade/lang';
@@ -44,7 +55,7 @@ export function main() {
});
- it('should call onTurnStart and onTurnDone before and after each turn', (done) => {
+ it('should call onTurnStart and onTurnDone before and after each turn', inject([AsyncTestCompleter], (async) => {
var a = PromiseWrapper.completer();
var b = PromiseWrapper.completer();
@@ -59,9 +70,9 @@ export function main() {
PromiseWrapper.all([a.promise, b.promise]).then((_) => {
expect(log.result()).toEqual('onTurnStart; run start; onTurnDone; onTurnStart; a then; onTurnDone; onTurnStart; b then; onTurnDone');
- done();
+ async.done();
});
- });
+ }));
});
describe("runOutsideAngular", () => {
@@ -101,7 +112,7 @@ export function main() {
}).toThrowError('bbb');
});
- it('should produce long stack traces', (done) => {
+ it('should produce long stack traces', inject([AsyncTestCompleter], (async) => {
zone.initCallbacks({onErrorHandler: saveStackTrace});
var c = PromiseWrapper.completer();
@@ -118,11 +129,11 @@ export function main() {
c.promise.then((_) => {
// then number of traces for JS and Dart is different
expect(trace.length).toBeGreaterThan(1);
- done();
+ async.done();
});
- });
+ }));
- it('should produce long stack traces (when using promises)', (done) => {
+ it('should produce long stack traces (when using promises)', inject([AsyncTestCompleter], (async) => {
zone.initCallbacks({onErrorHandler: saveStackTrace});
var c = PromiseWrapper.completer();
@@ -139,11 +150,11 @@ export function main() {
c.promise.then((_) => {
// then number of traces for JS and Dart is different
expect(trace.length).toBeGreaterThan(1);
- done();
+ async.done();
});
- });
+ }));
- it('should disable long stack traces', (done) => {
+ it('should disable long stack traces', inject([AsyncTestCompleter], (async) => {
var zone = new VmTurnZone({enableLongStackTrace: false});
zone.initCallbacks({onErrorHandler: saveStackTrace});
@@ -160,9 +171,9 @@ export function main() {
c.promise.then((_) => {
expect(trace.length).toEqual(1);
- done();
+ async.done();
});
- });
+ }));
});
});
}
diff --git a/modules/angular2/test/di/async_spec.js b/modules/angular2/test/di/async_spec.js
index 52a6a8c88d..4f8b5ad23f 100644
--- a/modules/angular2/test/di/async_spec.js
+++ b/modules/angular2/test/di/async_spec.js
@@ -1,4 +1,14 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {Injector, Inject, InjectPromise, bind, Key} from 'angular2/di';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
@@ -54,17 +64,17 @@ export function main() {
expect(injector.asyncGet(UserList)).toBePromise();
});
- it('should return the injector', function (done) {
+ it('should return the injector', inject([AsyncTestCompleter], (async) => {
var injector = new Injector([]);
var p = injector.asyncGet(Injector);
p.then(function (injector) {
expect(injector).toBe(injector);
- done();
+ async.done();
});
- });
+ }));
it('should return a promise when instantiating a sync binding ' +
- 'with an async dependency', function (done) {
+ 'with an async dependency', inject([AsyncTestCompleter], (async) => {
var injector = new Injector([
bind(UserList).toAsyncFactory(fetchUsers),
UserController
@@ -73,11 +83,11 @@ export function main() {
injector.asyncGet(UserController).then(function (userController) {
expect(userController).toBeAnInstanceOf(UserController);
expect(userController.list).toBeAnInstanceOf(UserList);
- done();
+ async.done();
});
- });
+ }));
- it("should create only one instance (async + async)", function (done) {
+ it("should create only one instance (async + async)", inject([AsyncTestCompleter], (async) => {
var injector = new Injector([
bind(UserList).toAsyncFactory(fetchUsers)
]);
@@ -87,11 +97,11 @@ export function main() {
PromiseWrapper.all([ul1, ul2]).then(function (uls) {
expect(uls[0]).toBe(uls[1]);
- done();
+ async.done();
});
- });
+ }));
- it("should create only one instance (sync + async)", function (done) {
+ it("should create only one instance (sync + async)", inject([AsyncTestCompleter], (async) => {
var injector = new Injector([
UserList
]);
@@ -104,11 +114,11 @@ export function main() {
promise.then(function (ful) {
expect(ful).toBe(ul);
- done();
+ async.done();
});
- });
+ }));
- it('should show the full path when error happens in a constructor', function (done) {
+ it('should show the full path when error happens in a constructor', inject([AsyncTestCompleter], (async) => {
var injector = new Injector([
UserController,
bind(UserList).toAsyncFactory(function () {
@@ -119,9 +129,9 @@ export function main() {
var promise = injector.asyncGet(UserController);
PromiseWrapper.then(promise, null, function (e) {
expect(e.message).toContain("Error during instantiation of UserList! (UserController -> UserList)");
- done();
+ async.done();
});
- });
+ }));
});
describe("get", function () {
@@ -167,4 +177,4 @@ export function main() {
});
});
});
-}
\ No newline at end of file
+}
diff --git a/modules/angular2/test/di/injector_spec.js b/modules/angular2/test/di/injector_spec.js
index 404a338d76..e030a60da6 100644
--- a/modules/angular2/test/di/injector_spec.js
+++ b/modules/angular2/test/di/injector_spec.js
@@ -267,6 +267,11 @@ export function main() {
expect(injector.get(Car)).toBeAnInstanceOf(Car);
});
+ it('should support null values', () => {
+ var injector = new Injector([bind('null').toValue(null)]);
+ expect(injector.get('null')).toBe(null);
+ });
+
describe("default bindings", function () {
it("should be used when no matching binding found", function () {
var injector = new Injector([], {defaultBindings: true});
diff --git a/modules/angular2/test/directives/foreach_spec.js b/modules/angular2/test/directives/foreach_spec.js
index 4d37c660d3..6657814c9d 100644
--- a/modules/angular2/test/directives/foreach_spec.js
+++ b/modules/angular2/test/directives/foreach_spec.js
@@ -1,19 +1,24 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ beforeEachBindings,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Injector} from 'angular2/di';
-import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
-import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
-import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
-import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
-import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
-import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
-import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
-import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
-import {CssProcessor} from 'angular2/src/core/compiler/css_processor';
+import {Compiler} from 'angular2/src/core/compiler/compiler';
+import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {Template} from 'angular2/src/core/annotations/template';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
@@ -22,30 +27,25 @@ import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {Foreach} from 'angular2/src/directives/foreach';
+import {bind} from 'angular2/di';
+
export function main() {
describe('foreach', () => {
var view, cd, compiler, component, tplResolver;
- beforeEach(() => {
- var urlResolver = new UrlResolver();
- tplResolver = new MockTemplateResolver();
- compiler = new Compiler(
- dynamicChangeDetection,
- new TemplateLoader(null, null),
- new DirectiveMetadataReader(),
- new Parser(new Lexer()),
- new CompilerCache(),
- new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
- tplResolver,
- new ComponentUrlMapper(),
- urlResolver,
- new CssProcessor(null)
- );
- });
+
+ beforeEachBindings(() => [
+ bind(TemplateResolver).toClass(MockTemplateResolver),
+ ]);
+
+ beforeEach(inject([Compiler, TemplateResolver], (c, t) => {
+ compiler = c;
+ tplResolver = t;
+ }));
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, component);
+ view.hydrate(new Injector([]), null, null, component, null);
cd = view.changeDetector;
}
@@ -60,17 +60,17 @@ export function main() {
var TEMPLATE = '{{item.toString()}};
';
- it('should reflect initial elements', (done) => {
+ it('should reflect initial elements', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('1;2;');
- done();
+ async.done();
});
- });
+ }));
- it('should reflect added elements', (done) => {
+ it('should reflect added elements', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
@@ -79,11 +79,11 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('1;2;3;');
- done();
+ async.done();
});
- });
+ }));
- it('should reflect removed elements', (done) => {
+ it('should reflect removed elements', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
@@ -92,11 +92,11 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('1;');
- done();
+ async.done();
});
- });
+ }));
- it('should reflect moved elements', (done) => {
+ it('should reflect moved elements', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
@@ -106,11 +106,11 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('2;1;');
- done();
+ async.done();
});
- });
+ }));
- it('should reflect a mix of all changes (additions/removals/moves)', (done) => {
+ it('should reflect a mix of all changes (additions/removals/moves)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
component.items = [0, 1, 2, 3, 4, 5];
@@ -120,9 +120,9 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('6;2;7;0;4;8;');
- done();
+ async.done();
});
- });
+ }));
it('should iterate over an array of objects', () => {
compileWithTemplate('').then((pv) => {
@@ -148,16 +148,16 @@ export function main() {
});
});
- it('should gracefully handle nulls', (done) => {
+ it('should gracefully handle nulls', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('').then((pv) => {
createView(pv);
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('');
- done();
+ async.done();
});
- });
+ }));
- it('should gracefully handle ref changing to null and back', (done) => {
+ it('should gracefully handle ref changing to null and back', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
@@ -170,11 +170,11 @@ export function main() {
component.items = [1, 2, 3];
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('1;2;3;');
- done();
+ async.done();
});
- });
+ }));
- it('should throw on ref changing to string', (done) => {
+ it('should throw on ref changing to string', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
cd.detectChanges();
@@ -182,54 +182,53 @@ export function main() {
component.items = 'whaaa';
expect(() => cd.detectChanges()).toThrowError();
- done();
+ async.done();
});
- });
+ }));
- it('should works with duplicates', (done) => {
+ it('should works with duplicates', inject([AsyncTestCompleter], (async) => {
compileWithTemplate(TEMPLATE).then((pv) => {
createView(pv);
var a = new Foo();
component.items = [a, a];
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('foo;foo;');
- done();
+ async.done();
});
- });
+ }));
- it('should repeat over nested arrays', (done) => {
- compileWithTemplate(
- '' +
- '
' +
- '{{subitem}};' +
- '
|
'
- ).then((pv) => {
- createView(pv);
- component.items = [['a', 'b'], ['c','d']];
- cd.detectChanges();
- cd.detectChanges();
- cd.detectChanges();
- expect(DOM.getText(view.nodes[0])).toEqual('a;b;|c;d;|');
- done();
- });
- });
+ it('should repeat over nested arrays', inject([AsyncTestCompleter], (async) => {
+ compileWithTemplate(
+ '' +
+ '
' +
+ '{{subitem}}-{{item.length}};' +
+ '
|
'
+ ).then((pv) => {
+ createView(pv);
+ component.items = [['a', 'b'], ['c']];
+ cd.detectChanges();
+ cd.detectChanges();
+ cd.detectChanges();
+ expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;|c-1;|');
+ async.done();
+ });
+ }));
+ it('should display indices correctly', inject([AsyncTestCompleter], (async) => {
+ var INDEX_TEMPLATE =
+ '{{i.toString()}}
';
+ compileWithTemplate(INDEX_TEMPLATE).then((pv) => {
+ createView(pv);
+ component.items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ cd.detectChanges();
+ expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
- it('should display indices correctly', (done) => {
- var INDEX_TEMPLATE =
- '{{i.toString()}}
';
- compileWithTemplate(INDEX_TEMPLATE).then((pv) => {
- createView(pv);
- component.items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- cd.detectChanges();
- expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
-
- component.items = [1, 2, 6, 7, 4, 3, 5, 8, 9, 0];
- cd.detectChanges();
- expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
- done();
- });
- });
+ component.items = [1, 2, 6, 7, 4, 3, 5, 8, 9, 0];
+ cd.detectChanges();
+ expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
+ async.done();
+ });
+ }));
});
}
@@ -243,7 +242,6 @@ class Foo {
@Component({selector: 'test-cmp'})
class TestComponent {
items: any;
- item: any;
constructor() {
this.items = [1, 2];
}
diff --git a/modules/angular2/test/directives/if_spec.js b/modules/angular2/test/directives/if_spec.js
index 8c56515c28..3e753857c4 100644
--- a/modules/angular2/test/directives/if_spec.js
+++ b/modules/angular2/test/directives/if_spec.js
@@ -1,4 +1,16 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ IS_DARTIUM,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
@@ -45,7 +57,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, component);
+ view.hydrate(new Injector([]), null, null, component, null);
cd = view.changeDetector;
}
@@ -58,53 +70,53 @@ export function main() {
return compiler.compile(TestComponent);
}
- it('should work in a template attribute', (done) => {
+ it('should work in a template attribute', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('hello
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
- done();
+ async.done();
});
- });
+ }));
- it('should work in a template element', (done) => {
+ it('should work in a template element', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('hello2
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello2');
- done();
+ async.done();
});
- });
+ }));
- it('should toggle node when condition changes', (done) => {
+ it('should toggle node when condition changes', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('hello
').then((pv) => {
createView(pv);
component.booleanCondition = false;
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
expect(DOM.getText(view.nodes[0])).toEqual('');
component.booleanCondition = true;
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
component.booleanCondition = false;
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
expect(DOM.getText(view.nodes[0])).toEqual('');
- done();
+ async.done();
});
- });
+ }));
- it('should update several nodes with if', (done) => {
+ it('should update several nodes with if', inject([AsyncTestCompleter], (async) => {
var templateString =
'' +
'
helloNumber ' +
@@ -115,76 +127,76 @@ export function main() {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(3);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(3);
expect(DOM.getText(view.nodes[0])).toEqual('helloNumberhelloStringhelloFunction');
component.numberCondition = 0;
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('helloString');
component.numberCondition = 1;
component.stringCondition = "bar";
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('helloNumber');
- done();
+ async.done();
});
- });
+ }));
if (!IS_DARTIUM) {
- it('should leave the element if the condition is a non-empty string (JS)', (done) => {
+ it('should leave the element if the condition is a non-empty string (JS)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
- done();
+ async.done();
});
- });
+ }));
- it('should leave the element if the condition is an object (JS)', (done) => {
+ it('should leave the element if the condition is an object (JS)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
- done();
+ async.done();
});
- });
+ }));
- it('should remove the element if the condition is null (JS)', (done) => {
+ it('should remove the element if the condition is null (JS)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
expect(DOM.getText(view.nodes[0])).toEqual('');
- done();
+ async.done();
});
- });
+ }));
- it('should not add the element twice if the condition goes from true to true (JS)', (done) => {
+ it('should not add the element twice if the condition goes from true to true (JS)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
component.numberCondition = 2;
cd.detectChanges();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
expect(DOM.getText(view.nodes[0])).toEqual('hello');
- done();
+ async.done();
});
- });
+ }));
- it('should not recreate the element if the condition goes from true to true (JS)', (done) => {
+ it('should not recreate the element if the condition goes from true to true (JS)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
@@ -195,19 +207,19 @@ export function main() {
cd.detectChanges();
expect(DOM.hasClass(view.nodes[0].childNodes[1], "foo")).toBe(true);
- done();
+ async.done();
});
- });
+ }));
} else {
- it('should not create the element if the condition is not a boolean (DART)', (done) => {
+ it('should not create the element if the condition is not a boolean (DART)', inject([AsyncTestCompleter], (async) => {
compileWithTemplate('
hello
').then((pv) => {
createView(pv);
expect(function(){cd.detectChanges();}).toThrowError();
- expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
+ expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
expect(DOM.getText(view.nodes[0])).toEqual('');
- done();
+ async.done();
});
- });
+ }));
}
});
diff --git a/modules/angular2/test/directives/non_bindable_spec.js b/modules/angular2/test/directives/non_bindable_spec.js
index f42ccf0184..b256fb5e10 100644
--- a/modules/angular2/test/directives/non_bindable_spec.js
+++ b/modules/angular2/test/directives/non_bindable_spec.js
@@ -1,4 +1,15 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@@ -43,7 +54,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, component);
+ view.hydrate(new Injector([]), null, null, component, null);
cd = view.changeDetector;
}
@@ -56,37 +67,37 @@ export function main() {
return compiler.compile(TestComponent);
}
- it('should not interpolate children', (done) => {
+ it('should not interpolate children', inject([AsyncTestCompleter], (async) => {
var template = '
{{text}}{{text}}
';
compileWithTemplate(template).then((pv) => {
createView(pv);
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('foo{{text}}');
- done();
+ async.done();
});
- });
+ }));
- it('should ignore directives on child nodes', (done) => {
+ it('should ignore directives on child nodes', inject([AsyncTestCompleter], (async) => {
var template = '
{{text}}
';
compileWithTemplate(template).then((pv) => {
createView(pv);
cd.detectChanges();
var span = DOM.querySelector(view.nodes[0], '#child');
expect(DOM.hasClass(span, 'compiled')).toBeFalsy();
- done();
+ async.done();
});
- });
+ }));
- it('should trigger directives on the same node', (done) => {
+ it('should trigger directives on the same node', inject([AsyncTestCompleter], (async) => {
var template = '
{{text}}
';
compileWithTemplate(template).then((pv) => {
createView(pv);
cd.detectChanges();
var span = DOM.querySelector(view.nodes[0], '#child');
expect(DOM.hasClass(span, 'compiled')).toBeTruthy();
- done();
+ async.done();
});
- });
+ }));
})
}
diff --git a/modules/angular2/test/directives/switch_spec.js b/modules/angular2/test/directives/switch_spec.js
index e83a621f3c..ea5ecaa342 100644
--- a/modules/angular2/test/directives/switch_spec.js
+++ b/modules/angular2/test/directives/switch_spec.js
@@ -1,4 +1,15 @@
-import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Injector} from 'angular2/di';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
@@ -40,7 +51,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, component);
+ view.hydrate(new Injector([]), null, null, component, null);
cd = view.changeDetector;
}
@@ -54,7 +65,7 @@ export function main() {
}
describe('switch value changes', () => {
- it('should switch amongst when values', (done) => {
+ it('should switch amongst when values', inject([AsyncTestCompleter], (async) => {
var template = '
' +
'
' +
'when a ' +
@@ -73,11 +84,11 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('when b');
- done();
+ async.done();
});
- });
+ }));
- it('should switch amongst when values with fallback to default', (done) => {
+ it('should switch amongst when values with fallback to default', inject([AsyncTestCompleter], (async) => {
var template = '' +
'
' +
'when a ' +
@@ -96,11 +107,11 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('when default');
- done();
+ async.done();
});
- });
+ }));
- it('should support multiple whens with the same value', (done) => {
+ it('should support multiple whens with the same value', inject([AsyncTestCompleter], (async) => {
var template = '' +
'
' +
'when a1; ' +
@@ -123,13 +134,13 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('when b1;when b2;');
- done();
+ async.done();
});
- });
+ }));
});
describe('when values changes', () => {
- it('should switch amongst when values', (done) => {
+ it('should switch amongst when values', inject([AsyncTestCompleter], (async) => {
var template = '' +
'
' +
'when 1; ' +
@@ -161,9 +172,9 @@ export function main() {
cd.detectChanges();
expect(DOM.getText(view.nodes[0])).toEqual('when default;');
- done();
+ async.done();
});
- });
+ }));
});
});
}
diff --git a/modules/angular2/test/forms/form_builder_spec.js b/modules/angular2/test/forms/form_builder_spec.js
new file mode 100644
index 0000000000..94fda5f4b5
--- /dev/null
+++ b/modules/angular2/test/forms/form_builder_spec.js
@@ -0,0 +1,65 @@
+import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, el} from 'angular2/test_lib';
+import {Control, FormBuilder} from 'angular2/forms';
+import * as validations from 'angular2/forms';
+
+export function main() {
+ describe("Form Builder", () => {
+ var b;
+
+ beforeEach(() => {
+ b = new FormBuilder();
+ });
+
+ it("should create controls from a value", () => {
+ var g = b.group({
+ "login": "some value"
+ });
+
+ expect(g.controls["login"].value).toEqual("some value");
+ });
+
+ it("should create controls from an array", () => {
+ var g = b.group({
+ "login": ["some value"],
+ "password": ["some value", validations.required]
+ });
+
+ expect(g.controls["login"].value).toEqual("some value");
+ expect(g.controls["password"].value).toEqual("some value");
+ expect(g.controls["password"].validator).toEqual(validations.required);
+ });
+
+ it("should use controls", () => {
+ var g = b.group({
+ "login": b.control("some value", validations.required)
+ });
+
+ expect(g.controls["login"].value).toEqual("some value");
+ expect(g.controls["login"].validator).toBe(validations.required);
+ });
+
+ it("should create groups with optional controls", () => {
+ var g = b.group({
+ "login": "some value"
+ }, {"optionals": {"login" : false}});
+
+ expect(g.contains("login")).toEqual(false);
+ });
+
+ it("should create groups with a custom validator", () => {
+ var g = b.group({
+ "login": "some value"
+ }, {"validator": validations.nullValidator});
+
+ expect(g.validator).toBe(validations.nullValidator);
+ });
+
+ it("should use default validators when no validators are provided", () => {
+ var g = b.group({
+ "login": "some value"
+ });
+ expect(g.controls["login"].validator).toBe(validations.nullValidator);
+ expect(g.validator).toBe(validations.controlGroupValidator);
+ });
+ });
+}
\ No newline at end of file
diff --git a/modules/angular2/test/forms/integration_spec.js b/modules/angular2/test/forms/integration_spec.js
index e5245963bd..066839fbe8 100644
--- a/modules/angular2/test/forms/integration_spec.js
+++ b/modules/angular2/test/forms/integration_spec.js
@@ -1,5 +1,19 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach,
- el, queryView, dispatchEvent} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ dispatchEvent,
+ el,
+ expect,
+ iit,
+ inject,
+ it,
+ queryView,
+ xit,
+ IS_NODEJS
+} from 'angular2/test_lib';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
@@ -49,14 +63,14 @@ export function main() {
compiler.compile(componentType).then((pv) => {
var view = pv.instantiate(null, null);
- view.hydrate(new Injector([]), null, context);
+ view.hydrate(new Injector([]), null, null, context, null);
detectChanges(view);
callback(view);
});
}
describe("integration tests", () => {
- it("should initialize DOM elements with the given form object", (done) => {
+ it("should initialize DOM elements with the given form object", inject([AsyncTestCompleter], (async) => {
var ctx = new MyComp(new ControlGroup({
"login": new Control("loginValue")
}));
@@ -68,32 +82,34 @@ export function main() {
compile(MyComp, t, ctx, (view) => {
var input = queryView(view, "input")
expect(input.value).toEqual("loginValue");
- done();
+ async.done();
});
- });
+ }));
- it("should update the control group values on DOM change", (done) => {
- var form = new ControlGroup({
- "login": new Control("oldValue")
- });
- var ctx = new MyComp(form);
+ if (!IS_NODEJS) {
+ it("should update the control group values on DOM change", inject([AsyncTestCompleter], (async) => {
+ var form = new ControlGroup({
+ "login": new Control("oldValue")
+ });
+ var ctx = new MyComp(form);
- var t = `
-
-
`;
+ var t = `
+
+
`;
- compile(MyComp, t, ctx, (view) => {
- var input = queryView(view, "input")
+ compile(MyComp, t, ctx, (view) => {
+ var input = queryView(view, "input")
- input.value = "updatedValue";
- dispatchEvent(input, "change");
+ input.value = "updatedValue";
+ dispatchEvent(input, "change");
- expect(form.value).toEqual({"login": "updatedValue"});
- done();
- });
- });
+ expect(form.value).toEqual({"login": "updatedValue"});
+ async.done();
+ });
+ }));
+ }
- it("should update DOM elements when rebinding the control group", (done) => {
+ it("should update DOM elements when rebinding the control group", inject([AsyncTestCompleter], (async) => {
var form = new ControlGroup({
"login": new Control("oldValue")
});
@@ -111,11 +127,11 @@ export function main() {
var input = queryView(view, "input")
expect(input.value).toEqual("newValue");
- done();
+ async.done();
});
- });
+ }));
- it("should update DOM element when rebinding the control name", (done) => {
+ it("should update DOM element when rebinding the control name", inject([AsyncTestCompleter], (async) => {
var ctx = new MyComp(new ControlGroup({
"one": new Control("one"),
"two": new Control("two")
@@ -133,96 +149,98 @@ export function main() {
detectChanges(view);
expect(input.value).toEqual("two");
- done();
+ async.done();
});
- });
+ }));
- describe("different control types", () => {
- it("should support type=checkbox", (done) => {
- var ctx = new MyComp(new ControlGroup({"checkbox": new Control(true)}));
+ if (!IS_NODEJS) {
+ describe("different control types", () => {
+ it("should support type=checkbox", inject([AsyncTestCompleter], (async) => {
+ var ctx = new MyComp(new ControlGroup({"checkbox": new Control(true)}));
- var t = `
-
-
`;
+ var t = `
+
+
`;
- compile(MyComp, t, ctx, (view) => {
- var input = queryView(view, "input")
- expect(input.checked).toBe(true);
+ compile(MyComp, t, ctx, (view) => {
+ var input = queryView(view, "input")
+ expect(input.checked).toBe(true);
- input.checked = false;
- dispatchEvent(input, "change");
+ input.checked = false;
+ dispatchEvent(input, "change");
- expect(ctx.form.value).toEqual({"checkbox" : false});
- done();
- });
+ expect(ctx.form.value).toEqual({"checkbox" : false});
+ async.done();
+ });
+ }));
+
+ it("should support custom value accessors", inject([AsyncTestCompleter], (async) => {
+ var ctx = new MyComp(new ControlGroup({"name": new Control("aa")}));
+
+ var t = `
+
+
`;
+
+ compile(MyComp, t, ctx, (view) => {
+ var input = queryView(view, "input")
+ expect(input.value).toEqual("!aa!");
+
+ input.value = "!bb!";
+ dispatchEvent(input, "change");
+
+ expect(ctx.form.value).toEqual({"name" : "bb"});
+ async.done();
+ });
+ }));
});
- it("should support custom value accessors", (done) => {
- var ctx = new MyComp(new ControlGroup({"name": new Control("aa")}));
+ describe("validations", () => {
+ it("should use validators defined in html", inject([AsyncTestCompleter], (async) => {
+ var form = new ControlGroup({"login": new Control("aa")});
+ var ctx = new MyComp(form);
- var t = `
-
-
`;
+ var t = `
+
+
`;
- compile(MyComp, t, ctx, (view) => {
- var input = queryView(view, "input")
- expect(input.value).toEqual("!aa!");
+ compile(MyComp, t, ctx, (view) => {
+ expect(form.valid).toEqual(true);
- input.value = "!bb!";
- dispatchEvent(input, "change");
+ var input = queryView(view, "input");
- expect(ctx.form.value).toEqual({"name" : "bb"});
- done();
- });
+ input.value = "";
+ dispatchEvent(input, "change");
+
+ expect(form.valid).toEqual(false);
+ async.done();
+ });
+ }));
+
+ it("should use validators defined in the model", inject([AsyncTestCompleter], (async) => {
+ var form = new ControlGroup({"login": new Control("aa", validators.required)});
+ var ctx = new MyComp(form);
+
+ var t = `
+
+
`;
+
+ compile(MyComp, t, ctx, (view) => {
+ expect(form.valid).toEqual(true);
+
+ var input = queryView(view, "input");
+
+ input.value = "";
+ dispatchEvent(input, "change");
+
+ expect(form.valid).toEqual(false);
+ async.done();
+ });
+ }));
});
- });
-
- describe("validations", () => {
- it("should use validators defined in html",(done) => {
- var form = new ControlGroup({"login": new Control("aa")});
- var ctx = new MyComp(form);
-
- var t = `
-
-
`;
-
- compile(MyComp, t, ctx, (view) => {
- expect(form.valid).toEqual(true);
-
- var input = queryView(view, "input");
-
- input.value = "";
- dispatchEvent(input, "change");
-
- expect(form.valid).toEqual(false);
- done();
- });
- });
-
- it("should use validators defined in the model",(done) => {
- var form = new ControlGroup({"login": new Control("aa", validators.required)});
- var ctx = new MyComp(form);
-
- var t = `
-
-
`;
-
- compile(MyComp, t, ctx, (view) => {
- expect(form.valid).toEqual(true);
-
- var input = queryView(view, "input");
-
- input.value = "";
- dispatchEvent(input, "change");
-
- expect(form.valid).toEqual(false);
- done();
- });
- });
- });
+ }
describe("nested forms", () => {
- it("should init DOM with the given form object", (done) => {
+ it("should init DOM with the given form object",inject([AsyncTestCompleter], (async) => {
var form = new ControlGroup({
"nested": new ControlGroup({
"login": new Control("value")
@@ -239,34 +257,36 @@ export function main() {
compile(MyComp, t, ctx, (view) => {
var input = queryView(view, "input")
expect(input.value).toEqual("value");
- done();
+ async.done();
});
- });
+ }));
- it("should update the control group values on DOM change", (done) => {
- var form = new ControlGroup({
- "nested": new ControlGroup({
- "login": new Control("value")
- })
- });
- var ctx = new MyComp(form);
+ if (!IS_NODEJS) {
+ it("should update the control group values on DOM change", inject([AsyncTestCompleter], (async) => {
+ var form = new ControlGroup({
+ "nested": new ControlGroup({
+ "login": new Control("value")
+ })
+ });
+ var ctx = new MyComp(form);
- var t = ``;
+ var t = ``;
- compile(MyComp, t, ctx, (view) => {
- var input = queryView(view, "input")
+ compile(MyComp, t, ctx, (view) => {
+ var input = queryView(view, "input")
- input.value = "updatedValue";
- dispatchEvent(input, "change");
+ input.value = "updatedValue";
+ dispatchEvent(input, "change");
- expect(form.value).toEqual({"nested" : {"login" : "updatedValue"}});
- done();
- });
- });
+ expect(form.value).toEqual({"nested" : {"login" : "updatedValue"}});
+ async.done();
+ });
+ }));
+ }
});
});
}
diff --git a/modules/angular2/test/forms/model_spec.js b/modules/angular2/test/forms/model_spec.js
index 65e405e8f9..8b81f30bcf 100644
--- a/modules/angular2/test/forms/model_spec.js
+++ b/modules/angular2/test/forms/model_spec.js
@@ -84,56 +84,68 @@ export function main() {
expect(g.errors).toEqual(null);
});
});
- });
- describe("OptionalControl", () => {
- it("should read properties from the wrapped component", () => {
- var wrapperControl = new Control("value", validations.required);
- var c = new OptionalControl(wrapperControl, true);
+ describe("optional components", () => {
+ describe("contains", () => {
+ var group;
- expect(c.value).toEqual('value');
- expect(c.status).toEqual('VALID');
- expect(c.validator).toEqual(validations.required);
- });
+ beforeEach(() => {
+ group = new ControlGroup({
+ "required": new Control("requiredValue"),
+ "optional": new Control("optionalValue")
+ }, {
+ "optional": false
+ });
+ });
- it("should update the wrapped component", () => {
- var wrappedControl = new Control("value");
- var c = new OptionalControl(wrappedControl, true);
+ // rename contains into has
+ it("should return false when the component is not included", () => {
+ expect(group.contains("optional")).toEqual(false);
+ })
- c.validator = validations.required;
- c.updateValue("newValue");
+ it("should return false when there is no component with the given name", () => {
+ expect(group.contains("something else")).toEqual(false);
+ });
+ it("should return true when the component is included", () => {
+ expect(group.contains("required")).toEqual(true);
- expect(wrappedControl.validator).toEqual(validations.required);
- expect(wrappedControl.value).toEqual('newValue');
- });
+ group.include("optional");
- it("should not include an inactive component into the group value", () => {
- var group = new ControlGroup({
- "required" : new Control("requiredValue"),
- "optional" : new OptionalControl(new Control("optionalValue"), false)
+ expect(group.contains("optional")).toEqual(true);
+ });
});
- expect(group.value).toEqual({"required" : "requiredValue"});
+ it("should not include an inactive component into the group value", () => {
+ var group = new ControlGroup({
+ "required": new Control("requiredValue"),
+ "optional": new Control("optionalValue")
+ }, {
+ "optional": false
+ });
- group.controls["optional"].cond = true;
+ expect(group.value).toEqual({"required" : "requiredValue"});
- expect(group.value).toEqual({"required" : "requiredValue", "optional" : "optionalValue"});
- });
+ group.include("optional");
- it("should not run validations on an inactive component", () => {
- var group = new ControlGroup({
- "required" : new Control("requiredValue", validations.required),
- "optional" : new OptionalControl(new Control("", validations.required), false)
+ expect(group.value).toEqual({"required" : "requiredValue", "optional" : "optionalValue"});
});
- expect(group.valid).toEqual(true);
+ it("should not run validations on an inactive component", () => {
+ var group = new ControlGroup({
+ "required": new Control("requiredValue", validations.required),
+ "optional": new Control("", validations.required)
+ }, {
+ "optional": false
+ });
- group.controls["optional"].cond = true;
+ expect(group.valid).toEqual(true);
- expect(group.valid).toEqual(false);
+ group.include("optional");
+
+ expect(group.valid).toEqual(false);
+ });
});
});
-
});
-}
\ No newline at end of file
+}
diff --git a/modules/angular2/test/mock/xhr_mock_spec.js b/modules/angular2/test/mock/xhr_mock_spec.js
index a2b7afa671..73460d4caa 100644
--- a/modules/angular2/test/mock/xhr_mock_spec.js
+++ b/modules/angular2/test/mock/xhr_mock_spec.js
@@ -1,4 +1,15 @@
-import {describe, beforeEach, it, expect, ddescribe, iit, el, IS_DARTIUM} from 'angular2/test_lib';
+import {
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ el,
+ expect,
+ iit,
+ inject,
+ IS_DARTIUM,
+ it,
+} from 'angular2/test_lib';
import {XHRMock} from 'angular2/src/mock/xhr_mock';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {isPresent} from 'angular2/src/facade/lang';
@@ -33,37 +44,37 @@ export function main() {
PromiseWrapper.then(request, onResponse, onError);
}
- it('should return a response from the definitions', (done) => {
+ it('should return a response from the definitions', inject([AsyncTestCompleter], (async) => {
var url = '/foo';
var response = 'bar';
xhr.when(url, response);
- expectResponse(xhr.get(url), url, response, done);
+ expectResponse(xhr.get(url), url, response, () => async.done());
xhr.flush();
- });
+ }));
- it('should return an error from the definitions', (done) => {
+ it('should return an error from the definitions', inject([AsyncTestCompleter], (async) => {
var url = '/foo';
var response = null;
xhr.when(url, response);
- expectResponse(xhr.get(url), url, response, done);
+ expectResponse(xhr.get(url), url, response, () => async.done());
xhr.flush();
- });
+ }));
- it('should return a response from the expectations', (done) => {
+ it('should return a response from the expectations', inject([AsyncTestCompleter], (async) => {
var url = '/foo';
var response = 'bar';
xhr.expect(url, response);
- expectResponse(xhr.get(url), url, response, done);
+ expectResponse(xhr.get(url), url, response, () => async.done());
xhr.flush();
- });
+ }));
- it('should return an error from the expectations', (done) => {
+ it('should return an error from the expectations', inject([AsyncTestCompleter], (async) => {
var url = '/foo';
var response = null;
xhr.expect(url, response);
- expectResponse(xhr.get(url), url, response, done);
+ expectResponse(xhr.get(url), url, response, () => async.done());
xhr.flush();
- });
+ }));
it('should not reuse expectations', () => {
var url = '/foo';
@@ -76,14 +87,14 @@ export function main() {
}).toThrowError('Unexpected request /foo');
});
- it('should return expectations before definitions', (done) => {
+ it('should return expectations before definitions', inject([AsyncTestCompleter], (async) => {
var url = '/foo';
xhr.when(url, 'when');
xhr.expect(url, 'expect');
expectResponse(xhr.get(url), url, 'expect');
- expectResponse(xhr.get(url), url, 'when', done);
+ expectResponse(xhr.get(url), url, 'when', () => async.done());
xhr.flush();
- });
+ }));
it('should throw when there is no definitions or expectations', () => {
xhr.get('/foo');
diff --git a/modules/angular2/test/services/title_spec.js b/modules/angular2/test/services/title_spec.js
new file mode 100644
index 0000000000..ba2397be46
--- /dev/null
+++ b/modules/angular2/test/services/title_spec.js
@@ -0,0 +1,32 @@
+import {ddescribe, describe, it, iit, xit, expect, afterEach} from 'angular2/test_lib';
+import {DOM} from 'angular2/src/dom/dom_adapter';
+
+import {Title} from 'angular2/src/services/title';
+
+export function main() {
+
+ describe('title service', () => {
+ var initialTitle = DOM.getTitle();
+ var titleService = new Title();
+
+ afterEach(() => {
+ DOM.setTitle(initialTitle);
+ });
+
+ it('should allow reading initial title', () => {
+ expect(titleService.getTitle()).toEqual(initialTitle);
+ });
+
+ it('should set a title on the injected document', () => {
+ titleService.setTitle('test title');
+ expect(DOM.getTitle()).toEqual('test title');
+ expect(titleService.getTitle()).toEqual('test title');
+ });
+
+ it('should reset title to empty string if title not provided', () => {
+ titleService.setTitle(null);
+ expect(DOM.getTitle()).toEqual('');
+ });
+
+ });
+}
diff --git a/modules/angular2/test/test_lib/test_lib_spec.js b/modules/angular2/test/test_lib/test_lib_spec.js
index 8b84ecfa33..93d7feb301 100644
--- a/modules/angular2/test/test_lib/test_lib_spec.js
+++ b/modules/angular2/test/test_lib/test_lib_spec.js
@@ -1,6 +1,6 @@
import {describe, it, iit, ddescribe, expect, tick, async, SpyObject, beforeEach, proxy} from 'angular2/test_lib';
-import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
-import {IMPLEMENTS, Date, DateWrapper} from 'angular2/src/facade/lang';
+import {MapWrapper} from 'angular2/src/facade/collection';
+import {IMPLEMENTS} from 'angular2/src/facade/lang';
class TestObj {
prop;
@@ -24,19 +24,6 @@ export function main() {
expect(actual).toEqual(expected);
expect(falseActual).not.toEqual(expected);
});
-
- it('should structurally compare objects with private and static fields', () => {
- expect(DateWrapper.fromMillis(1)).toEqual(DateWrapper.fromMillis(1));
- });
-
- it('should work for arrays of string maps', () => {
- expect([{'a':'b'}]).toEqual([{'a':'b'}]);
- });
-
- it('should work for arrays of real maps', () => {
- expect([MapWrapper.createFromStringMap({'a':'b'})]).toEqual([MapWrapper.createFromStringMap({'a':'b'})]);
- expect([MapWrapper.createFromStringMap({'a':'b'})]).not.toEqual([MapWrapper.createFromStringMap({'a':'c'})]);
- });
});
describe('toEqual for Maps', () => {
diff --git a/modules/angular2/test/transform/basic_bind_files/bar.dart b/modules/angular2/test/transform/basic_bind_files/bar.dart
deleted file mode 100644
index 6c9c91fdaa..0000000000
--- a/modules/angular2/test/transform/basic_bind_files/bar.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-library bar;
-
-import 'package:angular2/src/core/annotations/annotations.dart';
-
-@Component(selector: 'soup', componentServices: const [ToolTip])
-class MyComponent {}
-
-@Decorator(selector: '[tool-tip]', bind: const {'text': 'tool-tip'})
-class ToolTip {
- String text;
-}
diff --git a/modules/angular2/test/transform/basic_bind_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/basic_bind_files/expected/index.bootstrap.dart
deleted file mode 100644
index 58bb31464d..0000000000
--- a/modules/angular2/test/transform/basic_bind_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'package:angular2/src/core/annotations/annotations.dart' as i1;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory": () => new i0.MyComponent(),
- "parameters": const [const []],
- "annotations": const [
- const i1.Component(
- selector: 'soup', componentServices: const [i0.ToolTip])
- ]
- })
- ..registerType(i0.ToolTip, {
- "factory": () => new i0.ToolTip(),
- "parameters": const [const []],
- "annotations": const [
- const i1.Decorator(
- selector: '[tool-tip]', bind: const {'text': 'tool-tip'})
- ]
- })
- ..registerSetters({"text": (i0.ToolTip o, String value) => o.text = value});
-}
diff --git a/modules/angular2/test/transform/bind_generator/all_tests.dart b/modules/angular2/test/transform/bind_generator/all_tests.dart
new file mode 100644
index 0000000000..da1beb4694
--- /dev/null
+++ b/modules/angular2/test/transform/bind_generator/all_tests.dart
@@ -0,0 +1,42 @@
+library angular2.test.transform.bind_generator.all_tests;
+
+import 'dart:io';
+import 'package:barback/barback.dart';
+import 'package:angular2/src/transform/bind_generator/generator.dart';
+import 'package:angular2/src/transform/common/formatter.dart';
+import 'package:code_transformers/tests.dart';
+import 'package:dart_style/dart_style.dart';
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/vm_config.dart';
+
+import '../common/read_file.dart';
+
+var formatter = new DartFormatter();
+
+void allTests() {
+ var reader = new TestAssetReader();
+
+ test('should generate a setter for a `bind` property in an annotation.',
+ () async {
+ var inputPath = 'bind_generator/basic_bind_files/bar.ng_deps.dart';
+ var expected = formatter.format(
+ readFile('bind_generator/basic_bind_files/expected/bar.ng_deps.dart'));
+
+ var output = formatter
+ .format(await createNgSetters(reader, new AssetId('a', inputPath)));
+ expect(output, equals(expected));
+ });
+
+ test('should generate a single setter when multiple annotations bind to the '
+ 'same property.', () async {
+ var inputPath =
+ 'bind_generator/duplicate_bind_name_files/soup.ng_deps.dart';
+ var expected = formatter.format(readFile(
+ 'bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart'));
+
+ var output = formatter
+ .format(await createNgSetters(reader, new AssetId('a', inputPath)));
+ expect(output, equals(expected));
+ });
+}
diff --git a/modules/angular2/test/transform/bind_generator/basic_bind_files/bar.ng_deps.dart b/modules/angular2/test/transform/bind_generator/basic_bind_files/bar.ng_deps.dart
new file mode 100644
index 0000000000..927ce2f4ea
--- /dev/null
+++ b/modules/angular2/test/transform/bind_generator/basic_bind_files/bar.ng_deps.dart
@@ -0,0 +1,19 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(ToolTip, {
+ 'factory': () => new ToolTip(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Decorator(
+ selector: '[tool-tip]', bind: const {'text': 'tool-tip'})
+ ]
+ });
+}
diff --git a/modules/angular2/test/transform/bind_generator/basic_bind_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/bind_generator/basic_bind_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..ba66daa570
--- /dev/null
+++ b/modules/angular2/test/transform/bind_generator/basic_bind_files/expected/bar.ng_deps.dart
@@ -0,0 +1,20 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(ToolTip, {
+ 'factory': () => new ToolTip(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Decorator(
+ selector: '[tool-tip]', bind: const {'text': 'tool-tip'})
+ ]
+ })
+ ..registerSetters({'text': (o, String v) => o.text = v});
+}
diff --git a/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart b/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart
new file mode 100644
index 0000000000..ba3be64323
--- /dev/null
+++ b/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart
@@ -0,0 +1,26 @@
+library dinner.soup;
+
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'soup.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(SoupComponent, {
+ 'factory': () => new SoupComponent(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Component(
+ componentServices: const [SaladComponent],
+ bind: const {'menu': 'menu'})
+ ]
+ })
+ ..registerType(SaladComponent, {
+ 'factory': () => new SaladComponent(),
+ 'parameters': const [],
+ 'annotations': const [const Component(bind: const {'menu': 'menu'})]
+ })
+ ..registerSetters({'menu': (o, String v) => o.menu = v});
+}
diff --git a/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/soup.ng_deps.dart b/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/soup.ng_deps.dart
new file mode 100644
index 0000000000..7f88110003
--- /dev/null
+++ b/modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/soup.ng_deps.dart
@@ -0,0 +1,25 @@
+library dinner.soup;
+
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'soup.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(SoupComponent, {
+ 'factory': () => new SoupComponent(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Component(
+ componentServices: const [SaladComponent],
+ bind: const {'menu': 'menu'})
+ ]
+ })
+ ..registerType(SaladComponent, {
+ 'factory': () => new SaladComponent(),
+ 'parameters': const [],
+ 'annotations': const [const Component(bind: const {'menu': 'menu'})]
+ });
+}
diff --git a/modules/angular2/test/transform/common.dart b/modules/angular2/test/transform/common/application.dart
similarity index 100%
rename from modules/angular2/test/transform/common.dart
rename to modules/angular2/test/transform/common/application.dart
diff --git a/modules/angular2/test/transform/common/read_file.dart b/modules/angular2/test/transform/common/read_file.dart
new file mode 100644
index 0000000000..dc81d937c6
--- /dev/null
+++ b/modules/angular2/test/transform/common/read_file.dart
@@ -0,0 +1,32 @@
+library angular2.test.transform.common.read_file;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:angular2/src/transform/common/asset_reader.dart';
+import 'package:barback/barback.dart';
+
+/// Smooths over differences in CWD between IDEs and running tests in Travis.
+String readFile(String path) {
+ for (var myPath in [path, 'test/transform/${path}']) {
+ var file = new File(myPath);
+ if (file.existsSync()) {
+ return file.readAsStringSync();
+ }
+ }
+ return null;
+}
+
+class TestAssetReader implements AssetReader {
+ Future readAsString(AssetId id, {Encoding encoding}) =>
+ new Future.value(readFile(id.path));
+
+ Future hasInput(AssetId id) {
+ var exists = false;
+ for (var myPath in [id.path, 'test/transform/${id.path}']) {
+ var file = new File(myPath);
+ exists = exists || file.existsSync();
+ }
+ return new Future.value(exists);
+ }
+}
diff --git a/modules/angular2/test/transform/reflection_capabilities.dart b/modules/angular2/test/transform/common/reflection_capabilities.dart
similarity index 100%
rename from modules/angular2/test/transform/reflection_capabilities.dart
rename to modules/angular2/test/transform/common/reflection_capabilities.dart
diff --git a/modules/angular2/test/transform/directive_processor/all_tests.dart b/modules/angular2/test/transform/directive_processor/all_tests.dart
new file mode 100644
index 0000000000..b7b90657f6
--- /dev/null
+++ b/modules/angular2/test/transform/directive_processor/all_tests.dart
@@ -0,0 +1,30 @@
+library angular2.test.transform.directive_processor.all_tests;
+
+import 'dart:io';
+import 'package:barback/barback.dart';
+import 'package:angular2/src/transform/directive_processor/rewriter.dart';
+import 'package:angular2/src/transform/common/formatter.dart';
+import 'package:code_transformers/tests.dart';
+import 'package:dart_style/dart_style.dart';
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/vm_config.dart';
+
+import '../common/read_file.dart';
+
+var formatter = new DartFormatter();
+
+void allTests() {
+ test('should preserve parameter annotations as const instances.', () {
+ var inputPath = 'parameter_metadata/soup.dart';
+ var expected = _readFile('parameter_metadata/expected/soup.ng_deps.dart');
+ var output =
+ formatter.format(createNgDeps(_readFile(inputPath), inputPath));
+ expect(output, equals(expected));
+ });
+}
+
+var pathBase = 'directive_processor';
+
+/// Smooths over differences in CWD between IDEs and running tests in Travis.
+String _readFile(String path) => readFile('$pathBase/$path');
diff --git a/modules/angular2/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart b/modules/angular2/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart
new file mode 100644
index 0000000000..4558a20022
--- /dev/null
+++ b/modules/angular2/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart
@@ -0,0 +1,17 @@
+library dinner.soup;
+
+import 'soup.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(SoupComponent, {
+ 'factory':
+ (String description, salt) => new SoupComponent(description, salt),
+ 'parameters': const [const [Tasty, String], const [const Inject(Salt)]],
+ 'annotations': const [const Component(selector: '[soup]')]
+ });
+} // {"version":1,"importOffset":104,"registerOffset":451,"imports":["package:angular2/src/core/annotations/annotations.dart"]}
diff --git a/modules/angular2/test/transform/directive_processor/parameter_metadata/soup.dart b/modules/angular2/test/transform/directive_processor/parameter_metadata/soup.dart
new file mode 100644
index 0000000000..0a2524fc86
--- /dev/null
+++ b/modules/angular2/test/transform/directive_processor/parameter_metadata/soup.dart
@@ -0,0 +1,8 @@
+library dinner.soup;
+
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+@Component(selector: '[soup]')
+class SoupComponent {
+ SoupComponent(@Tasty String description, @Inject(Salt) salt);
+}
diff --git a/modules/angular2/test/transform/integration/all_tests.dart b/modules/angular2/test/transform/integration/all_tests.dart
new file mode 100644
index 0000000000..b3d0d3b45e
--- /dev/null
+++ b/modules/angular2/test/transform/integration/all_tests.dart
@@ -0,0 +1,134 @@
+library angular2.test.transform.integration;
+
+import 'dart:io';
+import 'package:angular2/transformer.dart';
+import 'package:code_transformers/tests.dart';
+import 'package:dart_style/dart_style.dart';
+import 'package:unittest/unittest.dart';
+
+import '../common/read_file.dart';
+
+var formatter = new DartFormatter();
+var transform = new AngularTransformerGroup(new TransformerOptions(
+ 'web/index.dart', reflectionEntryPoint: 'web/index.dart'));
+
+class IntegrationTestConfig {
+ final String name;
+ final Map assetPathToInputPath;
+ final Map assetPathToExpectedOutputPath;
+
+ IntegrationTestConfig(this.name,
+ {Map inputs, Map outputs})
+ : this.assetPathToInputPath = inputs,
+ this.assetPathToExpectedOutputPath = outputs;
+}
+
+void allTests() {
+ /*
+ * Each test has its own directory for inputs & an `expected` directory for
+ * expected outputs.
+ *
+ * In addition to these declared inputs, we inject a set of common inputs for
+ * every test.
+ */
+ var commonInputs = {
+ 'angular2|lib/src/core/annotations/annotations.dart':
+ '../../../lib/src/core/annotations/annotations.dart',
+ 'angular2|lib/src/core/application.dart': '../common/application.dart',
+ 'angular2|lib/src/reflection/reflection_capabilities.dart':
+ '../common/reflection_capabilities.dart'
+ };
+
+ var tests = [
+ new IntegrationTestConfig(
+ 'should generate proper code for a Component defining only a selector.',
+ inputs: {
+ 'a|web/index.dart': 'simple_annotation_files/index.dart',
+ 'a|web/bar.dart': 'simple_annotation_files/bar.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart':
+ 'simple_annotation_files/expected/bar.ng_deps.dart',
+ 'a|web/index.ng_deps.dart':
+ 'simple_annotation_files/expected/index.ng_deps.dart'
+ }),
+ new IntegrationTestConfig(
+ 'should generate proper code for a Component using a selector defined '
+ 'in another file.',
+ inputs: {
+ 'a|web/index.dart': 'two_deps_files/index.dart',
+ 'a|web/foo.dart': 'two_deps_files/foo.dart',
+ 'a|web/bar.dart': 'two_deps_files/bar.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart': 'two_deps_files/expected/bar.ng_deps.dart'
+ }),
+ new IntegrationTestConfig(
+ 'should generate proper code for a Component declaring a '
+ 'componentService defined in another file.',
+ inputs: {
+ 'a|web/index.dart': 'list_of_types_files/index.dart',
+ 'a|web/foo.dart': 'list_of_types_files/foo.dart',
+ 'a|web/bar.dart': 'list_of_types_files/bar.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart': 'list_of_types_files/expected/bar.ng_deps.dart'
+ }),
+ new IntegrationTestConfig(
+ 'should generate a factory for a class with no declared ctor.',
+ inputs: {
+ 'a|web/index.dart': 'synthetic_ctor_files/index.dart',
+ 'a|web/bar.dart': 'synthetic_ctor_files/bar.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart': 'synthetic_ctor_files/expected/bar.ng_deps.dart'
+ }),
+ new IntegrationTestConfig('should preserve multiple annotations.',
+ inputs: {
+ 'a|web/index.dart': 'two_annotations_files/index.dart',
+ 'a|web/bar.dart': 'two_annotations_files/bar.dart',
+ 'angular2|lib/src/core/annotations/template.dart':
+ '../../../lib/src/core/annotations/template.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart':
+ 'two_annotations_files/expected/bar.ng_deps.dart'
+ }),
+ new IntegrationTestConfig(
+ 'should ensure that dependencies are property chained.',
+ inputs: {
+ 'a|web/index.dart': 'chained_deps_files/index.dart',
+ 'a|web/foo.dart': 'chained_deps_files/foo.dart',
+ 'a|web/bar.dart': 'chained_deps_files/bar.dart'
+ },
+ outputs: {
+ 'a|web/bar.ng_deps.dart': 'chained_deps_files/expected/bar.ng_deps.dart',
+ 'a|web/foo.ng_deps.dart': 'chained_deps_files/expected/foo.ng_deps.dart'
+ })
+ ];
+
+ var cache = {};
+
+ for (var config in tests) {
+
+ // Read in input & output files.
+ config.assetPathToInputPath
+ ..addAll(commonInputs)
+ ..forEach((key, value) {
+ config.assetPathToInputPath[key] =
+ cache.putIfAbsent(value, () => _readFile(value));
+ });
+ config.assetPathToExpectedOutputPath.forEach((key, value) {
+ config.assetPathToExpectedOutputPath[key] = cache.putIfAbsent(value, () {
+ var code = _readFile(value);
+ return value.endsWith('dart') ? formatter.format(code) : code;
+ });
+ });
+ testPhases(config.name, [
+ [transform]
+ ], config.assetPathToInputPath, config.assetPathToExpectedOutputPath, []);
+ }
+}
+
+/// Smooths over differences in CWD between IDEs and running tests in Travis.
+String _readFile(String path) => readFile('integration/$path');
diff --git a/modules/angular2/test/transform/integration/chained_deps_files/bar.dart b/modules/angular2/test/transform/integration/chained_deps_files/bar.dart
new file mode 100644
index 0000000000..19f0b341c0
--- /dev/null
+++ b/modules/angular2/test/transform/integration/chained_deps_files/bar.dart
@@ -0,0 +1,9 @@
+library bar;
+
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'foo.dart' as dep;
+
+@Component(selector: '[soup]', services: const [dep.DependencyComponent])
+class MyComponent {
+ MyComponent();
+}
diff --git a/modules/angular2/test/transform/integration/chained_deps_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/chained_deps_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..baffcad961
--- /dev/null
+++ b/modules/angular2/test/transform/integration/chained_deps_files/expected/bar.ng_deps.dart
@@ -0,0 +1,22 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'foo.dart' as dep;
+import 'foo.ng_deps.dart' as i0;
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory': () => new MyComponent(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Component(
+ selector: '[soup]', services: const [dep.DependencyComponent])
+ ]
+ });
+ i0.setupReflection(reflector);
+}
diff --git a/modules/angular2/test/transform/integration/chained_deps_files/expected/foo.ng_deps.dart b/modules/angular2/test/transform/integration/chained_deps_files/expected/foo.ng_deps.dart
new file mode 100644
index 0000000000..db192c6a6f
--- /dev/null
+++ b/modules/angular2/test/transform/integration/chained_deps_files/expected/foo.ng_deps.dart
@@ -0,0 +1,16 @@
+library foo;
+
+import 'foo.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(DependencyComponent, {
+ 'factory': () => new DependencyComponent(),
+ 'parameters': const [],
+ 'annotations': const [const Component(selector: '[salad]')]
+ });
+}
diff --git a/modules/angular2/test/transform/integration/chained_deps_files/expected/index.ng_deps.dart b/modules/angular2/test/transform/integration/chained_deps_files/expected/index.ng_deps.dart
new file mode 100644
index 0000000000..b4c8d7c607
--- /dev/null
+++ b/modules/angular2/test/transform/integration/chained_deps_files/expected/index.ng_deps.dart
@@ -0,0 +1,13 @@
+library web_foo;
+
+import 'package:angular2/src/core/application.dart';
+import 'package:angular2/src/reflection/reflection_capabilities.dart';
+import 'bar.dart';
+import 'a:web/bar.ng_deps.dart' as i0;
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ i0.setupReflection(reflector);
+}
diff --git a/modules/angular2/test/transform/integration/chained_deps_files/foo.dart b/modules/angular2/test/transform/integration/chained_deps_files/foo.dart
new file mode 100644
index 0000000000..446f981fde
--- /dev/null
+++ b/modules/angular2/test/transform/integration/chained_deps_files/foo.dart
@@ -0,0 +1,8 @@
+library foo;
+
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+@Component(selector: '[salad]')
+class DependencyComponent {
+ DependencyComponent();
+}
diff --git a/modules/angular2/test/transform/basic_bind_files/index.dart b/modules/angular2/test/transform/integration/chained_deps_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/basic_bind_files/index.dart
rename to modules/angular2/test/transform/integration/chained_deps_files/index.dart
diff --git a/modules/angular2/test/transform/list_of_types_files/bar.dart b/modules/angular2/test/transform/integration/list_of_types_files/bar.dart
similarity index 100%
rename from modules/angular2/test/transform/list_of_types_files/bar.dart
rename to modules/angular2/test/transform/integration/list_of_types_files/bar.dart
diff --git a/modules/angular2/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..a8c1ca0721
--- /dev/null
+++ b/modules/angular2/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart
@@ -0,0 +1,19 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'foo.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory': (MyContext c) => new MyComponent(c),
+ 'parameters': const [const [MyContext]],
+ 'annotations': const [
+ const Component(componentServices: const [MyContext])
+ ]
+ });
+}
diff --git a/modules/angular2/test/transform/list_of_types_files/foo.dart b/modules/angular2/test/transform/integration/list_of_types_files/foo.dart
similarity index 100%
rename from modules/angular2/test/transform/list_of_types_files/foo.dart
rename to modules/angular2/test/transform/integration/list_of_types_files/foo.dart
diff --git a/modules/angular2/test/transform/list_of_types_files/index.dart b/modules/angular2/test/transform/integration/list_of_types_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/list_of_types_files/index.dart
rename to modules/angular2/test/transform/integration/list_of_types_files/index.dart
diff --git a/modules/angular2/test/transform/simple_annotation_files/bar.dart b/modules/angular2/test/transform/integration/simple_annotation_files/bar.dart
similarity index 100%
rename from modules/angular2/test/transform/simple_annotation_files/bar.dart
rename to modules/angular2/test/transform/integration/simple_annotation_files/bar.dart
diff --git a/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..f41b74e72f
--- /dev/null
+++ b/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart
@@ -0,0 +1,16 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory': () => new MyComponent(),
+ 'parameters': const [],
+ 'annotations': const [const Component(selector: '[soup]')]
+ });
+}
diff --git a/modules/angular2/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart b/modules/angular2/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart
new file mode 100644
index 0000000000..97710dd5c1
--- /dev/null
+++ b/modules/angular2/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart
@@ -0,0 +1,15 @@
+library web_foo;
+
+import 'index.dart';
+import 'package:angular2/src/core/application.dart';
+import 'package:angular2/src/reflection/reflection.dart';
+import 'package:angular2/src/reflection/reflection_capabilities.dart';
+import 'bar.dart';
+import 'bar.ng_deps.dart' as i0;
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ i0.setupReflection(reflector);
+}
diff --git a/modules/angular2/test/transform/simple_annotation_files/index.dart b/modules/angular2/test/transform/integration/simple_annotation_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/simple_annotation_files/index.dart
rename to modules/angular2/test/transform/integration/simple_annotation_files/index.dart
diff --git a/modules/angular2/test/transform/synthetic_ctor_files/bar.dart b/modules/angular2/test/transform/integration/synthetic_ctor_files/bar.dart
similarity index 100%
rename from modules/angular2/test/transform/synthetic_ctor_files/bar.dart
rename to modules/angular2/test/transform/integration/synthetic_ctor_files/bar.dart
diff --git a/modules/angular2/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..f41b74e72f
--- /dev/null
+++ b/modules/angular2/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart
@@ -0,0 +1,16 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory': () => new MyComponent(),
+ 'parameters': const [],
+ 'annotations': const [const Component(selector: '[soup]')]
+ });
+}
diff --git a/modules/angular2/test/transform/synthetic_ctor_files/index.dart b/modules/angular2/test/transform/integration/synthetic_ctor_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/synthetic_ctor_files/index.dart
rename to modules/angular2/test/transform/integration/synthetic_ctor_files/index.dart
diff --git a/modules/angular2/test/transform/two_annotations_files/bar.dart b/modules/angular2/test/transform/integration/two_annotations_files/bar.dart
similarity index 100%
rename from modules/angular2/test/transform/two_annotations_files/bar.dart
rename to modules/angular2/test/transform/integration/two_annotations_files/bar.dart
diff --git a/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..807b9db100
--- /dev/null
+++ b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart
@@ -0,0 +1,20 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'package:angular2/src/core/annotations/template.dart';
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory': () => new MyComponent(),
+ 'parameters': const [],
+ 'annotations': const [
+ const Component(selector: '[soup]'),
+ const Template(inline: 'Salad')
+ ]
+ });
+}
diff --git a/modules/angular2/test/transform/two_annotations_files/index.dart b/modules/angular2/test/transform/integration/two_annotations_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/two_annotations_files/index.dart
rename to modules/angular2/test/transform/integration/two_annotations_files/index.dart
diff --git a/modules/angular2/test/transform/two_deps_files/bar.dart b/modules/angular2/test/transform/integration/two_deps_files/bar.dart
similarity index 100%
rename from modules/angular2/test/transform/two_deps_files/bar.dart
rename to modules/angular2/test/transform/integration/two_deps_files/bar.dart
diff --git a/modules/angular2/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart
new file mode 100644
index 0000000000..8025b9ddd7
--- /dev/null
+++ b/modules/angular2/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart
@@ -0,0 +1,20 @@
+library bar;
+
+import 'bar.dart';
+import 'package:angular2/src/core/annotations/annotations.dart';
+import 'foo.dart' as prefix;
+
+bool _visited = false;
+void setupReflection(reflector) {
+ if (_visited) return;
+ _visited = true;
+ reflector
+ ..registerType(MyComponent, {
+ 'factory':
+ (prefix.MyContext c, String inValue) => new MyComponent(c, inValue),
+ 'parameters': const [const [prefix.MyContext], const [String]],
+ 'annotations': const [
+ const Component(selector: prefix.preDefinedSelector)
+ ]
+ });
+}
diff --git a/modules/angular2/test/transform/two_deps_files/foo.dart b/modules/angular2/test/transform/integration/two_deps_files/foo.dart
similarity index 100%
rename from modules/angular2/test/transform/two_deps_files/foo.dart
rename to modules/angular2/test/transform/integration/two_deps_files/foo.dart
diff --git a/modules/angular2/test/transform/two_deps_files/index.dart b/modules/angular2/test/transform/integration/two_deps_files/index.dart
similarity index 100%
rename from modules/angular2/test/transform/two_deps_files/index.dart
rename to modules/angular2/test/transform/integration/two_deps_files/index.dart
diff --git a/modules/angular2/test/transform/list_of_types_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/list_of_types_files/expected/index.bootstrap.dart
deleted file mode 100644
index 1051dff0e0..0000000000
--- a/modules/angular2/test/transform/list_of_types_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'foo.dart' as i1;
-import 'package:angular2/src/core/annotations/annotations.dart' as i2;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory": (i1.MyContext c) => new i0.MyComponent(c),
- "parameters": const [const [i1.MyContext]],
- "annotations": const [
- const i2.Component(componentServices: const [i1.MyContext])
- ]
- });
-}
diff --git a/modules/angular2/test/transform/reflection_remover/all_tests.dart b/modules/angular2/test/transform/reflection_remover/all_tests.dart
new file mode 100644
index 0000000000..e5b65c7ae0
--- /dev/null
+++ b/modules/angular2/test/transform/reflection_remover/all_tests.dart
@@ -0,0 +1,21 @@
+library angular2.test.transform.reflection_remover;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:angular2/src/transform/reflection_remover/codegen.dart';
+import 'package:angular2/src/transform/reflection_remover/rewriter.dart';
+import 'package:unittest/unittest.dart';
+
+import 'reflection_remover_files/expected/index.dart' as expected;
+import '../common/read_file.dart';
+
+void allTests() {
+ var codegen = new Codegen('web/index.dart', 'web/index.ng_deps.dart');
+
+ test('should remove uses of mirrors & insert calls to generated code.', () {
+ var code =
+ readFile('reflection_remover/reflection_remover_files/index.dart');
+ var output =
+ new Rewriter(code, codegen).rewrite(parseCompilationUnit(code));
+ expect(output, equals(expected.code));
+ });
+}
diff --git a/modules/angular2/test/transform/reflection_remover/reflection_remover_files/README.md b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/README.md
new file mode 100644
index 0000000000..616ff5aefe
--- /dev/null
+++ b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/README.md
@@ -0,0 +1,7 @@
+Tests that the reflection removal step:
+ 1. Comments out the import of reflection_capabilities.dart
+ 2. Comments out the instantiation of `ReflectionCapabilities`
+ 3. Adds the appropriate import.
+ 4. Adds the call to `setupReflection`
+ 5. Does not change line numbers in the source.
+ 6. Makes minimal changes to source offsets.
\ No newline at end of file
diff --git a/modules/angular2/test/transform/reflection_remover/reflection_remover_files/expected/index.dart b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/expected/index.dart
new file mode 100644
index 0000000000..eea63dadc9
--- /dev/null
+++ b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/expected/index.dart
@@ -0,0 +1,22 @@
+library angular2.test.transform.reflection_remover_files;
+
+// This file is intentionally formatted as a string to avoid having the
+// automatic transformer prettify it.
+//
+// This file represents transformed user code. Because this code will be
+// linked to output by a source map, we cannot change line numbers from the
+// original code and we therefore add our generated code on the same line as
+// those we are removing.
+
+var code = """
+library web_foo;
+
+import 'package:angular2/src/core/application.dart';
+import 'package:angular2/src/reflection/reflection.dart';
+import 'package:angular2/src/reflection/reflection_capabilities.dart';import 'index.ng_deps.dart' as ngStaticInit;
+
+void main() {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();ngStaticInit.setupReflection(reflector);
+ bootstrap(MyComponent);
+}
+""";
diff --git a/modules/angular2/test/transform/simple_annotation_files/expected/index.dart b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/index.dart
similarity index 75%
rename from modules/angular2/test/transform/simple_annotation_files/expected/index.dart
rename to modules/angular2/test/transform/reflection_remover/reflection_remover_files/index.dart
index cea925722d..45363b8a19 100644
--- a/modules/angular2/test/transform/simple_annotation_files/expected/index.dart
+++ b/modules/angular2/test/transform/reflection_remover/reflection_remover_files/index.dart
@@ -2,12 +2,9 @@ library web_foo;
import 'package:angular2/src/core/application.dart';
import 'package:angular2/src/reflection/reflection.dart';
-import 'index.bootstrap.dart' as ngStaticInit;
import 'package:angular2/src/reflection/reflection_capabilities.dart';
-import 'bar.dart';
void main() {
- ngStaticInit.setupReflection();
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrap(MyComponent);
}
diff --git a/modules/angular2/test/transform/simple_annotation_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/simple_annotation_files/expected/index.bootstrap.dart
deleted file mode 100644
index a4ddc3376a..0000000000
--- a/modules/angular2/test/transform/simple_annotation_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'package:angular2/src/core/annotations/annotations.dart' as i1;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory": () => new i0.MyComponent(),
- "parameters": const [const []],
- "annotations": const [const i1.Component(selector: '[soup]')]
- });
-}
diff --git a/modules/angular2/test/transform/synthetic_ctor_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/synthetic_ctor_files/expected/index.bootstrap.dart
deleted file mode 100644
index a4ddc3376a..0000000000
--- a/modules/angular2/test/transform/synthetic_ctor_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'package:angular2/src/core/annotations/annotations.dart' as i1;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory": () => new i0.MyComponent(),
- "parameters": const [const []],
- "annotations": const [const i1.Component(selector: '[soup]')]
- });
-}
diff --git a/modules/angular2/test/transform/transform.server.spec.dart b/modules/angular2/test/transform/transform.server.spec.dart
index ecb7f81afb..214f7f1a54 100644
--- a/modules/angular2/test/transform/transform.server.spec.dart
+++ b/modules/angular2/test/transform/transform.server.spec.dart
@@ -1,145 +1,17 @@
-library angular2.test;
+library angular2.test.transform;
-import 'dart:io';
-import 'package:barback/barback.dart';
-import 'package:angular2/transformer.dart';
-import 'package:code_transformers/tests.dart';
-import 'package:dart_style/dart_style.dart';
import 'package:unittest/unittest.dart';
import 'package:unittest/vm_config.dart';
+import 'bind_generator/all_tests.dart' as bindGenerator;
+import 'directive_processor/all_tests.dart' as directiveProcessor;
+import 'integration/all_tests.dart' as integration;
+import 'reflection_remover/all_tests.dart' as reflectionRemover;
+
main() {
useVMConfiguration();
-
- // TODO(kegluneq): Add a test for generating multiple annotations.
-
- group('Annotation tests:', _runTests);
-}
-
-var formatter = new DartFormatter();
-var transform = new AngularTransformer(new TransformerOptions('web/index.dart',
- reflectionEntryPoint: 'web/index.dart',
- newEntryPoint: 'web/index.bootstrap.dart'));
-
-class TestConfig {
- final String name;
- final Map assetPathToInputPath;
- final Map assetPathToExpectedOutputPath;
-
- TestConfig(this.name,
- {Map inputs, Map outputs})
- : this.assetPathToInputPath = inputs,
- this.assetPathToExpectedOutputPath = outputs;
-}
-
-void _runTests() {
- /*
- * Each test has its own directory for inputs & an `expected` directory for
- * expected outputs.
- *
- * In addition to these declared inputs, we inject a set of common inputs for
- * every test.
- */
- var commonInputs = {
- 'angular2|lib/src/core/annotations/annotations.dart':
- '../../lib/src/core/annotations/annotations.dart',
- 'angular2|lib/src/core/application.dart': 'common.dart',
- 'angular2|lib/src/reflection/reflection_capabilities.dart':
- 'reflection_capabilities.dart'
- };
-
- var tests = [
- new TestConfig('Simple',
- inputs: {
- 'a|web/index.dart': 'simple_annotation_files/index.dart',
- 'a|web/bar.dart': 'simple_annotation_files/bar.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'simple_annotation_files/expected/index.bootstrap.dart',
- 'a|web/index.dart': 'simple_annotation_files/expected/index.dart',
- }),
- new TestConfig('Two injected dependencies',
- inputs: {
- 'a|web/index.dart': 'two_deps_files/index.dart',
- 'a|web/foo.dart': 'two_deps_files/foo.dart',
- 'a|web/bar.dart': 'two_deps_files/bar.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'two_deps_files/expected/index.bootstrap.dart'
- }),
- new TestConfig('List of types',
- inputs: {
- 'a|web/index.dart': 'list_of_types_files/index.dart',
- 'a|web/foo.dart': 'list_of_types_files/foo.dart',
- 'a|web/bar.dart': 'list_of_types_files/bar.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'list_of_types_files/expected/index.bootstrap.dart'
- }),
- new TestConfig('Component with synthetic Constructor',
- inputs: {
- 'a|web/index.dart': 'synthetic_ctor_files/index.dart',
- 'a|web/bar.dart': 'synthetic_ctor_files/bar.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'synthetic_ctor_files/expected/index.bootstrap.dart'
- }),
- new TestConfig('Component with two annotations',
- inputs: {
- 'a|web/index.dart': 'two_annotations_files/index.dart',
- 'a|web/bar.dart': 'two_annotations_files/bar.dart',
- 'angular2|lib/src/core/annotations/template.dart':
- '../../lib/src/core/annotations/template.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'two_annotations_files/expected/index.bootstrap.dart'
- }),
- new TestConfig('Basic `bind`',
- inputs: {
- 'a|web/index.dart': 'basic_bind_files/index.dart',
- 'a|web/bar.dart': 'basic_bind_files/bar.dart'
- },
- outputs: {
- 'a|web/index.bootstrap.dart':
- 'basic_bind_files/expected/index.bootstrap.dart'
- })
- ];
-
- var cache = {};
-
- for (var config in tests) {
-
- // Read in input & output files.
- config.assetPathToInputPath
- ..addAll(commonInputs)
- ..forEach((key, value) {
- config.assetPathToInputPath[
- key] = cache.putIfAbsent(value, () => _readFile(value));
- });
- config.assetPathToExpectedOutputPath.forEach((key, value) {
- config.assetPathToExpectedOutputPath[key] = cache.putIfAbsent(value, () {
- var code = _readFile(value);
- return value.endsWith('dart') ? formatter.format(code) : code;
- });
- });
- testPhases(config.name, [
- [transform]
- ], config.assetPathToInputPath, config.assetPathToExpectedOutputPath, []);
- }
-}
-
-/// Smoothes over differences in CWD between IDEs and running tests in Travis.
-String _readFile(String path) {
- for (var myPath in [path, 'test/transform/${path}']) {
- var file = new File(myPath);
- if (file.existsSync()) {
- return file.readAsStringSync();
- }
- }
- return null;
+ group('Bind Generator', bindGenerator.allTests);
+ group('Directive Processor', directiveProcessor.allTests);
+ group('Reflection Remover', reflectionRemover.allTests);
+ group('Transformer Pipeline', integration.allTests);
}
diff --git a/modules/angular2/test/transform/two_annotations_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/two_annotations_files/expected/index.bootstrap.dart
deleted file mode 100644
index d5d665966d..0000000000
--- a/modules/angular2/test/transform/two_annotations_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'package:angular2/src/core/annotations/annotations.dart' as i1;
-import 'package:angular2/src/core/annotations/template.dart' as i2;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory": () => new i0.MyComponent(),
- "parameters": const [const []],
- "annotations": const [
- const i1.Component(selector: '[soup]'),
- const i2.Template(inline: 'Salad')
- ]
- });
-}
diff --git a/modules/angular2/test/transform/two_deps_files/expected/index.bootstrap.dart b/modules/angular2/test/transform/two_deps_files/expected/index.bootstrap.dart
deleted file mode 100644
index 046a923fff..0000000000
--- a/modules/angular2/test/transform/two_deps_files/expected/index.bootstrap.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-library angular2.src.transform.generated;
-
-import 'package:angular2/src/reflection/reflection.dart' show reflector;
-import 'bar.dart' as i0;
-import 'foo.dart' as i1;
-import 'package:angular2/src/core/annotations/annotations.dart' as i2;
-
-setupReflection() {
- reflector
- ..registerType(i0.MyComponent, {
- "factory":
- (i1.MyContext c, String inValue) => new i0.MyComponent(c, inValue),
- "parameters": const [const [i1.MyContext, String]],
- "annotations": const [const i2.Component(selector: i1.preDefinedSelector)]
- });
-}
diff --git a/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6 b/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6
index a15a431e06..7411cee33b 100644
--- a/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6
+++ b/modules/benchmarks/e2e_test/naive_infinite_scroll_spec.es6
@@ -9,11 +9,11 @@ describe('ng2 naive infinite scroll benchmark', function () {
it('should not throw errors', function() {
browser.get(URL);
var expectedRowCount = 18;
- var expectedCellsPerRow = 11;
- var allScrollItems = 'scroll-app /deep/ #testArea /deep/ scroll-item';
- var cells = `${ allScrollItems } /deep/ .row *`;
+ var expectedCellsPerRow = 28;
+ var allScrollItems = 'scroll-app #testArea scroll-item';
+ var cells = `${ allScrollItems } .row *`;
var stageButtons =
- `${ allScrollItems } /deep/ .row stage-buttons /deep/ button`;
+ `${ allScrollItems } .row stage-buttons button`;
var count = function(selector) {
return browser.executeScript(
diff --git a/modules/benchmarks/src/change_detection/change_detection_benchmark.js b/modules/benchmarks/src/change_detection/change_detection_benchmark.js
index ff1830425f..1b2baabe93 100644
--- a/modules/benchmarks/src/change_detection/change_detection_benchmark.js
+++ b/modules/benchmarks/src/change_detection/change_detection_benchmark.js
@@ -10,7 +10,8 @@ import {
ChangeDispatcher,
ChangeDetection,
dynamicChangeDetection,
- jitChangeDetection
+ jitChangeDetection,
+ BindingRecord
} from 'angular2/change_detection';
@@ -104,32 +105,29 @@ function setUpChangeDetection(changeDetection:ChangeDetection, iterations) {
var parser = new Parser(new Lexer());
var parentProto = changeDetection.createProtoChangeDetector('parent');
- var parentCd = parentProto.instantiate(dispatcher);
+ var parentCd = parentProto.instantiate(dispatcher, [], []);
var proto = changeDetection.createProtoChangeDetector("proto");
- var astWithSource = [
- parser.parseBinding('field0', null),
- parser.parseBinding('field1', null),
- parser.parseBinding('field2', null),
- parser.parseBinding('field3', null),
- parser.parseBinding('field4', null),
- parser.parseBinding('field5', null),
- parser.parseBinding('field6', null),
- parser.parseBinding('field7', null),
- parser.parseBinding('field8', null),
- parser.parseBinding('field9', null)
+ var bindingRecords = [
+ new BindingRecord(parser.parseBinding('field0', null), "memo", 0),
+ new BindingRecord(parser.parseBinding('field1', null), "memo", 1),
+ new BindingRecord(parser.parseBinding('field2', null), "memo", 2),
+ new BindingRecord(parser.parseBinding('field3', null), "memo", 3),
+ new BindingRecord(parser.parseBinding('field4', null), "memo", 4),
+ new BindingRecord(parser.parseBinding('field5', null), "memo", 5),
+ new BindingRecord(parser.parseBinding('field6', null), "memo", 6),
+ new BindingRecord(parser.parseBinding('field7', null), "memo", 7),
+ new BindingRecord(parser.parseBinding('field8', null), "memo", 8),
+ new BindingRecord(parser.parseBinding('field9', null), "memo", 9)
];
- for (var j = 0; j < 10; ++j) {
- proto.addAst(astWithSource[j].ast, "memo", j);
- }
for (var i = 0; i < iterations; ++i) {
var obj = new Obj();
for (var j = 0; j < 10; ++j) {
obj.setField(j, i);
}
- var cd = proto.instantiate(dispatcher);
- cd.hydrate(obj);
+ var cd = proto.instantiate(dispatcher, bindingRecords, []);
+ cd.hydrate(obj, null);
parentCd.addChild(cd);
}
return parentCd;
diff --git a/modules/benchmarks/src/element_injector/element_injector_benchmark.js b/modules/benchmarks/src/element_injector/element_injector_benchmark.js
index 8366ee7cc0..6036ffa845 100644
--- a/modules/benchmarks/src/element_injector/element_injector_benchmark.js
+++ b/modules/benchmarks/src/element_injector/element_injector_benchmark.js
@@ -33,11 +33,11 @@ export function main() {
var bindings = [A, B, C];
var proto = new ProtoElementInjector(null, 0, bindings);
- var elementInjector = proto.instantiate(null,null, null);
+ var elementInjector = proto.instantiate(null, null);
function instantiate () {
for (var i = 0; i < iterations; ++i) {
- var ei = proto.instantiate(null, null, null);
+ var ei = proto.instantiate(null, null);
ei.instantiateDirectives(appInjector, null, null);
}
}
diff --git a/modules/benchmarks/src/naive_infinite_scroll/index.js b/modules/benchmarks/src/naive_infinite_scroll/index.js
index 9f99139900..e1b83a55b7 100644
--- a/modules/benchmarks/src/naive_infinite_scroll/index.js
+++ b/modules/benchmarks/src/naive_infinite_scroll/index.js
@@ -6,12 +6,14 @@ import {Parser, Lexer, ChangeDetector, ChangeDetection}
from 'angular2/change_detection';
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
import {
- bootstrap, Component, Viewport, Template, ViewContainer, Compiler, onChange
+ bootstrap, Component, Viewport, Template, ViewContainer, Compiler, onChange, NgElement, Decorator
} from 'angular2/angular2';
import {reflector} from 'angular2/src/reflection/reflection';
import {CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
-import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
+import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@@ -256,6 +258,12 @@ export function setupReflectorForAngular() {
"annotations": []
});
+ reflector.registerType(EmulatedUnscopedShadowDomStrategy, {
+ "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
+ "parameters": [[StyleUrlResolver]],
+ "annotations": []
+ });
+
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
@@ -274,6 +282,12 @@ export function setupReflectorForAngular() {
"annotations": []
});
+ reflector.registerType(Content, {
+ "factory": (lightDom, el) => new Content(lightDom, el),
+ "parameters": [[DestinationLightDom], [NgElement]],
+ "annotations" : [new Decorator({selector: '[content]'})]
+ });
+
reflector.registerType(StyleInliner, {
"factory": (xhr, styleUrlResolver, urlResolver) =>
new StyleInliner(xhr, styleUrlResolver, urlResolver),
diff --git a/modules/benchmarks/src/tree/tree_benchmark.js b/modules/benchmarks/src/tree/tree_benchmark.js
index 3f7aaf0c48..b2fbefcfb9 100644
--- a/modules/benchmarks/src/tree/tree_benchmark.js
+++ b/modules/benchmarks/src/tree/tree_benchmark.js
@@ -2,13 +2,15 @@ import {Parser, Lexer, ChangeDetector, ChangeDetection, jitChangeDetection}
from 'angular2/change_detection';
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
-import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler} from 'angular2/angular2';
+import {bootstrap, Component, Viewport, Template, ViewContainer, Compiler, NgElement, Decorator} from 'angular2/angular2';
import {CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
-import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
+import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
@@ -127,12 +129,24 @@ function setupReflector() {
"annotations": []
});
+ reflector.registerType(EmulatedUnscopedShadowDomStrategy, {
+ "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
+ "parameters": [[StyleUrlResolver]],
+ "annotations": []
+ });
+
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
"annotations": []
});
+ reflector.registerType(Content, {
+ "factory": (lightDom, el) => new Content(lightDom, el),
+ "parameters": [[DestinationLightDom], [NgElement]],
+ "annotations" : [new Decorator({selector: '[content]'})]
+ });
+
reflector.registerType(UrlResolver, {
"factory": () => new UrlResolver(),
"parameters": [],
@@ -157,7 +171,6 @@ function setupReflector() {
"annotations": []
});
-
reflector.registerType(ComponentUrlMapper, {
"factory": () => new ComponentUrlMapper(),
"parameters": [],
diff --git a/modules/benchmarks_external/e2e_test/polymer_tree_perf.es6 b/modules/benchmarks_external/e2e_test/polymer_tree_perf.es6
new file mode 100644
index 0000000000..d471010d8e
--- /dev/null
+++ b/modules/benchmarks_external/e2e_test/polymer_tree_perf.es6
@@ -0,0 +1,20 @@
+var perfUtil = require('angular2/src/test_lib/perf_util');
+
+describe('polymer tree benchmark', function () {
+
+ var URL = 'benchmarks_external/src/tree/polymer/index.html';
+
+ afterEach(perfUtil.verifyNoBrowserErrors);
+
+ it('should log the stats', function(done) {
+ perfUtil.runClickBenchmark({
+ url: URL,
+ buttons: ['#destroyDom', '#createDom'],
+ id: 'polymer.tree',
+ params: [{
+ name: 'depth', value: 9, scale: 'log2'
+ }]
+ }).then(done, done.fail);
+ });
+
+});
diff --git a/modules/benchmarks_external/src/index.html b/modules/benchmarks_external/src/index.html
index 8ab0defcbe..c159c7bbf2 100644
--- a/modules/benchmarks_external/src/index.html
+++ b/modules/benchmarks_external/src/index.html
@@ -8,6 +8,9 @@
Tree benchmark
+
+ Polymer Tree benchmark
+
Largetable benchmark
diff --git a/modules/benchmarks_external/src/tree/polymer/binary_tree.html b/modules/benchmarks_external/src/tree/polymer/binary_tree.html
new file mode 100644
index 0000000000..d1fc193fc4
--- /dev/null
+++ b/modules/benchmarks_external/src/tree/polymer/binary_tree.html
@@ -0,0 +1,43 @@
+
+
+
+
+ {{data.value}}
+
+
+
+
+
+
+
diff --git a/modules/benchmarks_external/src/tree/polymer/index.html b/modules/benchmarks_external/src/tree/polymer/index.html
new file mode 100644
index 0000000000..2aba6179e0
--- /dev/null
+++ b/modules/benchmarks_external/src/tree/polymer/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+TODO
+
+ TODO: Does not use shadow DOM
+ TODO: Does not yet use builtin `if` construct as it uses a preview version of Polymer
+ Params
+
+
+Polymer JS 0.8-preview tree benchmark
+
+
+$SCRIPTS$
+
+
+
diff --git a/modules/benchmarks_external/src/tree/polymer/root_tree.html b/modules/benchmarks_external/src/tree/polymer/root_tree.html
new file mode 100644
index 0000000000..cb4c436528
--- /dev/null
+++ b/modules/benchmarks_external/src/tree/polymer/root_tree.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+ createDom
+ destroyDom
+
+
+
+
+
+
+
diff --git a/modules/benchpress/benchpress.es6 b/modules/benchpress/benchpress.es6
index 7b9e8b8681..7b1f0f23f2 100644
--- a/modules/benchpress/benchpress.es6
+++ b/modules/benchpress/benchpress.es6
@@ -1,2 +1,28 @@
+import { bind } from 'angular2/di';
+import { Options } from './common';
+
export * from './common';
export { SeleniumWebDriverAdapter } from './src/webdriver/selenium_webdriver_adapter';
+
+var fs = require('fs');
+
+// TODO(tbosch): right now we bind the `writeFile` method
+// in benchpres/benchpress.es6. This does not work for Dart,
+// find another way...
+// Note: Can't do the `require` call in a facade as it can't be loaded into the browser
+// for our unit tests via karma.
+Options.DEFAULT_BINDINGS.push(
+ bind(Options.WRITE_FILE).toValue(writeFile)
+);
+
+function writeFile(filename, content) {
+ return new Promise(function(resolve, reject) {
+ fs.writeFile(filename, content, (error) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve();
+ }
+ });
+ })
+}
diff --git a/modules/benchpress/common.js b/modules/benchpress/common.js
index c967724f8c..0da19f38f2 100644
--- a/modules/benchpress/common.js
+++ b/modules/benchpress/common.js
@@ -2,17 +2,18 @@ export { Sampler, SampleState } from './src/sampler';
export { Metric } from './src/metric';
export { Validator } from './src/validator';
export { Reporter } from './src/reporter';
-export { WebDriverExtension } from './src/web_driver_extension';
+export { WebDriverExtension, PerfLogFeatures } from './src/web_driver_extension';
export { WebDriverAdapter } from './src/web_driver_adapter';
export { SizeValidator } from './src/validator/size_validator';
export { RegressionSlopeValidator } from './src/validator/regression_slope_validator';
export { ConsoleReporter } from './src/reporter/console_reporter';
+export { JsonFileReporter } from './src/reporter/json_file_reporter';
export { SampleDescription } from './src/sample_description';
export { PerflogMetric } from './src/metric/perflog_metric';
export { ChromeDriverExtension } from './src/webdriver/chrome_driver_extension';
export { IOsDriverExtension } from './src/webdriver/ios_driver_extension';
export { Runner } from './src/runner';
-export { Options } from './src/sample_options';
+export { Options } from './src/common_options';
export { MeasureValues } from './src/measure_values';
export { MultiMetric } from './src/metric/multi_metric';
export { MultiReporter } from './src/reporter/multi_reporter';
diff --git a/modules/benchpress/pubspec.yaml b/modules/benchpress/pubspec.yaml
index b0702439ac..1709063a2b 100644
--- a/modules/benchpress/pubspec.yaml
+++ b/modules/benchpress/pubspec.yaml
@@ -16,4 +16,4 @@ dependency_overrides:
angular2:
path: ../angular2
dev_dependencies:
- guinness: '^0.1.16'
+ guinness: '^0.1.17'
diff --git a/modules/benchpress/src/sample_options.js b/modules/benchpress/src/common_options.js
similarity index 73%
rename from modules/benchpress/src/sample_options.js
rename to modules/benchpress/src/common_options.js
index b2c9801ae9..8af9df3825 100644
--- a/modules/benchpress/src/sample_options.js
+++ b/modules/benchpress/src/common_options.js
@@ -1,6 +1,8 @@
import { bind, OpaqueToken } from 'angular2/di';
+import { DateWrapper } from 'angular2/src/facade/lang';
export class Options {
+ static get DEFAULT_BINDINGS() { return _DEFAULT_BINDINGS; }
// TODO(tbosch): use static initializer when our transpiler supports it
static get SAMPLE_ID() { return _SAMPLE_ID; }
// TODO(tbosch): use static initializer when our transpiler supports it
@@ -23,6 +25,10 @@ export class Options {
* Used for micro benchmarks.
**/
static get MICRO_ITERATIONS() { return _MICRO_ITERATIONS; }
+ // TODO(tbosch): use static initializer when our transpiler supports it
+ static get NOW() { return _NOW; }
+ // TODO(tbosch): use static values when our transpiler supports them
+ static get WRITE_FILE() { return _WRITE_FILE; }
}
var _SAMPLE_ID = new OpaqueToken('Options.sampleId');
@@ -34,3 +40,13 @@ var _EXECUTE = new OpaqueToken('Options.execute');
var _CAPABILITIES = new OpaqueToken('Options.capabilities');
var _USER_AGENT = new OpaqueToken('Options.userAgent');
var _MICRO_ITERATIONS = new OpaqueToken('Options.microIterations');
+var _NOW = new OpaqueToken('Options.now');
+var _WRITE_FILE = new OpaqueToken('Options.writeFile');
+
+var _DEFAULT_BINDINGS = [
+ bind(_DEFAULT_DESCRIPTION).toValue({}),
+ bind(_SAMPLE_DESCRIPTION).toValue({}),
+ bind(_FORCE_GC).toValue(false),
+ bind(_PREPARE).toValue(false),
+ bind(_NOW).toValue( () => DateWrapper.now() )
+];
\ No newline at end of file
diff --git a/modules/benchpress/src/measure_values.js b/modules/benchpress/src/measure_values.js
index cafae766c2..89ed03c91a 100644
--- a/modules/benchpress/src/measure_values.js
+++ b/modules/benchpress/src/measure_values.js
@@ -1,4 +1,4 @@
-import { Date } from 'angular2/src/facade/lang';
+import { Date, DateWrapper } from 'angular2/src/facade/lang';
import { StringMap } from 'angular2/src/facade/collection';
export class MeasureValues {
@@ -11,4 +11,12 @@ export class MeasureValues {
this.runIndex = runIndex;
this.values = values;
}
+
+ toJson() {
+ return {
+ 'timeStamp': DateWrapper.toJson(this.timeStamp),
+ 'runIndex': this.runIndex,
+ 'values': this.values
+ };
+ }
}
diff --git a/modules/benchpress/src/metric/perflog_metric.js b/modules/benchpress/src/metric/perflog_metric.js
index 4345509455..867a675adb 100644
--- a/modules/benchpress/src/metric/perflog_metric.js
+++ b/modules/benchpress/src/metric/perflog_metric.js
@@ -3,9 +3,9 @@ import { isPresent, isBlank, int, BaseException, StringWrapper, Math } from 'ang
import { ListWrapper, StringMap, StringMapWrapper } from 'angular2/src/facade/collection';
import { bind, OpaqueToken } from 'angular2/di';
-import { WebDriverExtension } from '../web_driver_extension';
+import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
import { Metric } from '../metric';
-import { Options } from '../sample_options';
+import { Options } from '../common_options';
/**
* A metric that reads out the performance log
@@ -21,6 +21,7 @@ export class PerflogMetric extends Metric {
_measureCount:int;
_setTimeout:Function;
_microIterations:int;
+ _perfLogFeatures:PerfLogFeatures;
/**
* @param driverExtension
@@ -35,19 +36,24 @@ export class PerflogMetric extends Metric {
this._measureCount = 0;
this._setTimeout = setTimeout;
this._microIterations = microIterations;
+ this._perfLogFeatures = driverExtension.perfLogFeatures();
}
describe():StringMap {
var res = {
- 'script': 'script execution time in ms',
- 'render': 'render time in ms',
- 'gcTime': 'gc time in ms',
- 'gcAmount': 'gc amount in kbytes',
- 'gcTimeInScript': 'gc time during script execution in ms',
- 'gcAmountInScript': 'gc amount during script execution in kbytes'
+ 'scriptTime': 'script execution time in ms, including gc and render',
+ 'pureScriptTime': 'script execution time in ms, without gc nor render'
};
+ if (this._perfLogFeatures.render) {
+ res['renderTime'] = 'render time in and ouside of script in ms';
+ }
+ if (this._perfLogFeatures.gc) {
+ res['gcTime'] = 'gc time in and ouside of script in ms';
+ res['gcAmount'] = 'gc amount in kbytes';
+ res['majorGcTime'] = 'time of major gcs in ms';
+ }
if (this._microIterations > 0) {
- res['scriptMicroAvg'] = 'average script time for a micro iteration';
+ res['microScriptTimeAvg'] = 'average script time for a micro iteration';
}
return res;
}
@@ -120,16 +126,22 @@ export class PerflogMetric extends Metric {
_aggregateEvents(events, markName) {
var result = {
- 'script': 0,
- 'render': 0,
- 'gcTime': 0,
- 'gcAmount': 0,
- 'gcTimeInScript': 0,
- 'gcAmountInScript': 0
+ 'scriptTime': 0,
+ 'pureScriptTime': 0
};
+ if (this._perfLogFeatures.gc) {
+ result['gcTime'] = 0;
+ result['majorGcTime'] = 0;
+ result['gcAmount'] = 0;
+ }
+ if (this._perfLogFeatures.render) {
+ result['renderTime'] = 0;
+ }
var markStartEvent = null;
var markEndEvent = null;
+ var gcTimeInScript = 0;
+ var renderTimeInScript = 0;
var intervalStarts = {};
events.forEach( (event) => {
@@ -149,20 +161,29 @@ export class PerflogMetric extends Metric {
intervalStarts[name] = null;
if (StringWrapper.equals(name, 'gc')) {
result['gcTime'] += duration;
- result['gcAmount'] += (startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
- if (isPresent(intervalStarts['script'])) {
- result['gcTimeInScript'] += duration;
- result['gcAmountInScript'] += result['gcAmount'];
+ var amount = (startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
+ result['gcAmount'] += amount;
+ var majorGc = event['args']['majorGc'];
+ if (isPresent(majorGc) && majorGc) {
+ result['majorGcTime'] += duration;
}
- } else {
- result[name] += duration;
+ if (isPresent(intervalStarts['script'])) {
+ gcTimeInScript += duration;
+ }
+ } else if (StringWrapper.equals(name, 'render')) {
+ result['renderTime'] += duration;
+ if (isPresent(intervalStarts['script'])) {
+ renderTimeInScript += duration;
+ }
+ } else if (StringWrapper.equals(name, 'script')) {
+ result['scriptTime'] += duration;
}
}
}
});
- result['script'] -= result['gcTimeInScript'];
+ result['pureScriptTime'] = result['scriptTime'] - gcTimeInScript - renderTimeInScript;
if (this._microIterations > 0) {
- result['scriptMicroAvg'] = result['script'] / this._microIterations;
+ result['microScriptTimeAvg'] = result['scriptTime'] / this._microIterations;
}
return isPresent(markStartEvent) && isPresent(markEndEvent) ? result : null;
}
@@ -177,7 +198,8 @@ var _MARK_NAME_PREFIX = 'benchpress';
var _SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
var _BINDINGS = [
bind(PerflogMetric).toFactory(
- (driverExtension, setTimeout, microIterations) => new PerflogMetric(driverExtension, setTimeout, microIterations),
+ (driverExtension, setTimeout, microIterations) =>
+ new PerflogMetric(driverExtension, setTimeout, microIterations),
[WebDriverExtension, _SET_TIMEOUT, Options.MICRO_ITERATIONS]
),
bind(_SET_TIMEOUT).toValue( (fn, millis) => PromiseWrapper.setTimeout(fn, millis) ),
diff --git a/modules/benchpress/src/reporter/json_file_reporter.js b/modules/benchpress/src/reporter/json_file_reporter.js
new file mode 100644
index 0000000000..d1ccf50bb1
--- /dev/null
+++ b/modules/benchpress/src/reporter/json_file_reporter.js
@@ -0,0 +1,55 @@
+import { DateWrapper, isPresent, isBlank, Json } from 'angular2/src/facade/lang';
+import { List } from 'angular2/src/facade/collection';
+import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
+
+import { bind, OpaqueToken } from 'angular2/di';
+
+import { Reporter } from '../reporter';
+import { SampleDescription } from '../sample_description';
+import { MeasureValues } from '../measure_values';
+import { Options } from '../common_options';
+
+/**
+ * A reporter that writes results into a json file.
+ */
+export class JsonFileReporter extends Reporter {
+ // TODO(tbosch): use static values when our transpiler supports them
+ static get PATH() { return _PATH; }
+ static get BINDINGS() { return _BINDINGS; }
+
+ _writeFile:Function;
+ _path:string;
+ _description:SampleDescription;
+ _now:Function;
+
+ constructor(sampleDescription, path, writeFile, now) {
+ super();
+ this._description = sampleDescription;
+ this._path = path;
+ this._writeFile = writeFile;
+ this._now = now;
+ }
+
+ reportMeasureValues(measureValues:MeasureValues):Promise {
+ return PromiseWrapper.resolve(null);
+ }
+
+ reportSample(completeSample:List, validSample:List):Promise {
+ var content = Json.stringify({
+ 'description': this._description,
+ 'completeSample': completeSample,
+ 'validSample': validSample
+ });
+ var filePath = `${this._path}/${this._description.id}_${DateWrapper.toMillis(this._now())}.json`;
+ return this._writeFile(filePath, content);
+ }
+}
+
+var _PATH = new OpaqueToken('JsonFileReporter.path');
+var _BINDINGS = [
+ bind(JsonFileReporter).toFactory(
+ (sampleDescription, path, writeFile, now) => new JsonFileReporter(sampleDescription, path, writeFile, now),
+ [SampleDescription, _PATH, Options.WRITE_FILE, Options.NOW]
+ ),
+ bind(_PATH).toValue('.')
+];
diff --git a/modules/benchpress/src/runner.js b/modules/benchpress/src/runner.js
index 35a6c3d892..6425e2469d 100644
--- a/modules/benchpress/src/runner.js
+++ b/modules/benchpress/src/runner.js
@@ -18,7 +18,7 @@ import { SampleDescription } from './sample_description';
import { WebDriverAdapter } from './web_driver_adapter';
import { Reporter } from './reporter';
import { Metric } from './metric';
-import { Options } from './sample_options';
+import { Options } from './common_options';
/**
* The Runner is the main entry point for executing a sample run.
@@ -56,6 +56,7 @@ export class Runner {
}
var _DEFAULT_BINDINGS = [
+ Options.DEFAULT_BINDINGS,
Sampler.BINDINGS,
ConsoleReporter.BINDINGS,
RegressionSlopeValidator.BINDINGS,
diff --git a/modules/benchpress/src/sample_description.js b/modules/benchpress/src/sample_description.js
index 7054741f4e..56949d36ce 100644
--- a/modules/benchpress/src/sample_description.js
+++ b/modules/benchpress/src/sample_description.js
@@ -2,7 +2,7 @@ import { StringMapWrapper, ListWrapper, StringMap } from 'angular2/src/facade/co
import { bind, OpaqueToken } from 'angular2/di';
import { Validator } from './validator';
import { Metric } from './metric';
-import { Options } from './sample_options';
+import { Options } from './common_options';
/**
* SampleDescription merges all available descriptions about a sample
@@ -23,6 +23,14 @@ export class SampleDescription {
StringMapWrapper.forEach(description, (value, prop) => this.description[prop] = value );
});
}
+
+ toJson() {
+ return {
+ 'id': this.id,
+ 'description': this.description,
+ 'metrics': this.metrics
+ };
+ }
}
var _BINDINGS = [
@@ -39,7 +47,5 @@ var _BINDINGS = [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT,
Validator, Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
- ),
- bind(Options.DEFAULT_DESCRIPTION).toValue({}),
- bind(Options.SAMPLE_DESCRIPTION).toValue({})
+ )
];
diff --git a/modules/benchpress/src/sampler.js b/modules/benchpress/src/sampler.js
index d43fd304ae..5f7a0d27dc 100644
--- a/modules/benchpress/src/sampler.js
+++ b/modules/benchpress/src/sampler.js
@@ -9,7 +9,7 @@ import { Reporter } from './reporter';
import { WebDriverExtension } from './web_driver_extension';
import { WebDriverAdapter } from './web_driver_adapter';
-import { Options } from './sample_options';
+import { Options } from './common_options';
import { MeasureValues} from './measure_values';
/**
@@ -23,8 +23,6 @@ import { MeasureValues} from './measure_values';
export class Sampler {
// TODO(tbosch): use static values when our transpiler supports them
static get BINDINGS() { return _BINDINGS; }
- // TODO(tbosch): use static values when our transpiler supports them
- static get TIME() { return _TIME; }
_driver:WebDriverAdapter;
_driverExtension:WebDriverExtension;
@@ -34,14 +32,14 @@ export class Sampler {
_forceGc:boolean;
_prepare:Function;
_execute:Function;
- _time:Function;
+ _now:Function;
constructor({
- driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time
+ driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now
}:{
driver: WebDriverAdapter,
driverExtension: WebDriverExtension, metric: Metric, reporter: Reporter,
- validator: Validator, prepare: Function, execute: Function, time: Function
+ validator: Validator, prepare: Function, execute: Function, now: Function
}={}) {
this._driver = driver;
this._driverExtension = driverExtension;
@@ -51,7 +49,7 @@ export class Sampler {
this._forceGc = forceGc;
this._prepare = prepare;
this._execute = execute;
- this._time = time;
+ this._now = now;
}
sample():Promise {
@@ -96,7 +94,7 @@ export class Sampler {
}
_report(state:SampleState, metricValues:StringMap):Promise {
- var measureValues = new MeasureValues(state.completeSample.length, this._time(), metricValues);
+ var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
var completeSample = ListWrapper.concat(state.completeSample, [measureValues]);
var validSample = this._validator.validate(completeSample);
var resultPromise = this._reporter.reportMeasureValues(measureValues);
@@ -118,11 +116,9 @@ export class SampleState {
}
}
-var _TIME = new OpaqueToken('Sampler.time');
-
var _BINDINGS = [
bind(Sampler).toFactory(
- (driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, time) => new Sampler({
+ (driver, driverExtension, metric, reporter, validator, forceGc, prepare, execute, now) => new Sampler({
driver: driver,
driverExtension: driverExtension,
reporter: reporter,
@@ -134,14 +130,11 @@ var _BINDINGS = [
// special null object, which is expensive.
prepare: prepare !== false ? prepare : null,
execute: execute,
- time: time
+ now: now
}),
[
WebDriverAdapter, WebDriverExtension, Metric, Reporter, Validator,
- Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, _TIME
+ Options.FORCE_GC, Options.PREPARE, Options.EXECUTE, Options.NOW
]
- ),
- bind(Options.FORCE_GC).toValue(false),
- bind(Options.PREPARE).toValue(false),
- bind(_TIME).toValue( () => DateWrapper.now() )
+ )
];
diff --git a/modules/benchpress/src/validator/regression_slope_validator.js b/modules/benchpress/src/validator/regression_slope_validator.js
index 3143a896f5..6960b839d4 100644
--- a/modules/benchpress/src/validator/regression_slope_validator.js
+++ b/modules/benchpress/src/validator/regression_slope_validator.js
@@ -65,5 +65,5 @@ var _BINDINGS = [
[_SAMPLE_SIZE, _METRIC]
),
bind(_SAMPLE_SIZE).toValue(10),
- bind(_METRIC).toValue('script')
+ bind(_METRIC).toValue('scriptTime')
];
diff --git a/modules/benchpress/src/web_driver_extension.js b/modules/benchpress/src/web_driver_extension.js
index b2849c6dfc..9d70a3c2a1 100644
--- a/modules/benchpress/src/web_driver_extension.js
+++ b/modules/benchpress/src/web_driver_extension.js
@@ -1,10 +1,10 @@
import { bind, Injector, OpaqueToken } from 'angular2/di';
-import { BaseException, ABSTRACT, isBlank } from 'angular2/src/facade/lang';
+import { BaseException, ABSTRACT, isBlank, isPresent } from 'angular2/src/facade/lang';
import { Promise, PromiseWrapper } from 'angular2/src/facade/async';
import { List, ListWrapper, StringMap } from 'angular2/src/facade/collection';
-import { Options } from './sample_options';
+import { Options } from './common_options';
/**
* A WebDriverExtension implements extended commands of the webdriver protocol
@@ -64,9 +64,23 @@ export class WebDriverExtension {
throw new BaseException('NYI');
}
+ perfLogFeatures():PerfLogFeatures {
+ throw new BaseException('NYI');
+ }
+
supports(capabilities:StringMap):boolean {
return true;
}
}
+export class PerfLogFeatures {
+ render:boolean;
+ gc:boolean;
+
+ constructor({render, gc} = {}) {
+ this.render = isPresent(render) && render;
+ this.gc = isPresent(gc) && gc;
+ }
+}
+
var _CHILDREN = new OpaqueToken('WebDriverExtension.children');
diff --git a/modules/benchpress/src/webdriver/chrome_driver_extension.js b/modules/benchpress/src/webdriver/chrome_driver_extension.js
index b614035d20..19956f16d1 100644
--- a/modules/benchpress/src/webdriver/chrome_driver_extension.js
+++ b/modules/benchpress/src/webdriver/chrome_driver_extension.js
@@ -4,7 +4,7 @@ import {
Json, isPresent, isBlank, RegExpWrapper, StringWrapper, BaseException, NumberWrapper
} from 'angular2/src/facade/lang';
-import { WebDriverExtension } from '../web_driver_extension';
+import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
import { WebDriverAdapter } from '../web_driver_adapter';
import { Promise } from 'angular2/src/facade/async';
@@ -61,10 +61,13 @@ export class ChromeDriverExtension extends WebDriverExtension {
if (isBlank(normalizedEvents)) {
normalizedEvents = [];
}
+ var majorGCPids = {};
chromeEvents.forEach( (event) => {
var cat = event['cat'];
var name = event['name'];
var args = event['args'];
+ var pid = event['pid'];
+ var ph = event['ph'];
if (StringWrapper.equals(cat, 'disabled-by-default-devtools.timeline')) {
if (StringWrapper.equals(name, 'FunctionCall') &&
(isBlank(args) || isBlank(args['data']) || !StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
@@ -81,22 +84,40 @@ export class ChromeDriverExtension extends WebDriverExtension {
'name': 'render'
}));
} else if (StringWrapper.equals(name, 'GCEvent')) {
+ var normArgs = {
+ 'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] : args['usedHeapSizeBefore']
+ };
+ if (StringWrapper.equals(event['ph'], 'E')) {
+ normArgs['majorGc'] = isPresent(majorGCPids[pid]) && majorGCPids[pid];
+ }
+ majorGCPids[pid] = false;
ListWrapper.push(normalizedEvents, normalizeEvent(event, {
'name': 'gc',
- 'args': {
- 'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] : args['usedHeapSizeBefore']
- }
+ 'args': normArgs
}));
}
} else if (StringWrapper.equals(cat, 'blink.console')) {
ListWrapper.push(normalizedEvents, normalizeEvent(event, {
'name': name
}));
+ } else if (StringWrapper.equals(cat, 'v8')) {
+ if (StringWrapper.equals(name, 'majorGC')) {
+ if (StringWrapper.equals(ph, 'B')) {
+ majorGCPids[pid] = true;
+ }
+ }
}
});
return normalizedEvents;
}
+ perfLogFeatures():PerfLogFeatures {
+ return new PerfLogFeatures({
+ render: true,
+ gc: true
+ });
+ }
+
supports(capabilities:StringMap):boolean {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
}
diff --git a/modules/benchpress/src/webdriver/ios_driver_extension.js b/modules/benchpress/src/webdriver/ios_driver_extension.js
index fdd2f5fac2..80d92d23a7 100644
--- a/modules/benchpress/src/webdriver/ios_driver_extension.js
+++ b/modules/benchpress/src/webdriver/ios_driver_extension.js
@@ -1,10 +1,10 @@
import { bind } from 'angular2/di';
import { ListWrapper, StringMap } from 'angular2/src/facade/collection';
import {
- Json, isPresent, isBlank, RegExpWrapper, StringWrapper
+ Json, isPresent, isBlank, RegExpWrapper, StringWrapper, BaseException
} from 'angular2/src/facade/lang';
-import { WebDriverExtension } from '../web_driver_extension';
+import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
import { WebDriverAdapter } from '../web_driver_adapter';
import { Promise } from 'angular2/src/facade/async';
@@ -21,7 +21,7 @@ export class IOsDriverExtension extends WebDriverExtension {
}
gc() {
- return this._driver.executeScript('window.gc()');
+ throw new BaseException('Force GC is not supported on iOS');
}
timeBegin(name:string):Promise {
@@ -81,14 +81,8 @@ export class IOsDriverExtension extends WebDriverExtension {
StringWrapper.equals(type, 'CompositeLayers')) {
ListWrapper.push(events, createStartEvent('render', startTime));
endEvent = createEndEvent('render', endTime);
- } else if (StringWrapper.equals(type, 'GCEvent')) {
- ListWrapper.push(events, createStartEvent('gc', startTime, {
- 'usedHeapSize': 0
- }));
- endEvent = createEndEvent('gc', endTime, {
- 'usedHeapSize': -data['usedHeapSizeDelta']
- });
}
+ // Note: ios used to support GCEvent up until iOS 6 :-(
if (isPresent(record['children'])) {
this._convertPerfRecordsToEvents(record['children'], events);
}
@@ -99,6 +93,12 @@ export class IOsDriverExtension extends WebDriverExtension {
return events;
}
+ perfLogFeatures():PerfLogFeatures {
+ return new PerfLogFeatures({
+ render: true
+ });
+ }
+
supports(capabilities:StringMap):boolean {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'safari');
}
diff --git a/modules/benchpress/test/metric/multi_metric_spec.js b/modules/benchpress/test/metric/multi_metric_spec.js
index 79beb1de80..f6911de9d0 100644
--- a/modules/benchpress/test/metric/multi_metric_spec.js
+++ b/modules/benchpress/test/metric/multi_metric_spec.js
@@ -1,4 +1,15 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { List, ListWrapper, StringMap } from 'angular2/src/facade/collection';
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
@@ -15,28 +26,28 @@ export function main() {
describe('multi metric', () => {
- it('should merge descriptions', (done) => {
+ it('should merge descriptions', inject([AsyncTestCompleter], (async) => {
createMetric(['m1', 'm2']).then( (m) => {
expect(m.describe()).toEqual({
'm1': 'describe', 'm2': 'describe'
});
- done();
+ async.done();
});
- });
+ }));
- it('should merge all beginMeasure calls', (done) => {
+ it('should merge all beginMeasure calls', inject([AsyncTestCompleter], (async) => {
createMetric(['m1', 'm2'])
.then( (m) => m.beginMeasure() )
.then( (values) => {
expect(values).toEqual([
'm1_beginMeasure', 'm2_beginMeasure'
]);
- done();
+ async.done();
});
- });
+ }));
[false, true].forEach( (restartFlag) => {
- it(`should merge all endMeasure calls for restart=${restartFlag}`, (done) => {
+ it(`should merge all endMeasure calls for restart=${restartFlag}`, inject([AsyncTestCompleter], (async) => {
createMetric(['m1', 'm2'])
.then( (m) => m.endMeasure(restartFlag) )
.then( (values) => {
@@ -44,9 +55,9 @@ export function main() {
'm1': { 'restart': restartFlag },
'm2': { 'restart': restartFlag }
});
- done();
+ async.done();
});
- });
+ }));
});
});
diff --git a/modules/benchpress/test/metric/perflog_metric_spec.js b/modules/benchpress/test/metric/perflog_metric_spec.js
index 8bf61ad3d4..e3786ffb38 100644
--- a/modules/benchpress/test/metric/perflog_metric_spec.js
+++ b/modules/benchpress/test/metric/perflog_metric_spec.js
@@ -1,10 +1,25 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { List, ListWrapper } from 'angular2/src/facade/collection';
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
-import { isPresent } from 'angular2/src/facade/lang';
+import { isPresent, isBlank } from 'angular2/src/facade/lang';
-import { Metric, PerflogMetric, WebDriverExtension, bind, Injector, Options } from 'benchpress/common';
+import {
+ Metric, PerflogMetric, WebDriverExtension,
+ PerfLogFeatures,
+ bind, Injector, Options
+} from 'benchpress/common';
import { TraceEventFactory } from '../trace_event_factory';
@@ -12,15 +27,19 @@ export function main() {
var commandLog;
var eventFactory = new TraceEventFactory('timeline', 'pid0');
- function createMetric(perfLogs, microIterations = 0) {
+ function createMetric(perfLogs, microIterations = 0, perfLogFeatures = null) {
commandLog = [];
+ if (isBlank(perfLogFeatures)) {
+ perfLogFeatures = new PerfLogFeatures({render: true, gc: true});
+ }
var bindings = [
+ Options.DEFAULT_BINDINGS,
PerflogMetric.BINDINGS,
bind(PerflogMetric.SET_TIMEOUT).toValue( (fn, millis) => {
ListWrapper.push(commandLog, ['setTimeout', millis]);
fn();
}),
- bind(WebDriverExtension).toValue(new MockDriverExtension(perfLogs, commandLog)),
+ bind(WebDriverExtension).toValue(new MockDriverExtension(perfLogs, commandLog, perfLogFeatures)),
bind(Options.MICRO_ITERATIONS).toValue(microIterations)
];
return new Injector(bindings).get(PerflogMetric);
@@ -28,26 +47,47 @@ export function main() {
describe('perflog metric', () => {
- it('should describe itself', () => {
- expect(createMetric([[]]).describe()['script']).toBe('script execution time in ms');
+ it('should describe itself based on the perfLogFeatrues', () => {
+ expect(createMetric([[]], 0, new PerfLogFeatures()).describe()).toEqual({
+ 'scriptTime': 'script execution time in ms, including gc and render',
+ 'pureScriptTime': 'script execution time in ms, without gc nor render'
+ });
+
+ expect(createMetric([[]], 0, new PerfLogFeatures({
+ render: true,
+ gc: false
+ })).describe()).toEqual({
+ 'scriptTime': 'script execution time in ms, including gc and render',
+ 'pureScriptTime': 'script execution time in ms, without gc nor render',
+ 'renderTime': 'render time in and ouside of script in ms',
+ });
+
+ expect(createMetric([[]]).describe()).toEqual({
+ 'scriptTime': 'script execution time in ms, including gc and render',
+ 'pureScriptTime': 'script execution time in ms, without gc nor render',
+ 'renderTime': 'render time in and ouside of script in ms',
+ 'gcTime': 'gc time in and ouside of script in ms',
+ 'gcAmount': 'gc amount in kbytes',
+ 'majorGcTime': 'time of major gcs in ms'
+ });
});
describe('beginMeasure', () => {
- it('should mark the timeline', (done) => {
+ it('should mark the timeline', inject([AsyncTestCompleter], (async) => {
var metric = createMetric([[]]);
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
- done();
+ async.done();
});
- });
+ }));
});
describe('endMeasure', () => {
- it('should mark and aggregate events in between the marks', (done) => {
+ it('should mark and aggregate events in between the marks', inject([AsyncTestCompleter], (async) => {
var events = [
[
eventFactory.markStart('benchpress0', 0),
@@ -65,13 +105,13 @@ export function main() {
['timeEnd', 'benchpress0', null],
'readPerfLog'
]);
- expect(data['script']).toBe(2);
+ expect(data['scriptTime']).toBe(2);
- done();
+ async.done();
});
- });
+ }));
- it('should restart timing', (done) => {
+ it('should restart timing', inject([AsyncTestCompleter], (async) => {
var events = [
[
eventFactory.markStart('benchpress0', 0),
@@ -94,11 +134,11 @@ export function main() {
'readPerfLog'
]);
- done();
+ async.done();
});
- });
+ }));
- it('should loop and aggregate until the end mark is present', (done) => {
+ it('should loop and aggregate until the end mark is present', inject([AsyncTestCompleter], (async) => {
var events = [
[ eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1) ],
[ eventFactory.end('script', 2) ],
@@ -117,13 +157,13 @@ export function main() {
[ 'setTimeout', 100 ],
'readPerfLog'
]);
- expect(data['script']).toBe(3);
+ expect(data['scriptTime']).toBe(3);
- done();
+ async.done();
});
- });
+ }));
- it('should store events after the end mark for the next call', (done) => {
+ it('should store events after the end mark for the next call', inject([AsyncTestCompleter], (async) => {
var events = [
[ eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1), eventFactory.markStart('benchpress1', 1),
eventFactory.start('script', 1), eventFactory.end('script', 2) ],
@@ -133,7 +173,7 @@ export function main() {
metric.beginMeasure()
.then( (_) => metric.endMeasure(true) )
.then( (data) => {
- expect(data['script']).toBe(0);
+ expect(data['scriptTime']).toBe(0);
return metric.endMeasure(true)
})
.then( (data) => {
@@ -144,11 +184,11 @@ export function main() {
['timeEnd', 'benchpress1', 'benchpress2'],
'readPerfLog'
]);
- expect(data['script']).toBe(3);
+ expect(data['scriptTime']).toBe(3);
- done();
+ async.done();
});
- });
+ }));
});
@@ -163,47 +203,47 @@ export function main() {
}
- it('should report a single interval', (done) => {
+ it('should report a single interval', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 0),
eventFactory.end('script', 5)
]).then((data) => {
- expect(data['script']).toBe(5);
- done();
+ expect(data['scriptTime']).toBe(5);
+ async.done();
});
- });
+ }));
- it('should sum up multiple intervals', (done) => {
+ it('should sum up multiple intervals', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 0),
eventFactory.end('script', 5),
eventFactory.start('script', 10),
eventFactory.end('script', 17)
]).then((data) => {
- expect(data['script']).toBe(12);
- done();
+ expect(data['scriptTime']).toBe(12);
+ async.done();
});
- });
+ }));
- it('should ignore not started intervals', (done) => {
+ it('should ignore not started intervals', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.end('script', 10)
]).then((data) => {
- expect(data['script']).toBe(0);
- done();
+ expect(data['scriptTime']).toBe(0);
+ async.done();
});
- });
+ }));
- it('should ignore not ended intervals', (done) => {
+ it('should ignore not ended intervals', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 10)
]).then((data) => {
- expect(data['script']).toBe(0);
- done();
+ expect(data['scriptTime']).toBe(0);
+ async.done();
});
- });
+ }));
- it('should ignore events from different processed as the start mark', (done) => {
+ it('should ignore events from different processed as the start mark', inject([AsyncTestCompleter], (async) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric([[
eventFactory.markStart('benchpress0', 0),
@@ -216,109 +256,91 @@ export function main() {
metric.beginMeasure()
.then( (_) => metric.endMeasure(false) )
.then((data) => {
- expect(data['script']).toBe(5);
- done();
+ expect(data['scriptTime']).toBe(5);
+ async.done();
});
- });
+ }));
- ['script', 'gcTime', 'render'].forEach( (metricName) => {
- it(`should support ${metricName} metric`, (done) => {
- aggregate([
- eventFactory.start(metricName, 0),
- eventFactory.end(metricName, 5)
- ]).then((data) => {
- expect(data[metricName]).toBe(5);
- done();
- });
+ it('should support scriptTime metric', inject([AsyncTestCompleter], (async) => {
+ aggregate([
+ eventFactory.start('script', 0),
+ eventFactory.end('script', 5)
+ ]).then((data) => {
+ expect(data['scriptTime']).toBe(5);
+ async.done();
});
- });
+ }));
- it('should support gcAmount metric', (done) => {
+ it('should support renderTime metric', inject([AsyncTestCompleter], (async) => {
+ aggregate([
+ eventFactory.start('render', 0),
+ eventFactory.end('render', 5)
+ ]).then((data) => {
+ expect(data['renderTime']).toBe(5);
+ async.done();
+ });
+ }));
+
+ it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000})
]).then((data) => {
+ expect(data['gcTime']).toBe(5);
expect(data['gcAmount']).toBe(1.5);
- done();
+ expect(data['majorGcTime']).toBe(0);
+ async.done();
});
- });
+ }));
- it('should subtract gcTime in script from script time', (done) => {
+ it('should support majorGcTime metric', inject([AsyncTestCompleter], (async) => {
+ aggregate([
+ eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
+ eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
+ ]).then((data) => {
+ expect(data['gcTime']).toBe(5);
+ expect(data['majorGcTime']).toBe(5);
+ async.done();
+ });
+ }));
+
+ it('should support pureScriptTime = scriptTime-gcTime-renderTime', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 0),
eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
eventFactory.end('gc', 4, {'usedHeapSize': 0}),
- eventFactory.end('script', 5)
+ eventFactory.start('render', 4),
+ eventFactory.end('render', 5),
+ eventFactory.end('script', 6)
]).then((data) => {
- expect(data['script']).toBe(2);
- done();
+ expect(data['scriptTime']).toBe(6);
+ expect(data['pureScriptTime']).toBe(2);
+ async.done();
});
- });
+ }));
describe('microIterations', () => {
- it('should not report scriptMicroAvg if microIterations = 0', (done) => {
+ it('should not report microScriptTimeAvg if microIterations = 0', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 0),
eventFactory.end('script', 5)
], 0).then((data) => {
- expect(isPresent(data['scriptMicroAvg'])).toBe(false);
- done();
+ expect(isPresent(data['microScriptTimeAvg'])).toBe(false);
+ async.done();
});
- });
+ }));
- it('should report scriptMicroAvg', (done) => {
+ it('should report microScriptTimeAvg', inject([AsyncTestCompleter], (async) => {
aggregate([
eventFactory.start('script', 0),
eventFactory.end('script', 5)
], 4).then((data) => {
- expect(data['script']).toBe(5);
- expect(data['scriptMicroAvg']).toBe(5/4);
- done();
+ expect(data['scriptTime']).toBe(5);
+ expect(data['microScriptTimeAvg']).toBe(5/4);
+ async.done();
});
- });
-
- });
-
- describe('gcTimeInScript / gcAmountInScript', () => {
-
- it('should detect gc during script execution with begin/end events', (done) => {
- aggregate([
- eventFactory.start('script', 0),
- eventFactory.start('gc', 1, {'usedHeapSize': 10000}),
- eventFactory.end('gc', 4, {'usedHeapSize': 0}),
- eventFactory.end('script', 5)
- ]).then((data) => {
- expect(data['gcTimeInScript']).toBe(3);
- expect(data['gcAmountInScript']).toBe(10.0);
- done();
- });
- });
-
- it('should detect gc during script execution with complete events', (done) => {
- aggregate([
- eventFactory.complete('script', 0, 5),
- eventFactory.start('gc', 1, {'usedHeapSize': 10000}),
- eventFactory.end('gc', 4, {'usedHeapSize': 0})
- ]).then((data) => {
- expect(data['gcTimeInScript']).toBe(3);
- expect(data['gcAmountInScript']).toBe(10.0);
- done();
- });
- });
-
- it('should ignore gc outside of script execution', (done) => {
- aggregate([
- eventFactory.start('gc', 1, {'usedHeapSize': 10}),
- eventFactory.end('gc', 4, {'usedHeapSize': 0}),
- eventFactory.start('script', 0),
- eventFactory.end('script', 5)
- ]).then((data) => {
- expect(data['gcTimeInScript']).toEqual(0.0);
- expect(data['gcAmountInScript']).toEqual(0.0);
- done();
- });
- });
+ }));
});
@@ -330,10 +352,12 @@ export function main() {
class MockDriverExtension extends WebDriverExtension {
_perfLogs:List;
_commandLog:List;
- constructor(perfLogs, commandLog) {
+ _perfLogFeatures:PerfLogFeatures;
+ constructor(perfLogs, commandLog, perfLogFeatures) {
super();
this._perfLogs = perfLogs;
this._commandLog = commandLog;
+ this._perfLogFeatures = perfLogFeatures;
}
timeBegin(name):Promise {
@@ -346,6 +370,10 @@ class MockDriverExtension extends WebDriverExtension {
return PromiseWrapper.resolve(null);
}
+ perfLogFeatures():PerfLogFeatures {
+ return this._perfLogFeatures;
+ }
+
readPerfLog():Promise {
ListWrapper.push(this._commandLog, 'readPerfLog');
if (this._perfLogs.length > 0) {
diff --git a/modules/benchpress/test/reporter/json_file_reporter_spec.js b/modules/benchpress/test/reporter/json_file_reporter_spec.js
new file mode 100644
index 0000000000..16f4a44e01
--- /dev/null
+++ b/modules/benchpress/test/reporter/json_file_reporter_spec.js
@@ -0,0 +1,109 @@
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
+
+import { DateWrapper, Json, RegExpWrapper, isPresent } from 'angular2/src/facade/lang';
+import { PromiseWrapper } from 'angular2/src/facade/async';
+
+import {
+ bind, Injector,
+ SampleDescription,
+ MeasureValues,
+ Options
+} from 'benchpress/common';
+
+
+import { JsonFileReporter } from 'benchpress/src/reporter/json_file_reporter';
+
+export function main() {
+ describe('file reporter', () => {
+ var loggedFile;
+
+ function createReporter({sampleId, descriptions, metrics, path}) {
+ var bindings = [
+ JsonFileReporter.BINDINGS,
+ bind(SampleDescription).toValue(new SampleDescription(sampleId, descriptions, metrics)),
+ bind(JsonFileReporter.PATH).toValue(path),
+ bind(Options.NOW).toValue( () => DateWrapper.fromMillis(1234) ),
+ bind(Options.WRITE_FILE).toValue((filename, content) => {
+ loggedFile = {
+ 'filename': filename,
+ 'content': content
+ };
+ return PromiseWrapper.resolve(null);
+ })
+ ];
+ return new Injector(bindings).get(JsonFileReporter);
+ }
+
+ it('should write all data into a file', inject([AsyncTestCompleter], (async) => {
+ createReporter({
+ sampleId: 'someId',
+ descriptions: [{ 'a': 2 }],
+ path: 'somePath',
+ metrics: {
+ 'script': 'script time'
+ }
+ }).reportSample([
+ mv(0, 0, { 'a': 3, 'b': 6})
+ ], [mv(0, 0, {
+ 'a': 3, 'b': 6
+ }), mv(1, 1, {
+ 'a': 5, 'b': 9
+ })]);
+ var regExp = RegExpWrapper.create('somePath/someId_\\d+\\.json');
+ expect(isPresent(RegExpWrapper.firstMatch(regExp, loggedFile['filename']))).toBe(true);
+ var parsedContent = Json.parse(loggedFile['content']);
+ expect(parsedContent).toEqual({
+ "description": {
+ "id": "someId",
+ "description": {
+ "a": 2
+ },
+ "metrics": {"script": "script time"}
+ },
+ "completeSample": [{
+ "timeStamp": "1970-01-01T00:00:00.000Z",
+ "runIndex": 0,
+ "values": {
+ "a": 3,
+ "b": 6
+ }
+ }],
+ "validSample": [
+ {
+ "timeStamp": "1970-01-01T00:00:00.000Z",
+ "runIndex": 0,
+ "values": {
+ "a": 3,
+ "b": 6
+ }
+ },
+ {
+ "timeStamp": "1970-01-01T00:00:00.001Z",
+ "runIndex": 1,
+ "values": {
+ "a": 5,
+ "b": 9
+ }
+ }
+ ]
+ });
+ async.done();
+ }));
+
+ });
+}
+
+function mv(runIndex, time, values) {
+ return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
+}
diff --git a/modules/benchpress/test/reporter/multi_reporter_spec.js b/modules/benchpress/test/reporter/multi_reporter_spec.js
index 7c0b64d83e..06ab013205 100644
--- a/modules/benchpress/test/reporter/multi_reporter_spec.js
+++ b/modules/benchpress/test/reporter/multi_reporter_spec.js
@@ -1,4 +1,15 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { List, ListWrapper, StringMap } from 'angular2/src/facade/collection';
import { PromiseWrapper, Promise } from 'angular2/src/facade/async';
@@ -16,7 +27,7 @@ export function main() {
describe('multi reporter', () => {
- it('should reportMeasureValues to all', (done) => {
+ it('should reportMeasureValues to all', inject([AsyncTestCompleter], (async) => {
var mv = new MeasureValues(0, DateWrapper.now(), {});
createReporters(['m1', 'm2'])
.then( (r) => r.reportMeasureValues(mv) )
@@ -26,11 +37,11 @@ export function main() {
{'id': 'm1', 'values': mv},
{'id': 'm2', 'values': mv}
]);
- done();
+ async.done();
});
- });
+ }));
- it('should reportSample to call', (done) => {
+ it('should reportSample to call', inject([AsyncTestCompleter], (async) => {
var completeSample = [
new MeasureValues(0, DateWrapper.now(), {}),
new MeasureValues(1, DateWrapper.now(), {})
@@ -45,9 +56,9 @@ export function main() {
{'id': 'm1', 'completeSample': completeSample, 'validSample': validSample},
{'id': 'm2', 'completeSample': completeSample, 'validSample': validSample}
]);
- done();
+ async.done();
})
- });
+ }));
});
}
diff --git a/modules/benchpress/test/runner_spec.js b/modules/benchpress/test/runner_spec.js
index 39dd5e5adf..8a33dc9001 100644
--- a/modules/benchpress/test/runner_spec.js
+++ b/modules/benchpress/test/runner_spec.js
@@ -1,4 +1,15 @@
-import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import {
Runner, Sampler, SampleDescription,
Validator, bind, Injector, Metric,
@@ -31,16 +42,16 @@ export function main() {
return runner;
}
- it('should set SampleDescription.id', (done) => {
+ it('should set SampleDescription.id', inject([AsyncTestCompleter], (async) => {
createRunner().sample({id: 'someId'})
.then( (_) => injector.asyncGet(SampleDescription) )
.then( (desc) => {
expect(desc.id).toBe('someId');
- done();
+ async.done();
});
- });
+ }));
- it('should merge SampleDescription.description', (done) => {
+ it('should merge SampleDescription.description', inject([AsyncTestCompleter], (async) => {
createRunner([
bind(Options.DEFAULT_DESCRIPTION).toValue({'a': 1})
]).sample({id: 'someId', bindings: [
@@ -55,44 +66,44 @@ export function main() {
'b': 2,
'v': 11
});
- done();
+ async.done();
});
- });
+ }));
- it('should fill SampleDescription.metrics from the Metric', (done) => {
+ it('should fill SampleDescription.metrics from the Metric', inject([AsyncTestCompleter], (async) => {
createRunner().sample({id: 'someId'})
.then( (_) => injector.asyncGet(SampleDescription) )
.then( (desc) => {
expect(desc.metrics).toEqual({ 'm1': 'some metric' });
- done();
+ async.done();
});
- });
+ }));
- it('should bind Options.EXECUTE', (done) => {
+ it('should bind Options.EXECUTE', inject([AsyncTestCompleter], (async) => {
var execute = () => {};
createRunner().sample({id: 'someId', execute: execute}).then( (_) => {
expect(injector.get(Options.EXECUTE)).toEqual(execute);
- done();
+ async.done();
});
- });
+ }));
- it('should bind Options.PREPARE', (done) => {
+ it('should bind Options.PREPARE', inject([AsyncTestCompleter], (async) => {
var prepare = () => {};
createRunner().sample({id: 'someId', prepare: prepare}).then( (_) => {
expect(injector.get(Options.PREPARE)).toEqual(prepare);
- done();
+ async.done();
});
- });
+ }));
- it('should bind Options.MICRO_ITERATIONS', (done) => {
+ it('should bind Options.MICRO_ITERATIONS', inject([AsyncTestCompleter], (async) => {
createRunner().sample({id: 'someId', microIterations: 23}).then( (_) => {
expect(injector.get(Options.MICRO_ITERATIONS)).toEqual(23);
- done();
+ async.done();
});
- });
+ }));
- it('should overwrite bindings per sample call', (done) => {
+ it('should overwrite bindings per sample call', inject([AsyncTestCompleter], (async) => {
createRunner([
bind(Options.DEFAULT_DESCRIPTION).toValue({'a': 1}),
]).sample({id: 'someId', bindings: [
@@ -101,10 +112,10 @@ export function main() {
.then( (desc) => {
expect(injector.get(SampleDescription).description['a']).toBe(2);
- done();
+ async.done();
});
- });
+ }));
});
}
diff --git a/modules/benchpress/test/sampler_spec.js b/modules/benchpress/test/sampler_spec.js
index 9da9bacdbb..d6da57f7f9 100644
--- a/modules/benchpress/test/sampler_spec.js
+++ b/modules/benchpress/test/sampler_spec.js
@@ -1,4 +1,15 @@
-import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { isBlank, isPresent, BaseException, stringify, Date, DateWrapper } from 'angular2/src/facade/lang';
import { ListWrapper, List } from 'angular2/src/facade/collection';
@@ -39,15 +50,17 @@ export function main() {
if (isBlank(driverExtension)) {
driverExtension = new MockDriverExtension([]);
}
- var bindings = ListWrapper.concat(Sampler.BINDINGS, [
+ var bindings = [
+ Options.DEFAULT_BINDINGS,
+ Sampler.BINDINGS,
bind(Metric).toValue(metric),
bind(Reporter).toValue(reporter),
bind(WebDriverAdapter).toValue(driver),
bind(WebDriverExtension).toValue(driverExtension),
bind(Options.EXECUTE).toValue(execute),
bind(Validator).toValue(validator),
- bind(Sampler.TIME).toValue( () => DateWrapper.fromMillis(time++) )
- ]);
+ bind(Options.NOW).toValue( () => DateWrapper.fromMillis(time++) )
+ ];
if (isPresent(prepare)) {
ListWrapper.push(bindings, bind(Options.PREPARE).toValue(prepare));
}
@@ -58,7 +71,7 @@ export function main() {
sampler = new Injector(bindings).get(Sampler);
}
- it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor', (done) => {
+ it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor', inject([AsyncTestCompleter], (async) => {
var log = [];
var count = 0;
var driver = new MockDriverAdapter([], (callback) => {
@@ -79,12 +92,12 @@ export function main() {
sampler.sample().then( (_) => {
expect(count).toBe(4);
expect(log).toEqual([0,1,2,3]);
- done();
+ async.done();
});
- });
+ }));
- it('should call prepare, gc, beginMeasure, execute, gc, endMeasure for every iteration', (done) => {
+ it('should call prepare, gc, beginMeasure, execute, gc, endMeasure for every iteration', inject([AsyncTestCompleter], (async) => {
var workCount = 0;
var log = [];
createSampler({
@@ -115,11 +128,11 @@ export function main() {
['gc'],
['endMeasure', false, {'script': 1}],
]);
- done();
+ async.done();
});
- });
+ }));
- it('should call execute, gc, endMeasure for every iteration if there is no prepare callback', (done) => {
+ it('should call execute, gc, endMeasure for every iteration if there is no prepare callback', inject([AsyncTestCompleter], (async) => {
var log = [];
var workCount = 0;
createSampler({
@@ -143,11 +156,11 @@ export function main() {
['gc'],
['endMeasure', true, {'script': 1}],
]);
- done();
+ async.done();
});
- });
+ }));
- it('should not gc if the flag is not set', (done) => {
+ it('should not gc if the flag is not set', inject([AsyncTestCompleter], (async) => {
var log = [];
createSampler({
metric: createCountingMetric(),
@@ -158,11 +171,11 @@ export function main() {
});
sampler.sample().then( (_) => {
expect(log).toEqual([]);
- done();
+ async.done();
});
- });
+ }));
- it('should only collect metrics for execute and ignore metrics from prepare', (done) => {
+ it('should only collect metrics for execute and ignore metrics from prepare', inject([AsyncTestCompleter], (async) => {
var scriptTime = 0;
var iterationCount = 1;
createSampler({
@@ -184,11 +197,11 @@ export function main() {
expect(state.completeSample.length).toBe(2);
expect(state.completeSample[0]).toEqual(mv(0, 1000, {'script': 10}));
expect(state.completeSample[1]).toEqual(mv(1, 1001, {'script': 20}));
- done();
+ async.done();
});
- });
+ }));
- it('should call the validator for every execution and store the valid sample', (done) => {
+ it('should call the validator for every execution and store the valid sample', inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
@@ -213,11 +226,11 @@ export function main() {
['validate', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
);
- done();
+ async.done();
});
- });
+ }));
- it('should report the metric values', (done) => {
+ it('should report the metric values', inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
createSampler({
@@ -244,9 +257,9 @@ export function main() {
['reportSample', [mv(0, 1000, {'script': 0}), mv(1, 1001, {'script': 1})], validSample]
);
- done();
+ async.done();
});
- });
+ }));
});
}
@@ -366,4 +379,4 @@ class MockReporter extends Reporter {
ListWrapper.push(this._log, ['reportSample', completeSample, validSample]);
return PromiseWrapper.resolve(null);
}
-}
\ No newline at end of file
+}
diff --git a/modules/benchpress/test/web_driver_extension_spec.js b/modules/benchpress/test/web_driver_extension_spec.js
index 896d5b45dd..5c609d6cae 100644
--- a/modules/benchpress/test/web_driver_extension_spec.js
+++ b/modules/benchpress/test/web_driver_extension_spec.js
@@ -1,4 +1,15 @@
-import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { StringMap, ListWrapper } from 'angular2/src/facade/collection';
import { isPresent, StringWrapper } from 'angular2/src/facade/lang';
@@ -17,22 +28,22 @@ export function main() {
describe('WebDriverExtension.bindTo', () => {
- it('should bind the extension that matches the capabilities', (done) => {
+ it('should bind the extension that matches the capabilities', inject([AsyncTestCompleter], (async) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then( (m) => {
expect(m.id).toEqual('m2');
- done();
+ async.done();
});
- });
+ }));
- it('should throw if there is no match', (done) => {
+ it('should throw if there is no match', inject([AsyncTestCompleter], (async) => {
PromiseWrapper.catchError(
createExtension(['m1'], {'browser': 'm2'}),
(err) => {
expect(isPresent(err)).toBe(true);
- done();
+ async.done();
}
);
- });
+ }));
});
}
diff --git a/modules/benchpress/test/webdriver/chrome_driver_extension_spec.js b/modules/benchpress/test/webdriver/chrome_driver_extension_spec.js
index 52b1e00a04..cb8f665570 100644
--- a/modules/benchpress/test/webdriver/chrome_driver_extension_spec.js
+++ b/modules/benchpress/test/webdriver/chrome_driver_extension_spec.js
@@ -1,4 +1,15 @@
-import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { ListWrapper } from 'angular2/src/facade/collection';
import { PromiseWrapper } from 'angular2/src/facade/async';
@@ -17,6 +28,8 @@ export function main() {
var extension;
var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
+ var v8Events = new TraceEventFactory('v8', 'pid0');
+ var v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
var chromeTimelineEvents = new TraceEventFactory('disabled-by-default-devtools.timeline', 'pid0');
var normEvents = new TraceEventFactory('timeline', 'pid0');
@@ -32,125 +45,155 @@ export function main() {
return extension;
}
- it('should force gc via window.gc()', (done) => {
+ it('should force gc via window.gc()', inject([AsyncTestCompleter], (async) => {
createExtension().gc().then( (_) => {
expect(log).toEqual([['executeScript', 'window.gc()']]);
- done();
+ async.done();
});
- });
+ }));
- it('should mark the timeline via console.time()', (done) => {
+ it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
createExtension().timeBegin('someName').then( (_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
- done();
+ async.done();
});
- });
+ }));
- it('should mark the timeline via console.timeEnd()', (done) => {
+ it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
createExtension().timeEnd('someName').then( (_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
- done();
+ async.done();
});
- });
+ }));
- it('should mark the timeline via console.time() and console.timeEnd()', (done) => {
+ it('should mark the timeline via console.time() and console.timeEnd()', inject([AsyncTestCompleter], (async) => {
createExtension().timeEnd('name1', 'name2').then( (_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
- done();
+ async.done();
});
- });
+ }));
describe('readPerfLog', () => {
- it('should execute a dummy script before reading them', (done) => {
+ it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
createExtension([]).readPerfLog().then( (_) => {
expect(log).toEqual([ [ 'executeScript', '1+1' ], [ 'logs', 'performance' ] ]);
- done();
+ async.done();
});
- });
+ }));
- it('should normalize times to ms and forward ph and pid event properties', (done) => {
+ it('should normalize times to ms and forward ph and pid event properties', inject([AsyncTestCompleter], (async) => {
createExtension([
chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.complete('script', 1.1, 5.5, null),
]);
- done();
+ async.done();
});
- });
+ }));
- it('should normalize "tdur" to "dur"', (done) => {
+ it('should normalize "tdur" to "dur"', inject([AsyncTestCompleter], (async) => {
var event = chromeTimelineEvents.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.complete('script', 1.1, 5.5, null),
]);
- done();
+ async.done();
});
- });
+ }));
- it('should report FunctionCall events as "script"', (done) => {
+ it('should report FunctionCall events as "script"', inject([AsyncTestCompleter], (async) => {
createExtension([
chromeTimelineEvents.start('FunctionCall', 0)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.start('script', 0),
]);
- done();
+ async.done();
});
- });
+ }));
- it('should ignore FunctionCalls from webdriver', (done) => {
+ it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
createExtension([
chromeTimelineEvents.start('FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})
]).readPerfLog().then( (events) => {
expect(events).toEqual([]);
- done();
+ async.done();
});
- });
+ }));
- it('should report begin timestamps', (done) => {
+ it('should report begin timestamps', inject([AsyncTestCompleter], (async) => {
createExtension([
blinkEvents.create('S', 'someName', 1000)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.markStart('someName', 1.0)
]);
- done();
+ async.done();
});
- });
+ }));
- it('should report end timestamps', (done) => {
+ it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
createExtension([
blinkEvents.create('F', 'someName', 1000)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.markEnd('someName', 1.0)
]);
- done();
+ async.done();
});
- });
+ }));
- it('should report gc', (done) => {
+ it('should report gc', inject([AsyncTestCompleter], (async) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
- normEvents.end('gc', 2.0, {'usedHeapSize': 0}),
+ normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}),
]);
- done();
+ async.done();
});
- });
+ }));
+
+ it('should report major gc', inject([AsyncTestCompleter], (async) => {
+ createExtension([
+ chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
+ v8EventsOtherProcess.start('majorGC', 1100, null),
+ v8EventsOtherProcess.end('majorGC', 1200, null),
+ chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
+ ]).readPerfLog().then( (events) => {
+ expect(events).toEqual([
+ normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
+ normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}),
+ ]);
+ async.done();
+ });
+ }));
+
+ it('should ignore major gc from different processes', inject([AsyncTestCompleter], (async) => {
+ createExtension([
+ chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
+ v8Events.start('majorGC', 1100, null),
+ v8Events.end('majorGC', 1200, null),
+ chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
+ ]).readPerfLog().then( (events) => {
+ expect(events).toEqual([
+ normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
+ normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': true}),
+ ]);
+ async.done();
+ });
+ }));
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
- it(`should report ${recordType} as "render"`, (done) => {
+ it(`should report ${recordType} as "render"`, inject([AsyncTestCompleter], (async) => {
createExtension([
chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345)
@@ -159,21 +202,21 @@ export function main() {
normEvents.start('render', 1.234),
normEvents.end('render', 2.345),
]);
- done();
+ async.done();
});
- });
+ }));
});
- it('should throw an error on buffer overflow', (done) => {
+ it('should throw an error on buffer overflow', inject([AsyncTestCompleter], (async) => {
PromiseWrapper.catchError(createExtension([
chromeTimelineEvents.start('FunctionCall', 1234),
], 'Tracing.bufferUsage').readPerfLog(), (err) => {
expect( () => {
throw err;
}).toThrowError('The DevTools trace buffer filled during the test!');
- done();
+ async.done();
});
- });
+ }));
it('should match chrome browsers', () => {
expect(createExtension().supports({
diff --git a/modules/benchpress/test/webdriver/ios_driver_extension_spec.js b/modules/benchpress/test/webdriver/ios_driver_extension_spec.js
index c774e27379..0d43707a0e 100644
--- a/modules/benchpress/test/webdriver/ios_driver_extension_spec.js
+++ b/modules/benchpress/test/webdriver/ios_driver_extension_spec.js
@@ -1,4 +1,15 @@
-import {describe, ddescribe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
+import {
+ afterEach,
+ AsyncTestCompleter,
+ beforeEach,
+ ddescribe,
+ describe,
+ expect,
+ iit,
+ inject,
+ it,
+ xit,
+} from 'angular2/test_lib';
import { ListWrapper } from 'angular2/src/facade/collection';
import { PromiseWrapper } from 'angular2/src/facade/async';
@@ -30,47 +41,44 @@ export function main() {
return extension;
}
- it('should force gc via window.gc()', (done) => {
- createExtension().gc().then( (_) => {
- expect(log).toEqual([['executeScript', 'window.gc()']]);
- done();
- });
+ it('should throw on forcing gc', () => {
+ expect( () => createExtension().gc() ).toThrowError('Force GC is not supported on iOS');
});
- it('should mark the timeline via console.time()', (done) => {
+ it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
createExtension().timeBegin('someName').then( (_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
- done();
+ async.done();
});
- });
+ }));
- it('should mark the timeline via console.timeEnd()', (done) => {
+ it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
createExtension().timeEnd('someName').then( (_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
- done();
+ async.done();
});
- });
+ }));
- it('should mark the timeline via console.time() and console.timeEnd()', (done) => {
+ it('should mark the timeline via console.time() and console.timeEnd()', inject([AsyncTestCompleter], (async) => {
createExtension().timeEnd('name1', 'name2').then( (_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
- done();
+ async.done();
});
- });
+ }));
describe('readPerfLog', () => {
- it('should execute a dummy script before reading them', (done) => {
+ it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
createExtension([]).readPerfLog().then( (_) => {
expect(log).toEqual([ [ 'executeScript', '1+1' ], [ 'logs', 'performance' ] ]);
- done();
+ async.done();
});
- });
+ }));
- it('should report FunctionCall records as "script"', (done) => {
+ it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => {
createExtension([
durationRecord('FunctionCall', 1, 5)
]).readPerfLog().then( (events) => {
@@ -78,55 +86,43 @@ export function main() {
normEvents.start('script', 1),
normEvents.end('script', 5)
]);
- done();
+ async.done();
});
- });
+ }));
- it('should ignore FunctionCalls from webdriver', (done) => {
+ it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
createExtension([
internalScriptRecord(1, 5)
]).readPerfLog().then( (events) => {
expect(events).toEqual([]);
- done();
+ async.done();
});
- });
+ }));
- it('should report begin time', (done) => {
+ it('should report begin time', inject([AsyncTestCompleter], (async) => {
createExtension([
timeBeginRecord('someName', 12)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.markStart('someName', 12)
]);
- done();
+ async.done();
});
- });
+ }));
- it('should report end timestamps', (done) => {
+ it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
createExtension([
timeEndRecord('someName', 12)
]).readPerfLog().then( (events) => {
expect(events).toEqual([
normEvents.markEnd('someName', 12)
]);
- done();
+ async.done();
});
- });
-
- it('should report gc', (done) => {
- createExtension([
- gcRecord(1, 3, 21)
- ]).readPerfLog().then( (events) => {
- expect(events).toEqual([
- normEvents.start('gc', 1, {'usedHeapSize': 0}),
- normEvents.end('gc', 3, {'usedHeapSize': -21}),
- ]);
- done();
- });
- });
+ }));
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers'].forEach( (recordType) => {
- it(`should report ${recordType}`, (done) => {
+ it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
createExtension([
durationRecord(recordType, 0, 1)
]).readPerfLog().then( (events) => {
@@ -134,13 +130,13 @@ export function main() {
normEvents.start('render', 0),
normEvents.end('render', 1),
]);
- done();
+ async.done();
});
- });
+ }));
});
- it('should walk children', (done) => {
+ it('should walk children', inject([AsyncTestCompleter], (async) => {
createExtension([
durationRecord('FunctionCall', 1, 5, [
timeBeginRecord('someName', 2)
@@ -151,9 +147,9 @@ export function main() {
normEvents.markStart('someName', 2),
normEvents.end('script', 5)
]);
- done();
+ async.done();
});
- });
+ }));
it('should match safari browsers', () => {
expect(createExtension().supports({
@@ -213,17 +209,6 @@ function internalScriptRecord(startTime, endTime) {
};
}
-function gcRecord(startTime, endTime, gcAmount) {
- return {
- 'type': 'GCEvent',
- 'startTime': startTime,
- 'endTime': endTime,
- 'data': {
- 'usedHeapSizeDelta': gcAmount
- }
- };
-}
-
class MockDriverAdapter extends WebDriverAdapter {
_log:List;
_perfRecords:List;
diff --git a/modules/examples/e2e_test/hello_world/hello_world_spec.es6 b/modules/examples/e2e_test/hello_world/hello_world_spec.es6
index 1bdcf97e39..a5f8c8bbf3 100644
--- a/modules/examples/e2e_test/hello_world/hello_world_spec.es6
+++ b/modules/examples/e2e_test/hello_world/hello_world_spec.es6
@@ -40,9 +40,9 @@ describe('hello world', function () {
});
function getComponentText(selector, innerSelector) {
- return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.querySelector("'+innerSelector+'").textContent');
+ return browser.executeScript('return document.querySelector("'+selector+'").querySelector("'+innerSelector+'").textContent');
}
function clickComponentButton(selector, innerSelector) {
- return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.querySelector("'+innerSelector+'").click()');
+ return browser.executeScript('return document.querySelector("'+selector+'").querySelector("'+innerSelector+'").click()');
}
diff --git a/modules/examples/pubspec.yaml b/modules/examples/pubspec.yaml
index 5b9b95319f..c799570f0a 100644
--- a/modules/examples/pubspec.yaml
+++ b/modules/examples/pubspec.yaml
@@ -8,7 +8,7 @@ dependency_overrides:
angular2:
path: ../angular2
dev_dependencies:
- guinness: ">=0.1.16 <0.2.0"
+ guinness: ">=0.1.17 <0.2.0"
benchpress:
path: ../benchpress
transformers:
diff --git a/modules/examples/src/hello_world/index_common.js b/modules/examples/src/hello_world/index_common.js
index 3ed4672da7..32f0b5b01f 100644
--- a/modules/examples/src/hello_world/index_common.js
+++ b/modules/examples/src/hello_world/index_common.js
@@ -1,4 +1,5 @@
import {bootstrap, Component, Decorator, Template, NgElement} from 'angular2/angular2';
+import {Injectable} from 'angular2/di';
// Angular 2.0 supports 3 basic types of directives:
// - Component - the basic building blocks of Angular 2.0 apps. Backed by
@@ -15,7 +16,7 @@ import {bootstrap, Component, Decorator, Template, NgElement} from 'angular2/ang
selector: 'hello-app',
// These are services that would be created if a class in the component's
// template tries to inject them.
- componentServices: [GreetingService]
+ services: [GreetingService]
})
// The template for the component.
@Template({
@@ -52,7 +53,8 @@ class RedDec {
}
}
-// A service used by the HelloCmp component.
+// A service available to the Injector, used by the HelloCmp component.
+@Injectable()
class GreetingService {
greeting:string;
constructor() {
diff --git a/modules/examples/src/hello_world/index_static.js b/modules/examples/src/hello_world/index_static.js
index f2c2a22ab3..51fecd8f45 100644
--- a/modules/examples/src/hello_world/index_static.js
+++ b/modules/examples/src/hello_world/index_static.js
@@ -7,7 +7,9 @@ import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
-import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
+import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
+import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
@@ -27,7 +29,7 @@ function setup() {
"annotations" : [
new Component({
selector: 'hello-app',
- componentServices: [app.GreetingService]
+ services: [app.GreetingService]
}),
new Template({
directives: [app.RedDec],
@@ -125,6 +127,12 @@ function setup() {
"annotations": []
});
+ reflector.registerType(EmulatedUnscopedShadowDomStrategy, {
+ "factory": (styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
+ "parameters": [[StyleUrlResolver]],
+ "annotations": []
+ });
+
reflector.registerType(StyleUrlResolver, {
"factory": (urlResolver) => new StyleUrlResolver(urlResolver),
"parameters": [[UrlResolver]],
@@ -143,6 +151,12 @@ function setup() {
"annotations": []
});
+ reflector.registerType(Content, {
+ "factory": (lightDom, el, selector) => new Content(lightDom, el, selector),
+ "parameters": [[DestinationLightDom], [NgElement], [String]],
+ "annotations" : []
+ });
+
reflector.registerType(StyleInliner, {
"factory": (xhr, styleUrlResolver, urlResolver) =>
new StyleInliner(xhr, styleUrlResolver, urlResolver),
diff --git a/modules/examples/src/todo/css/base.css b/modules/examples/src/todo/css/base.css
new file mode 100644
index 0000000000..502f06cf18
--- /dev/null
+++ b/modules/examples/src/todo/css/base.css
@@ -0,0 +1,379 @@
+@charset "utf-8";
+
+button {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: none;
+ font-size: 100%;
+ vertical-align: baseline;
+ font-family: inherit;
+ font-weight: inherit;
+ color: inherit;
+ -webkit-appearance: none;
+ -ms-appearance: none;
+ appearance: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+}
+
+button,
+input[type="checkbox"] {
+ outline: none;
+}
+
+.hidden {
+ display: none;
+}
+
+.visible {
+ display: block !important;
+}
+
+#todoapp {
+ background: #fff;
+ margin: 130px 0 40px 0;
+ position: relative;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
+ 0 25px 50px 0 rgba(0, 0, 0, 0.1);
+}
+
+#todoapp input::-webkit-input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+}
+
+#todoapp input::-moz-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+}
+
+#todoapp input::input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+}
+
+#todoapp h1 {
+ position: absolute;
+ top: -155px;
+ width: 100%;
+ font-size: 100px;
+ font-weight: 100;
+ text-align: center;
+ color: rgba(175, 47, 47, 0.15);
+ -webkit-text-rendering: optimizeLegibility;
+ -moz-text-rendering: optimizeLegibility;
+ -ms-text-rendering: optimizeLegibility;
+ text-rendering: optimizeLegibility;
+}
+
+#new-todo,
+.edit {
+ position: relative;
+ margin: 0;
+ width: 100%;
+ font-size: 24px;
+ font-family: inherit;
+ font-weight: inherit;
+ line-height: 1.4em;
+ border: 0;
+ outline: none;
+ color: inherit;
+ padding: 6px;
+ border: 1px solid #999;
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+}
+
+#new-todo {
+ padding: 16px 16px 16px 60px;
+ border: none;
+ background: rgba(0, 0, 0, 0.003);
+ box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
+}
+
+#main {
+ position: relative;
+ z-index: 2;
+ border-top: 1px solid #e6e6e6;
+}
+
+label[for='toggle-all'] {
+ display: none;
+}
+
+#toggle-all {
+ position: absolute;
+ top: -55px;
+ left: -12px;
+ width: 60px;
+ height: 34px;
+ text-align: center;
+ border: none; /* Mobile Safari */
+}
+
+#toggle-all:before {
+ content: '❯';
+ font-size: 22px;
+ color: #e6e6e6;
+ padding: 10px 27px 10px 27px;
+}
+
+#toggle-all:checked:before {
+ color: #737373;
+}
+
+#todo-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+#todo-list li {
+ position: relative;
+ font-size: 24px;
+ border-bottom: 1px solid #ededed;
+}
+
+#todo-list li:last-child {
+ border-bottom: none;
+}
+
+#todo-list li.editing {
+ border-bottom: none;
+ padding: 0;
+}
+
+#todo-list li.editing .edit {
+ display: block;
+ width: 506px;
+ padding: 13px 17px 12px 17px;
+ margin: 0 0 0 43px;
+}
+
+#todo-list li.editing .view {
+ display: none;
+}
+
+#todo-list li .toggle {
+ text-align: center;
+ width: 40px;
+ /* auto, since non-WebKit browsers doesn't support input styling */
+ height: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ margin: auto 0;
+ border: none; /* Mobile Safari */
+ -webkit-appearance: none;
+ -ms-appearance: none;
+ appearance: none;
+}
+
+#todo-list li .toggle:after {
+ content: url('data:image/svg+xml;utf8, ');
+}
+
+#todo-list li .toggle:checked:after {
+ content: url('data:image/svg+xml;utf8, ');
+}
+
+#todo-list li label {
+ white-space: pre;
+ word-break: break-word;
+ padding: 15px 60px 15px 15px;
+ margin-left: 45px;
+ display: block;
+ line-height: 1.2;
+ transition: color 0.4s;
+}
+
+#todo-list li.completed label {
+ color: #d9d9d9;
+ text-decoration: line-through;
+}
+
+#todo-list li .destroy {
+ display: none;
+ position: absolute;
+ top: 0;
+ right: 10px;
+ bottom: 0;
+ width: 40px;
+ height: 40px;
+ margin: auto 0;
+ font-size: 30px;
+ color: #cc9a9a;
+ margin-bottom: 11px;
+ transition: color 0.2s ease-out;
+}
+
+#todo-list li .destroy:hover {
+ color: #af5b5e;
+}
+
+#todo-list li .destroy:after {
+ content: '×';
+}
+
+#todo-list li:hover .destroy {
+ display: block;
+}
+
+#todo-list li .edit {
+ display: none;
+}
+
+#todo-list li.editing:last-child {
+ margin-bottom: -1px;
+}
+
+#footer {
+ color: #777;
+ padding: 10px 15px;
+ height: 20px;
+ text-align: center;
+ border-top: 1px solid #e6e6e6;
+}
+
+#footer:before {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 50px;
+ overflow: hidden;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
+ 0 8px 0 -3px #f6f6f6,
+ 0 9px 1px -3px rgba(0, 0, 0, 0.2),
+ 0 16px 0 -6px #f6f6f6,
+ 0 17px 2px -6px rgba(0, 0, 0, 0.2);
+}
+
+#todo-count {
+ float: left;
+ text-align: left;
+}
+
+#todo-count strong {
+ font-weight: 300;
+}
+
+#filters {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ right: 0;
+ left: 0;
+}
+
+#filters li {
+ display: inline;
+}
+
+#filters li a {
+ color: inherit;
+ margin: 3px;
+ padding: 3px 7px;
+ text-decoration: none;
+ border: 1px solid transparent;
+ border-radius: 3px;
+}
+
+#filters li a.selected,
+#filters li a:hover {
+ border-color: rgba(175, 47, 47, 0.1);
+}
+
+#filters li a.selected {
+ border-color: rgba(175, 47, 47, 0.2);
+}
+
+#clear-completed,
+html #clear-completed:active {
+ float: right;
+ position: relative;
+ line-height: 20px;
+ text-decoration: none;
+ cursor: pointer;
+ visibility: hidden;
+ position: relative;
+}
+
+#clear-completed::after {
+ visibility: visible;
+ content: 'Clear completed';
+ position: absolute;
+ right: 0;
+ white-space: nowrap;
+}
+
+#clear-completed:hover::after {
+ text-decoration: underline;
+}
+
+#info {
+ margin: 65px auto 0;
+ color: #bfbfbf;
+ font-size: 10px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-align: center;
+}
+
+#info p {
+ line-height: 1;
+}
+
+#info a {
+ color: inherit;
+ text-decoration: none;
+ font-weight: 400;
+}
+
+#info a:hover {
+ text-decoration: underline;
+}
+
+/*
+Hack to remove background from Mobile Safari.
+Can't use it globally since it destroys checkboxes in Firefox
+*/
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ #toggle-all,
+ #todo-list li .toggle {
+ background: none;
+ }
+
+ #todo-list li .toggle {
+ height: 40px;
+ }
+
+ #toggle-all {
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+ -webkit-appearance: none;
+ appearance: none;
+ }
+}
+
+@media (max-width: 430px) {
+ #footer {
+ height: 50px;
+ }
+
+ #filters {
+ bottom: 10px;
+ }
+}
diff --git a/modules/examples/src/todo/css/bg.png b/modules/examples/src/todo/css/bg.png
new file mode 100644
index 0000000000..b2a7600825
Binary files /dev/null and b/modules/examples/src/todo/css/bg.png differ
diff --git a/modules/examples/src/todo/css/main.css b/modules/examples/src/todo/css/main.css
new file mode 100644
index 0000000000..6177782da2
--- /dev/null
+++ b/modules/examples/src/todo/css/main.css
@@ -0,0 +1,19 @@
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ line-height: 1.4em;
+ background: #eaeaea;
+ color: #4d4d4d;
+ width: 550px;
+ margin: 0 auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-font-smoothing: antialiased;
+ -ms-font-smoothing: antialiased;
+ -o-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+}
diff --git a/modules/examples/src/todo/index.html b/modules/examples/src/todo/index.html
new file mode 100644
index 0000000000..a7e935cb7b
--- /dev/null
+++ b/modules/examples/src/todo/index.html
@@ -0,0 +1,13 @@
+
+
+ Todo Angular 2
+
+
+
+ Loading...
+
+
+
+ $SCRIPTS$
+
+
diff --git a/modules/examples/src/todo/index.js b/modules/examples/src/todo/index.js
new file mode 100644
index 0000000000..c90e5e967d
--- /dev/null
+++ b/modules/examples/src/todo/index.js
@@ -0,0 +1,77 @@
+import {bootstrap, Component, Template, Foreach} from 'angular2/angular2';
+import {Store, Todo, TodoFactory} from './services/TodoStore';
+
+@Component({
+ selector: 'todo-app',
+ services: [
+ Store,
+ TodoFactory
+ ]
+})
+@Template({
+ url: 'todo.html',
+ directives: [Foreach]
+})
+class TodoApp {
+ todoStore: Store;
+ todoEdit: Todo;
+ factory: TodoFactory;
+
+ constructor(store: Store, factory: TodoFactory) {
+ this.todoStore = store;
+ this.todoEdit = null;
+ this.factory = factory;
+ }
+
+ enterTodo($event, inputElement) {
+ if($event.which === 13) { // ENTER_KEY
+ this.addTodo(inputElement.value);
+ inputElement.value = '';
+ }
+ }
+
+ editTodo(todo: Todo) {
+ this.todoEdit = todo;
+ }
+
+ doneEditing($event, todo: Todo) {
+ var which = $event.which;
+ var target = $event.target;
+ if(which === 13) {
+ todo.title = target.value;
+ this.todoStore.save(todo);
+ this.todoEdit = null;
+ } else if (which === 27) {
+ this.todoEdit = null;
+ target.value = todo.title;
+ }
+ }
+
+ addTodo(newTitle: string) {
+ this.todoStore.add(this.factory.create(newTitle, false));
+ }
+
+ completeMe(todo: Todo) {
+ todo.completed = !todo.completed;
+ }
+
+ deleteMe(todo: Todo) {
+ this.todoStore.remove(todo);
+ }
+
+ toggleAll($event) {
+ var isComplete = $event.target.checked;
+ this.todoStore.list.forEach((todo) => {
+ todo.completed = isComplete;
+ this.todoStore.save(todo);
+ });
+ }
+
+ clearCompleted() {
+ this.todoStore.removeBy((todo) => todo.completed);
+ }
+}
+
+export function main() {
+ bootstrap(TodoApp);
+}
diff --git a/modules/examples/src/todo/services/TodoStore.js b/modules/examples/src/todo/services/TodoStore.js
new file mode 100644
index 0000000000..751c7656dd
--- /dev/null
+++ b/modules/examples/src/todo/services/TodoStore.js
@@ -0,0 +1,72 @@
+import {ListWrapper} from 'angular2/src/facade/collection';
+
+// base model for RecordStore
+export class KeyModel {
+ _key: number;
+ constructor(key: number) {
+ this._key = key;
+ }
+}
+
+export class Todo extends KeyModel {
+ title: string;
+ completed: boolean;
+
+ constructor(key: number, theTitle: string, isCompleted: boolean) {
+ super(key);
+ this.title = theTitle;
+ this.completed = isCompleted;
+ }
+}
+
+export class TodoFactory {
+ _uid: number;
+
+ constructor() {
+ this._uid = 0;
+ }
+
+ nextUid() {
+ this._uid = this._uid + 1;
+ return this._uid;
+ }
+
+ create(title: string, isCompleted: boolean) {
+ return new Todo(this.nextUid(), title, isCompleted);
+ }
+}
+
+// Store manages any generic item that inherits from KeyModel
+export class Store {
+ list: List;
+
+ constructor() {
+ this.list = [];
+ }
+
+ add(record: KeyModel) {
+ this.list.push(record);
+ }
+
+ remove(record: KeyModel) {
+ this.spliceOut(record);
+ }
+
+ removeBy(callback: Function) {
+ var records = ListWrapper.filter(this.list, callback);
+ ListWrapper.removeAll(this.list, records);
+ }
+
+ spliceOut(record: KeyModel) {
+ var i = this.indexFor(record);
+ if( i > -1 ) {
+ return this.list.splice(i, 1)[0];
+ }
+ return null;
+ }
+
+ indexFor(record: KeyModel) {
+ return this.list.indexOf(record);
+ }
+
+}
diff --git a/modules/examples/src/todo/todo.html b/modules/examples/src/todo/todo.html
new file mode 100644
index 0000000000..51db5c016a
--- /dev/null
+++ b/modules/examples/src/todo/todo.html
@@ -0,0 +1,71 @@
+
+
+
+
+
diff --git a/modules/examples/test/benchpress/webdriver_async.server.spec.dart b/modules/examples/test/benchpress/webdriver_async.server.spec.dart
index 3a4150960f..d6bac085ee 100644
--- a/modules/examples/test/benchpress/webdriver_async.server.spec.dart
+++ b/modules/examples/test/benchpress/webdriver_async.server.spec.dart
@@ -46,7 +46,7 @@ Future createTestDriver() {
'binary': env['DARTIUM_BIN'],
'args': ['--js-flags=--expose-gc'],
'perfLoggingPrefs': {
- 'traceCategories': 'blink.console,disabled-by-default-devtools.timeline'
+ 'traceCategories': 'v8,blink.console,disabled-by-default-devtools.timeline'
},
},
'loggingPrefs': {
diff --git a/package.json b/package.json
index 1b62ce1c22..439061d0a5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "angular",
- "version": "2.0.0-alpha.12",
+ "version": "2.0.0-alpha.13",
"description": "Angular 2 - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
"bugs": "https://github.com/angular/angular/issues",
@@ -20,7 +20,10 @@
"url": "https://github.com/angular/angular.git"
},
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "npm run test-js && npm run test-dart",
+ "test-js": "./scripts/ci/test_js.sh",
+ "test-dart": "./scripts/ci/test_dart.sh",
+ "postinstall": "./node_modules/.bin/bower install"
},
"dependencies": {
"es6-module-loader": "^0.9.2",
@@ -36,10 +39,12 @@
"angular": "1.3.5",
"bower": "^1.3.12",
"canonical-path": "0.0.2",
+ "css-parse": "2.0.0",
"del": "~1",
"dgeni": "^0.4.1",
- "dgeni-packages": "^0.10.10",
+ "dgeni-packages": "^0.10.11",
"event-stream": "^3.1.5",
+ "fs-extra": "^0.16.4",
"glob": "^4.0.6",
"gulp": "^3.8.8",
"gulp-changed": "^1.0.0",
@@ -59,9 +64,11 @@
"karma-dart": "^0.2.8",
"karma-jasmine": "^0.2.2",
"lodash": "^2.4.1",
+ "madge": "mlaval/madge#es6",
"merge": "^1.2.0",
"minimatch": "^2.0.1",
"minimist": "1.1.x",
+ "parse5": "1.3.2",
"protractor": "1.7.x",
"q": "^1.0.1",
"run-sequence": "^0.3.6",
diff --git a/protractor-dart2js.conf.js b/protractor-dart2js.conf.js
index 53066b7b4a..ba9e223554 100644
--- a/protractor-dart2js.conf.js
+++ b/protractor-dart2js.conf.js
@@ -6,7 +6,8 @@ config.baseUrl = 'http://localhost:8002/';
config.exclude.push(
'dist/js/cjs/examples/e2e_test/sourcemap/sourcemap_spec.js',
// TODO: remove this line when largetable dart has been added
- 'dist/js/cjs/benchmarks_external/e2e_test/largetable_perf.js'
+ 'dist/js/cjs/benchmarks_external/e2e_test/largetable_perf.js',
+ 'dist/js/cjs/benchmarks_external/e2e_test/polymer_tree_perf.js'
);
data.createBenchpressRunner({ lang: 'dart' });
diff --git a/protractor-shared.js b/protractor-shared.js
index ead58a61df..ecfbdbe77d 100644
--- a/protractor-shared.js
+++ b/protractor-shared.js
@@ -1,5 +1,6 @@
// load traceur runtime as our tests are written in es6
require('traceur/bin/traceur-runtime.js');
+var fs = require('fs-extra');
var argv = require('yargs')
.usage('Angular e2e/perf test options.')
@@ -35,7 +36,7 @@ var browsers = argv['browsers'].split(',');
var CHROME_OPTIONS = {
'args': ['--js-flags=--expose-gc'],
'perfLoggingPrefs': {
- 'traceCategories': 'blink.console,disabled-by-default-devtools.timeline'
+ 'traceCategories': 'v8,blink.console,disabled-by-default-devtools.timeline'
}
};
@@ -122,17 +123,25 @@ var getBenchmarkFiles = function (benchmark, spec) {
};
var config = exports.config = {
- // Disable waiting for Angular as we don't have an integration layer yet...
- // TODO(tbosch): Implement a proper debugging API for Ng2.0, remove this here
- // and the sleeps in all tests.
onPrepare: function() {
- browser.ignoreSynchronization = true;
- var _get = browser.get;
- var sleepInterval = process.env.TRAVIS || process.env.JENKINS_URL ? 7000 : 3000;
- browser.get = function() {
- var result = _get.apply(this, arguments);
- browser.sleep(sleepInterval);
- return result;
+ patchProtractorWait(browser);
+ // During benchmarking, we need to open a new browser
+ // for every benchmark, otherwise the numbers can get skewed
+ // from other benchmarks (e.g. Chrome keeps JIT caches, ...)
+ if (argv['benchmark']) {
+ var originalBrowser = browser;
+ var _tmpBrowser;
+ beforeEach(function() {
+ global.browser = originalBrowser.forkNewDriverInstance();
+ patchProtractorWait(global.browser);
+ global.element = global.browser.element;
+ global.$ = global.browser.$;
+ global.$$ = global.browser.$$;
+ });
+ afterEach(function() {
+ global.browser.quit();
+ global.browser = originalBrowser;
+ });
}
},
@@ -166,6 +175,20 @@ var config = exports.config = {
}
};
+// Disable waiting for Angular as we don't have an integration layer yet...
+// TODO(tbosch): Implement a proper debugging API for Ng2.0, remove this here
+// and the sleeps in all tests.
+function patchProtractorWait(browser) {
+ browser.ignoreSynchronization = true;
+ var _get = browser.get;
+ var sleepInterval = process.env.TRAVIS || process.env.JENKINS_URL ? 7000 : 3000;
+ browser.get = function() {
+ var result = _get.apply(this, arguments);
+ browser.sleep(sleepInterval);
+ return result;
+ }
+}
+
exports.createBenchpressRunner = function(options) {
var nodeUuid = require('node-uuid');
var benchpress = require('./dist/js/cjs/benchpress/benchpress');
@@ -186,13 +209,21 @@ exports.createBenchpressRunner = function(options) {
if (process.env.GIT_SHA) {
runId = process.env.GIT_SHA + ' ' + runId;
}
+ var resultsFolder = './dist/benchmark_results';
+ fs.ensureDirSync(resultsFolder);
var bindings = [
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_BINDINGS,
benchpress.bind(benchpress.Options.FORCE_GC).toValue(argv['force-gc']),
benchpress.bind(benchpress.Options.DEFAULT_DESCRIPTION).toValue({
'lang': options.lang,
'runId': runId
- })
+ }),
+ benchpress.MultiReporter.createBindings([
+ benchpress.ConsoleReporter,
+ benchpress.JsonFileReporter
+ ]),
+ benchpress.JsonFileReporter.BINDINGS,
+ benchpress.bind(benchpress.JsonFileReporter.PATH).toValue(resultsFolder)
];
if (argv['benchmark']) {
bindings.push(benchpress.Validator.bindTo(benchpress.RegressionSlopeValidator));
diff --git a/pubspec.yaml b/pubspec.yaml
index 6f31654cc3..5ba90e5ee8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,4 +5,4 @@ dependencies:
stack_trace: '>=1.1.1 <1.2.0'
dev_dependencies:
- guinness: ">=0.1.16 <0.2.0"
+ guinness: ">=0.1.17 <0.2.0"
diff --git a/scripts/ci/build_and_test.sh b/scripts/ci/build_and_test.sh
index 2192043496..5d7165af8d 100755
--- a/scripts/ci/build_and_test.sh
+++ b/scripts/ci/build_and_test.sh
@@ -9,8 +9,4 @@ SCRIPT_DIR=$(dirname $0)
cd $SCRIPT_DIR/../..
${SCRIPT_DIR}/build_$MODE.sh
-${SCRIPT_DIR}/test_unit_$MODE.sh
-if [ "$MODE" == "dart" ]; then # JS doesn't yet have server tests
- ${SCRIPT_DIR}/test_server_$MODE.sh
-fi
-${SCRIPT_DIR}/test_e2e_$MODE.sh
+${SCRIPT_DIR}/test_$MODE.sh
diff --git a/scripts/ci/test_dart.sh b/scripts/ci/test_dart.sh
new file mode 100755
index 0000000000..bc481d60e6
--- /dev/null
+++ b/scripts/ci/test_dart.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -e
+
+echo =============================================================================
+# go to project dir
+SCRIPT_DIR=$(dirname $0)
+cd $SCRIPT_DIR/../..
+
+${SCRIPT_DIR}/test_unit_dart.sh
+${SCRIPT_DIR}/test_server_dart.sh
+${SCRIPT_DIR}/test_e2e_dart.sh
diff --git a/scripts/ci/test_e2e_dart.sh b/scripts/ci/test_e2e_dart.sh
index cad86c1049..4d7e97ef8f 100755
--- a/scripts/ci/test_e2e_dart.sh
+++ b/scripts/ci/test_e2e_dart.sh
@@ -21,4 +21,4 @@ trap killServer EXIT
# wait for server to come up!
sleep 10
-./node_modules/.bin/protractor protractor-dart2js.conf.js --browsers=$E2E_BROWSERS
\ No newline at end of file
+./node_modules/.bin/protractor protractor-dart2js.conf.js --browsers=${E2E_BROWSERS:-Dartium}
diff --git a/scripts/ci/test_e2e_js.sh b/scripts/ci/test_e2e_js.sh
index 3e151ff73d..53928a2974 100755
--- a/scripts/ci/test_e2e_js.sh
+++ b/scripts/ci/test_e2e_js.sh
@@ -21,4 +21,4 @@ trap killServer EXIT
# wait for server to come up!
sleep 10
-./node_modules/.bin/protractor protractor-js.conf.js --browsers=$E2E_BROWSERS
+./node_modules/.bin/protractor protractor-js.conf.js --browsers=${E2E_BROWSERS:-Dartium}
diff --git a/scripts/ci/test_js.sh b/scripts/ci/test_js.sh
new file mode 100755
index 0000000000..5ec3a5a043
--- /dev/null
+++ b/scripts/ci/test_js.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -e
+
+echo =============================================================================
+# go to project dir
+SCRIPT_DIR=$(dirname $0)
+cd $SCRIPT_DIR/../..
+
+${SCRIPT_DIR}/test_unit_js.sh
+# ${SCRIPT_DIR}/test_server_js.sh # JS doesn't yet have server tests
+${SCRIPT_DIR}/test_e2e_js.sh
diff --git a/scripts/ci/test_unit_js.sh b/scripts/ci/test_unit_js.sh
index 863e8c0423..6d2e6e963d 100755
--- a/scripts/ci/test_unit_js.sh
+++ b/scripts/ci/test_unit_js.sh
@@ -10,3 +10,4 @@ cd $SCRIPT_DIR/../..
./node_modules/.bin/gulp test.transpiler.unittest
./node_modules/.bin/gulp docs/test
./node_modules/.bin/gulp test.unit.js/ci --browsers=$KARMA_BROWSERS
+./node_modules/.bin/gulp test.unit.cjs
diff --git a/test-main.dart b/test-main.dart
index 33d0de13fa..82e616960d 100644
--- a/test-main.dart
+++ b/test-main.dart
@@ -2,6 +2,8 @@ import 'package:guinness/guinness.dart';
import 'package:unittest/unittest.dart' as unit;
import 'package:angular2/src/dom/browser_adapter.dart';
+import 'package:angular2/src/test_lib/test_lib.dart' show testSetup;
+
main() {
BrowserDomAdapter.makeCurrent();
unit.filterStacks = true;
@@ -12,6 +14,8 @@ main() {
guinness.autoInit = false;
guinness.initSpecs();
+
+ testSetup();
}
_printWarnings () {
@@ -24,4 +28,4 @@ _printWarnings () {
if (info.exclusiveDescribes.isNotEmpty) {
print("WARN: ddescribe caused some tests to be excluded");
}
-}
\ No newline at end of file
+}
diff --git a/tools/build/dartanalyzer.js b/tools/build/dartanalyzer.js
index ece942269c..107c515d66 100644
--- a/tools/build/dartanalyzer.js
+++ b/tools/build/dartanalyzer.js
@@ -64,6 +64,9 @@ module.exports = function(gulp, plugins, config) {
if (line.match(/\/test\/core\/compiler\/view_.*spec\.dart/)) {
return;
}
+ if (line.match(/\/test_lib_spec\.dart/)) {
+ return;
+ }
}
if (line.match(/\[hint\]/)) {
hintCount++;
diff --git a/tools/build/html.js b/tools/build/html.js
index d41a2bf280..c3371d4a1f 100644
--- a/tools/build/html.js
+++ b/tools/build/html.js
@@ -17,7 +17,7 @@ module.exports = function(gulp, plugins, config) {
var scripts = util.filterByFile(config.scriptsPerFolder, fileName).map(function(script) {
var scriptTag;
var scriptSrc = script.src;
- if (script.copy) {
+ if (script.copy || script.copyOnly) {
scriptSrc = path.basename(script.src);
self.push(new VinylFile({
cwd: file.cwd,
@@ -26,6 +26,9 @@ module.exports = function(gulp, plugins, config) {
contents: fs.readFileSync(script.src)
}));
};
+ if (script.copyOnly) {
+ return '';
+ }
if (scriptSrc) {
scriptTag = '';
} else {
diff --git a/tools/build/transformCJSTests.js b/tools/build/transformCJSTests.js
new file mode 100644
index 0000000000..53b08c9c83
--- /dev/null
+++ b/tools/build/transformCJSTests.js
@@ -0,0 +1,16 @@
+var through2 = require('through2');
+
+module.exports = function() {
+ return through2.obj(function(file, encoding, done) {
+ if (file.relative.substring(file.relative.length - 8) == "_spec.js") {
+ var content =
+ "var parse5Adapter = require('angular2/src/dom/parse5_adapter');\r\n"
+ + "parse5Adapter.Parse5DomAdapter.makeCurrent();\r\n"
+ + String(file.contents)
+ + "\r\n main();";
+ file.contents = new Buffer(content);
+ }
+ this.push(file);
+ done();
+ });
+}
diff --git a/tools/transpiler/spec/types_spec.js b/tools/transpiler/spec/types_spec.js
index 0facc5751e..4a13028e75 100644
--- a/tools/transpiler/spec/types_spec.js
+++ b/tools/transpiler/spec/types_spec.js
@@ -22,7 +22,6 @@ function namedObjectType({a,b}:{a:A,b:B}) {
class Bar {
constructor({
selector,
- lightDomServices,
implementsTypes
})
{
diff --git a/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js b/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js
index 17e51a51ba..95d5abab60 100644
--- a/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js
+++ b/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js
@@ -516,7 +516,19 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
}
toString() {
- return "library " + this.libName + "_dart;\n" + super.toString();
+ return "library " + this._transformLibName(this.libName) + ";\n" + super.toString();
+ }
+
+ _transformLibName(libName) {
+ var parts = libName.split('.');
+ for (var part of parts) {
+ if (DART_RESERVED_WORDS.indexOf(part) != -1) {
+ return libName + '_dart';
+ }
+ }
+ return libName;
}
}
+// see: https://www.dartlang.org/docs/dart-up-and-running/ch02.html for a full list.
+const DART_RESERVED_WORDS = ['if', 'switch'];
diff --git a/tools/transpiler/unittest/transpilertests.js b/tools/transpiler/unittest/transpilertests.js
index fa95e1f895..52d8dd91d7 100644
--- a/tools/transpiler/unittest/transpilertests.js
+++ b/tools/transpiler/unittest/transpilertests.js
@@ -27,7 +27,7 @@ describe('transpile to dart', function(){
"var s1:string = \"${a}\";" +
"var s2:string = '\\${a}';" +
"var s3:string = '$a';");
- expect(result.js).toBe("library test_dart;\n" +
+ expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = \"\\${a}\";\n" +
"String s2 = '\\${a}';\n" +
@@ -39,7 +39,7 @@ describe('transpile to dart', function(){
"var a:number = 1;" +
"var s1:string = `$a`;" +
"var s2:string = `\\$a`;");
- expect(result.js).toBe("library test_dart;\n" +
+ expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = '''\\$a''';\n" +
"String s2 = '''\\$a''';\n");
@@ -49,7 +49,7 @@ describe('transpile to dart', function(){
var result = compiler.compile(options, "test.js",
"var a:number = 1;" +
"var s1:string = `${a}`;");
- expect(result.js).toBe("library test_dart;\n" +
+ expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = '''${a}''';\n");
});
@@ -60,25 +60,31 @@ describe('transpile to dart', function(){
it('should support types without generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List = [];");
- expect(result.js).toBe("library test_dart;\nList a = [];\n");
+ expect(result.js).toBe("library test;\nList a = [];\n");
});
it('should support one level generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List = [];");
- expect(result.js).toBe("library test_dart;\nList a = [];\n");
+ expect(result.js).toBe("library test;\nList a = [];\n");
});
it('should support multiple one level generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List = [];");
- expect(result.js).toBe("library test_dart;\nList a = [];\n");
+ expect(result.js).toBe("library test;\nList a = [];\n");
});
it('should support nested generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List > = [];");
- expect(result.js).toBe("library test_dart;\nList > a = [];\n");
+ expect(result.js).toBe("library test;\nList > a = [];\n");
+ });
+
+ it('should add dart suffix to reserved words', function() {
+ var result = compiler.compile(options, "project/if.js",
+ "var a;");
+ expect(result.js).toBe("library project.if_dart;\nvar a;\n");
});
});
});