From 33b5ba863e8b0aa451b4415079fb43051debe5f6 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 13 Mar 2015 11:10:11 +0100 Subject: [PATCH] feat(tests): add a test injector fixes #614 Asynchronous test should inject an AsyncTestCompleter: Before: it("async test", (done) => { // ... done(); }); After: it("async test", inject([AsyncTestCompleter], (async) => { // ... async.done(); })); Note: inject() is currently a function and the first parameter is the array of DI tokens to inject as the test function parameters. This construct is linked to Traceur limitations. The planned syntax is: it("async test", @Inject (async: AsyncTestCompleter) => { // ... async.done(); }); --- .../angular2/src/test_lib/test_injector.js | 114 +++++++++++ modules/angular2/src/test_lib/test_lib.dart | 129 ++++++++++--- modules/angular2/src/test_lib/test_lib.es6 | 157 ++++++++++++++- .../angular2/test/core/application_spec.js | 66 ++++--- .../core/compiler/compiler_common_tests.js | 69 ++++--- .../compiler_html5lib.server.spec.dart | 2 + .../test/core/compiler/integration_spec.js | 179 ++++++++++-------- .../shadow_dom_emulation_integration_spec.js | 56 +++--- .../core/compiler/shadow_dom_strategy_spec.js | 19 +- .../test/core/compiler/style_inliner_spec.js | 68 ++++--- .../core/compiler/template_loader_spec.js | 31 ++- .../test/core/zone/vm_turn_zone_spec.js | 37 ++-- modules/angular2/test/di/async_spec.js | 44 +++-- .../angular2/test/directives/foreach_spec.js | 127 +++++++------ modules/angular2/test/directives/if_spec.js | 74 +++++--- .../test/directives/non_bindable_spec.js | 31 ++- .../angular2/test/directives/switch_spec.js | 37 ++-- .../angular2/test/forms/integration_spec.js | 77 ++++---- modules/angular2/test/mock/xhr_mock_spec.js | 43 +++-- .../test/metric/multi_metric_spec.js | 31 ++- .../test/metric/perflog_metric_spec.js | 109 ++++++----- .../test/reporter/json_file_reporter_spec.js | 19 +- .../test/reporter/multi_reporter_spec.js | 25 ++- modules/benchpress/test/runner_spec.js | 55 +++--- modules/benchpress/test/sampler_spec.js | 57 +++--- .../test/web_driver_extension_spec.js | 25 ++- .../webdriver/chrome_driver_extension_spec.js | 109 ++++++----- .../webdriver/ios_driver_extension_spec.js | 85 +++++---- test-main.dart | 6 +- 29 files changed, 1241 insertions(+), 640 deletions(-) create mode 100644 modules/angular2/src/test_lib/test_injector.js diff --git a/modules/angular2/src/test_lib/test_injector.js b/modules/angular2/src/test_lib/test_injector.js new file mode 100644 index 0000000000..d807926a8e --- /dev/null +++ b/modules/angular2/src/test_lib/test_injector.js @@ -0,0 +1,114 @@ +import {bind} from 'angular2/di'; +import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; +import {Reflector, reflector} from 'angular2/src/reflection/reflection'; +import {Parser, Lexer, ChangeDetection, dynamicChangeDetection} from 'angular2/change_detection'; +import {ExceptionHandler} from 'angular2/src/core/exception_handler'; +import {TemplateLoader} from 'angular2/src/core/compiler/template_loader'; +import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; +import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; +import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'; +import {XHR} from 'angular2/src/core/compiler/xhr/xhr'; +import {XHRMock} from 'angular2/src/mock/xhr_mock'; +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 {StyleInliner} from 'angular2/src/core/compiler/style_inliner'; +import {CssProcessor} from 'angular2/src/core/compiler/css_processor'; + +import {Injector} from 'angular2/di'; + +import {List, ListWrapper} from 'angular2/src/facade/collection'; +import {FunctionWrapper} from 'angular2/src/facade/lang'; + +/** + * Returns the root injector bindings. + * + * This must be kept in sync with the _rootBindings in application.js + * + * @returns {*[]} + */ +function _getRootBindings() { + return [ + bind(Reflector).toValue(reflector), + ]; +} + +/** + * Returns the application injector bindings. + * + * This must be kept in sync with _injectorBindings() in application.js + * + * @returns {*[]} + */ +function _getAppBindings() { + return [ + bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy), + Compiler, + CompilerCache, + TemplateResolver, + bind(ChangeDetection).toValue(dynamicChangeDetection), + TemplateLoader, + DirectiveMetadataReader, + Parser, + Lexer, + ExceptionHandler, + bind(XHR).toClass(XHRMock), + ComponentUrlMapper, + UrlResolver, + StyleUrlResolver, + StyleInliner, + bind(CssProcessor).toFactory(() => new CssProcessor(null), []), + ]; +} + +export function createTestInjector(bindings: List) { + var rootInjector = new Injector(_getRootBindings()); + return rootInjector.createChild(ListWrapper.concat(_getAppBindings(), bindings)); +} + +/** + * Allows injecting dependencies in beforeEach() and it(). + * + * Example: + * + * beforeEach(inject([Dependency, AClass], (dep, object) => { + * // some code that uses `dep` and `object` + * // ... + * })); + * + * it('...', inject([AClass, AsyncTestCompleter], (object, async) => { + * object.doSomething().then(() => { + * expect(...); + * async.done(); + * }); + * }) + * + * Notes: + * - injecting an `AsyncTestCompleter` allow completing async tests - this is the equivalent of + * adding a `done` parameter in Jasmine, + * - inject is currently a function because of some Traceur limitation the syntax should eventually + * becomes `it('...', @Inject (object: AClass, async: AsyncTestCompleter) => { ... });` + * + * @param {Array} tokens + * @param {Function} fn + * @return {FunctionWithParamTokens} + */ +export function inject(tokens: List, fn: Function) { + return new FunctionWithParamTokens(tokens, fn); +} + +export class FunctionWithParamTokens { + _tokens: List; + _fn: Function; + + constructor(tokens: List, fn: Function) { + this._tokens = tokens; + this._fn = fn; + } + + execute(injector: Injector) { + var params = ListWrapper.map(this._tokens, (t) => injector.get(t)); + FunctionWrapper.apply(this._fn, params); + } +} + diff --git a/modules/angular2/src/test_lib/test_lib.dart b/modules/angular2/src/test_lib/test_lib.dart index dfa3557972..ba8b2c051d 100644 --- a/modules/angular2/src/test_lib/test_lib.dart +++ b/modules/angular2/src/test_lib/test_lib.dart @@ -1,18 +1,76 @@ library test_lib.test_lib; import 'package:guinness/guinness.dart' as gns; -export 'package:guinness/guinness.dart' hide Expect, expect, NotExpect, beforeEach, it, iit; +export 'package:guinness/guinness.dart' hide Expect, expect, NotExpect, beforeEach, it, iit, xit; import 'package:unittest/unittest.dart' hide expect; import 'dart:mirrors'; import 'dart:async'; -import 'package:angular2/src/reflection/reflection.dart'; -import 'package:angular2/src/reflection/reflection_capabilities.dart'; + import 'package:collection/equality.dart'; import 'package:angular2/src/dom/dom_adapter.dart' show DOM; +import 'package:angular2/src/reflection/reflection.dart'; +import 'package:angular2/src/reflection/reflection_capabilities.dart'; + +import 'package:angular2/src/di/binding.dart' show bind; +import 'package:angular2/src/di/injector.dart' show Injector; + +import './test_injector.dart'; +export './test_injector.dart' show inject; + bool IS_DARTIUM = true; bool IS_NODEJS = false; +List _testBindings = []; +Injector _injector; +bool _isCurrentTestAsync; +bool _inIt = false; + +class AsyncTestCompleter { + Completer _completer; + + AsyncTestCompleter() { + _completer = new Completer(); + } + + done() { + _completer.complete(); + } + + get future => _completer.future; +} + +testSetup() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + // beforeEach configuration: + // - Priority 3: clear the bindings before each test, + // - Priority 2: collect the bindings before each test, see beforeEachBindings(), + // - Priority 1: create the test injector to be used in beforeEach() and it() + + gns.beforeEach( + () { + _testBindings.clear(); + }, + priority: 3 + ); + + var completerBinding = bind(AsyncTestCompleter).toFactory(() { + // Mark the test as async when an AsyncTestCompleter is injected in an it(), + if (!_inIt) throw 'AsyncTestCompleter can only be injected in an "it()"'; + _isCurrentTestAsync = true; + return new AsyncTestCompleter(); + }); + + gns.beforeEach( + () { + _isCurrentTestAsync = false; + _testBindings.add(completerBinding); + _injector = createTestInjector(_testBindings); + }, + priority: 1 + ); +} + Expect expect(actual, [matcher]) { final expect = new Expect(actual); if (matcher != null) expect.to(matcher); @@ -46,38 +104,55 @@ class NotExpect extends gns.NotExpect { } beforeEach(fn) { - gns.beforeEach(_enableReflection(fn)); + if (fn is! FunctionWithParamTokens) fn = new FunctionWithParamTokens([], fn); + gns.beforeEach(() { + fn.execute(_injector); + }); } +/** + * Allows overriding default bindings defined in test_injector.js. + * + * The given function must return a list of DI bindings. + * + * Example: + * + * beforeEachBindings(() => [ + * bind(Compiler).toClass(MockCompiler), + * bind(SomeToken).toValue(myValue), + * ]); + */ +beforeEachBindings(fn) { + gns.beforeEach( + () { + var bindings = fn(); + if (bindings != null) _testBindings.addAll(bindings); + }, + priority: 2 + ); +} + +_it(gnsFn, name, fn) { + if (fn is! FunctionWithParamTokens) fn = new FunctionWithParamTokens([], fn); + gnsFn(name, () { + _inIt = true; + fn.execute(_injector); + _inIt = false; + if (_isCurrentTestAsync) return _injector.get(AsyncTestCompleter).future; + }); +} + + it(name, fn) { - gns.it(name, _enableReflection(_handleAsync(fn))); + _it(gns.it, name, fn); } iit(name, fn) { - gns.iit(name, _enableReflection(_handleAsync(fn))); + _it(gns.iit, name, fn); } -_enableReflection(fn) { - return () { - reflector.reflectionCapabilities = new ReflectionCapabilities(); - return fn(); - }; -} - -_handleAsync(fn) { - ClosureMirror cm = reflect(fn); - MethodMirror mm = cm.function; - - var completer = new Completer(); - - if (mm.parameters.length == 1) { - return () { - cm.apply([completer.complete]); - return completer.future; - }; - } - - return fn; +xit(name, fn) { + _it(gns.xit, name, fn); } // TODO(tbosch): remove when https://github.com/vsavkin/guinness/issues/41 diff --git a/modules/angular2/src/test_lib/test_lib.es6 b/modules/angular2/src/test_lib/test_lib.es6 index 628dc44d3c..0e8b42f6d5 100644 --- a/modules/angular2/src/test_lib/test_lib.es6 +++ b/modules/angular2/src/test_lib/test_lib.es6 @@ -1,20 +1,160 @@ import {DOM} from 'angular2/src/dom/dom_adapter'; +import {bind} from 'angular2/di'; + +import {createTestInjector, FunctionWithParamTokens, inject} from './test_injector'; + +export {inject} from './test_injector'; + +export {proxy} from 'rtts_assert/rtts_assert'; + var _global = typeof window === 'undefined' ? global : window; -export {proxy} from 'rtts_assert/rtts_assert'; -export var describe = _global.describe; -export var xdescribe = _global.xdescribe; -export var ddescribe = _global.ddescribe; -export var it = _global.it; -export var xit = _global.xit; -export var iit = _global.iit; -export var beforeEach = _global.beforeEach; export var afterEach = _global.afterEach; export var expect = _global.expect; + export var IS_DARTIUM = false; export var IS_NODEJS = typeof window === 'undefined'; +export class AsyncTestCompleter { + _done: Function; + + constructor(done: Function) { + this._done = done; + } + + done() { + this._done(); + } +} + +var jsmBeforeEach = _global.beforeEach; +var jsmDescribe = _global.describe; +var jsmDDescribe = _global.ddescribe; +var jsmXDescribe = _global.xdescribe; +var jsmIt = _global.it; +var jsmIIt = _global.iit; +var jsmXIt = _global.xit; + +var runnerStack = []; +var inIt = false; + +var testBindings; + +class BeforeEachRunner { + constructor(parent: BeforeEachRunner) { + this._fns = []; + this._parent = parent; + } + + beforeEach(fn: FunctionWithParamTokens) { + this._fns.push(fn); + } + + run(injector) { + if (this._parent) this._parent.run(); + this._fns.forEach((fn) => fn.execute(injector)); + } +} + +// Reset the test bindings before each test +jsmBeforeEach(() => { testBindings = []; }); + +function _describe(jsmFn, ...args) { + var parentRunner = runnerStack.length === 0 ? null : runnerStack[runnerStack.length - 1]; + var runner = new BeforeEachRunner(parentRunner); + runnerStack.push(runner); + var suite = jsmFn(...args); + runnerStack.pop(); + return suite; +} + +export function describe(...args) { + return _describe(jsmDescribe, ...args); +} + +export function ddescribe(...args) { + return _describe(jsmDDescribe, ...args); +} + +export function xdescribe(...args) { + return _describe(jsmXDescribe, ...args); +} + +export function beforeEach(fn) { + if (runnerStack.length > 0) { + // Inside a describe block, beforeEach() uses a BeforeEachRunner + var runner = runnerStack[runnerStack.length - 1]; + if (!(fn instanceof FunctionWithParamTokens)) { + fn = inject([], fn); + } + runner.beforeEach(fn); + } else { + // Top level beforeEach() are delegated to jasmine + jsmBeforeEach(fn); + } +} + +/** + * Allows overriding default bindings defined in test_injector.js. + * + * The given function must return a list of DI bindings. + * + * Example: + * + * beforeEachBindings(() => [ + * bind(Compiler).toClass(MockCompiler), + * bind(SomeToken).toValue(myValue), + * ]); + */ +export function beforeEachBindings(fn) { + jsmBeforeEach(() => { + var bindings = fn(); + if (!bindings) return; + testBindings = [...testBindings, ...bindings]; + }); +} + +function _it(jsmFn, name, fn) { + var runner = runnerStack[runnerStack.length - 1]; + + jsmFn(name, function(done) { + var async = false; + + var completerBinding = bind(AsyncTestCompleter).toFactory(() => { + // Mark the test as async when an AsyncTestCompleter is injected in an it() + if (!inIt) throw new Error('AsyncTestCompleter can only be injected in an "it()"'); + async = true; + return new AsyncTestCompleter(done); + }); + + var injector = createTestInjector([...testBindings, completerBinding]); + + runner.run(injector); + + if (!(fn instanceof FunctionWithParamTokens)) { + fn = inject([], fn); + } + inIt = true; + fn.execute(injector); + inIt = false; + + if (!async) done(); + }); +} + +export function it(name, fn) { + return _it(jsmIt, name, fn); +} + +export function xit(name, fn) { + return _it(jsmXIt, name, fn); +} + +export function iit(name, fn) { + return _it(jsmIIt, name, fn); +} + // To make testing consistent between dart and js _global.print = function(msg) { if (_global.dump) { @@ -151,7 +291,6 @@ export class SpyObject { } } - function elementText(n) { var hasNodes = (n) => {var children = DOM.childNodes(n); return children && children.length > 0;} if (!IS_NODEJS) { diff --git a/modules/angular2/test/core/application_spec.js b/modules/angular2/test/core/application_spec.js index db2568e5b9..65c94663dd 100644 --- a/modules/angular2/test/core/application_spec.js +++ b/modules/angular2/test/core/application_spec.js @@ -1,4 +1,15 @@ -import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach} from 'angular2/test_lib'; +import { + AsyncTestCompleter, + beforeEach, + ddescribe, + describe, + expect, + iit, + inject, + it, + xdescribe, + xit, +} from 'angular2/test_lib'; import {bootstrap, appDocumentToken, appElementToken} from 'angular2/src/core/application'; import {Component} from 'angular2/src/core/annotations/annotations'; @@ -69,55 +80,56 @@ export function main() { }); describe('bootstrap factory method', () => { - it('should throw if no element is found', (done) => { + it('should throw if no element is found', inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp, [], (e,t) => {throw e;}); PromiseWrapper.then(injectorPromise, null, (reason) => { expect(reason.message).toContain( 'The app selector "hello-app" did not match any elements'); - done(); + async.done(); }); - }); + })); it('should create an injector promise', () => { var injectorPromise = bootstrap(HelloRootCmp, testBindings); expect(injectorPromise).not.toBe(null); }); - it('should resolve an injector promise and contain bindings', (done) => { + it('should resolve an injector promise and contain bindings', inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp, testBindings); injectorPromise.then((injector) => { expect(injector.get(appElementToken)).toBe(el); - done(); + async.done(); }); - }); + })); - it('should provide the application component in the injector', (done) => { + it('should provide the application component in the injector', inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp, testBindings); injectorPromise.then((injector) => { expect(injector.get(HelloRootCmp)).toBeAnInstanceOf(HelloRootCmp); - done(); + async.done(); }); - }); + })); - it('should display hello world', (done) => { + it('should display hello world', inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp, testBindings); injectorPromise.then((injector) => { - expect(injector.get(appElementToken)).toHaveText('hello world!'); - done(); - }); - }); - it('should support multiple calls to bootstrap', (done) => { + expect(injector.get(appElementToken)).toHaveText('hello world!'); + async.done(); + }); + })); + + it('should support multiple calls to bootstrap', inject([AsyncTestCompleter], (async) => { var injectorPromise1 = bootstrap(HelloRootCmp, testBindings); var injectorPromise2 = bootstrap(HelloRootCmp2, testBindings); PromiseWrapper.all([injectorPromise1, injectorPromise2]).then((injectors) => { expect(injectors[0].get(appElementToken)).toHaveText('hello world!'); expect(injectors[1].get(appElementToken)).toHaveText('hello world, again!'); - done(); + async.done(); }); - }); + })); - it("should make the provided bindings available to the application component", (done) => { + it("should make the provided bindings available to the application component", inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp3, [ testBindings, bind("appBinding").toValue("BoundValue") @@ -125,25 +137,25 @@ export function main() { injectorPromise.then((injector) => { expect(injector.get(HelloRootCmp3).appBinding).toEqual("BoundValue"); - done(); + async.done(); }); - }); + })); - it("should avoid cyclic dependencies when root component requires Lifecycle through DI", (done) => { + it("should avoid cyclic dependencies when root component requires Lifecycle through DI", inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmp4, testBindings); injectorPromise.then((injector) => { expect(injector.get(HelloRootCmp4).lc).toBe(injector.get(LifeCycle)); - done(); + async.done(); }); - }); + })); - it("should support shadow dom content tag", (done) => { + it("should support shadow dom content tag", inject([AsyncTestCompleter], (async) => { var injectorPromise = bootstrap(HelloRootCmpContent, testBindings); injectorPromise.then((injector) => { expect(injector.get(appElementToken)).toHaveText('before: loading after: done'); - done(); + async.done(); }); - }); + })); }); } diff --git a/modules/angular2/test/core/compiler/compiler_common_tests.js b/modules/angular2/test/core/compiler/compiler_common_tests.js index 690ac250e8..514aafee75 100644 --- a/modules/angular2/test/core/compiler/compiler_common_tests.js +++ b/modules/angular2/test/core/compiler/compiler_common_tests.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 {DOM} from 'angular2/src/dom/dom_adapter'; import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; @@ -51,7 +62,7 @@ export function runCompilerCommonTests() { urlResolver, new ComponentUrlMapper()); } - it('should run the steps and return the ProtoView of the root element', (done) => { + it('should run the steps and return the ProtoView of the root element', inject([AsyncTestCompleter], (async) => { var rootProtoView = new ProtoView(null, null, null); var compiler = createCompiler( (parent, current, control) => { current.inheritedProtoView = rootProtoView; @@ -59,21 +70,21 @@ export function runCompilerCommonTests() { tplResolver.setTemplate(MainComponent, new Template({inline: '
'})); compiler.compile(MainComponent).then( (protoView) => { expect(protoView).toBe(rootProtoView); - done(); + async.done(); }); - }); + })); - it('should use the inline template', (done) => { + it('should use the inline template', inject([AsyncTestCompleter], (async) => { var compiler = createCompiler( (parent, current, control) => { current.inheritedProtoView = new ProtoView(current.element, null, null); }); compiler.compile(MainComponent).then( (protoView) => { expect(DOM.getInnerHTML(protoView.element)).toEqual('inline component'); - done(); + async.done(); }); - }); + })); - it('should wait for async styles to be resolved', (done) => { + it('should wait for async styles to be resolved', inject([AsyncTestCompleter], (async) => { var styleResolved = false; var completer = PromiseWrapper.completer(); @@ -95,11 +106,11 @@ export function runCompilerCommonTests() { completer.resolve(null); pvPromise.then((protoView) => { expect(styleResolved).toEqual(true); - done(); + async.done(); }); - }); + })); - it('should load nested components', (done) => { + it('should load nested components', inject([AsyncTestCompleter], (async) => { var compiler = createCompiler( (parent, current, control) => { if (DOM.hasClass(current.element, 'nested')) { current.componentDirective = reader.read(NestedComponent); @@ -113,11 +124,11 @@ export function runCompilerCommonTests() { compiler.compile(MainComponent).then( (protoView) => { var nestedView = protoView.elementBinders[0].nestedProtoView; expect(DOM.getInnerHTML(nestedView.element)).toEqual('nested component'); - done(); + async.done(); }); - }); + })); - it('should cache compiled components', (done) => { + it('should cache compiled components', inject([AsyncTestCompleter], (async) => { var compiler = createCompiler( (parent, current, control) => { current.inheritedProtoView = new ProtoView(current.element, null, null); }); @@ -128,11 +139,11 @@ export function runCompilerCommonTests() { return compiler.compile(MainComponent); }).then( (protoView) => { expect(firstProtoView).toBe(protoView); - done(); + async.done(); }); - }); + })); - it('should re-use components being compiled', (done) => { + it('should re-use components being compiled', inject([AsyncTestCompleter], (async) => { var nestedElBinders = []; var compiler = createCompiler( (parent, current, control) => { current.inheritedProtoView = new ProtoView(current.element, null, null); @@ -146,11 +157,11 @@ export function runCompilerCommonTests() { new Template({inline: '
'})); compiler.compile(MainComponent).then( (protoView) => { expect(nestedElBinders[0].nestedProtoView).toBe(nestedElBinders[1].nestedProtoView); - done(); + async.done(); }); - }); + })); - it('should allow recursive components', (done) => { + it('should allow recursive components', inject([AsyncTestCompleter], (async) => { var compiler = createCompiler( (parent, current, control) => { current.inheritedProtoView = new ProtoView(current.element, null, null); current.inheritedElementBinder = current.inheritedProtoView.bindElement(null); @@ -158,9 +169,9 @@ export function runCompilerCommonTests() { }); compiler.compile(RecursiveComponent).then( (protoView) => { expect(protoView.elementBinders[0].nestedProtoView).toBe(protoView); - done(); + async.done(); }); - }); + })); }); }); @@ -176,7 +187,7 @@ export function runCompilerCommonTests() { } function createNestedComponentSpec(name, resolver: TemplateResolver, error:string = null) { - it(`should load nested components ${name}`, (done) => { + it(`should load nested components ${name}`, inject([AsyncTestCompleter], (async) => { var compiler = createCompiler((parent, current, control) => { if (DOM.hasClass(current.element, 'parent')) { @@ -193,14 +204,14 @@ export function runCompilerCommonTests() { var nestedView = protoView.elementBinders[0].nestedProtoView; expect(error).toBeNull(); expect(DOM.getInnerHTML(nestedView.element)).toEqual('nested component'); - done(); + async.done(); }, function(compileError) { expect(compileError.message).toEqual(error); - done(); + async.done(); } ); - }); + })); } var templateResolver = new FakeTemplateResolver(); @@ -244,7 +255,7 @@ export function runCompilerCommonTests() { }); describe('URL resolution', () => { - it('should resolve template URLs by combining application, component and template URLs', (done) => { + it('should resolve template URLs by combining application, component and template URLs', inject([AsyncTestCompleter], (async) => { var steps = [new MockStep((parent, current, control) => { current.inheritedProtoView = new ProtoView(current.element, null, null); })]; @@ -263,9 +274,9 @@ export function runCompilerCommonTests() { tplResolver.setTemplate(MainComponent, template); compiler.compile(MainComponent).then((protoView) => { expect(tplLoader.getTemplateUrl(template)).toEqual('http://www.app.com/cmp/tpl.html'); - done(); + async.done(); }); - }) + })) }); }); } diff --git a/modules/angular2/test/core/compiler/compiler_html5lib.server.spec.dart b/modules/angular2/test/core/compiler/compiler_html5lib.server.spec.dart index c25f660ae9..2bbf506e6c 100644 --- a/modules/angular2/test/core/compiler/compiler_html5lib.server.spec.dart +++ b/modules/angular2/test/core/compiler/compiler_html5lib.server.spec.dart @@ -1,9 +1,11 @@ library angular2.compiler.html5lib_dom_adapter.test; import 'package:angular2/src/dom/html5lib_adapter.dart'; +import 'package:angular2/src/test_lib/test_lib.dart' show testSetup; import 'compiler_common_tests.dart'; void main() { Html5LibDomAdapter.makeCurrent(); + testSetup(); runCompilerCommonTests(); } diff --git a/modules/angular2/test/core/compiler/integration_spec.js b/modules/angular2/test/core/compiler/integration_spec.js index ba33608055..34331fa9b9 100644 --- a/modules/angular2/test/core/compiler/integration_spec.js +++ b/modules/angular2/test/core/compiler/integration_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 {Type, isPresent, BaseException, assertionsEnabled, isJsObject} from 'angular2/src/facade/lang'; @@ -61,7 +72,7 @@ export function main() { cd = view.changeDetector; } - it('should consume text node changes', (done) => { + it('should consume text node changes', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({inline: '
{{ctxProp}}
'})); compiler.compile(MyComp).then((pv) => { createView(pv); @@ -69,11 +80,11 @@ export function main() { cd.detectChanges(); expect(DOM.getInnerHTML(view.nodes[0])).toEqual('Hello World!'); - done(); + async.done(); }); - }); + })); - it('should consume element binding changes', (done) => { + it('should consume element binding changes', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({inline: '
'})); compiler.compile(MyComp).then((pv) => { @@ -83,11 +94,11 @@ export function main() { cd.detectChanges(); expect(view.nodes[0].id).toEqual('Hello World!'); - done(); + async.done(); }); - }); + })); - it('should consume binding to aria-* attributes', (done) => { + it('should consume binding to aria-* attributes', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({inline: '
'})); compiler.compile(MyComp).then((pv) => { @@ -101,11 +112,11 @@ export function main() { cd.detectChanges(); expect(DOM.getAttribute(view.nodes[0], 'aria-label')).toEqual('Changed aria label'); - done(); + async.done(); }); - }); + })); - it('should consume binding to property names where attr name and property name do not match', (done) => { + it('should consume binding to property names where attr name and property name do not match', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({inline: '
'})); compiler.compile(MyComp).then((pv) => { @@ -118,11 +129,11 @@ export function main() { cd.detectChanges(); expect(view.nodes[0].tabIndex).toEqual(5); - done(); + async.done(); }); - }); + })); - it('should consume binding to inner-html', (done) => { + it('should consume binding to inner-html', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({inline: '
'})); compiler.compile(MyComp).then((pv) => { @@ -136,11 +147,11 @@ export function main() { cd.detectChanges(); expect(DOM.getInnerHTML(view.nodes[0])).toEqual('Some other
HTML
'); - done(); + async.done(); }); - }); + })); - it('should consume directive watch expression change.', (done) => { + it('should consume directive watch expression change.', inject([AsyncTestCompleter], (async) => { var tpl = '
' + '
' + @@ -160,11 +171,11 @@ export function main() { expect(view.elementInjectors[1].get(MyDir).dirProp).toEqual('Hi there!'); expect(view.elementInjectors[2].get(MyDir).dirProp).toEqual('Hi there!'); expect(view.elementInjectors[3].get(MyDir).dirProp).toEqual('One more Hello World!'); - done(); + async.done(); }); - }); + })); - it("should support pipes in bindings and bind config", (done) => { + it("should support pipes in bindings and bind config", inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({ inline: '', @@ -187,11 +198,11 @@ export function main() { // it is doubled twice: once in the binding, second time in the bind config expect(comp.prop).toEqual('aaaa'); - done(); + async.done(); }); - }); + })); - it('should support nested components.', (done) => { + it('should support nested components.', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({ inline: '', directives: [ChildComp] @@ -203,12 +214,12 @@ export function main() { cd.detectChanges(); expect(view.nodes[0].shadowRoot.childNodes[0].nodeValue).toEqual('hello'); - done(); + async.done(); }); - }); + })); // GH issue 328 - https://github.com/angular/angular/issues/328 - it('should support different directive types on a single node', (done) => { + it('should support different directive types on a single node', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({ inline: '', @@ -225,11 +236,11 @@ export function main() { expect(elInj.get(MyDir).dirProp).toEqual('Hello World!'); expect(elInj.get(ChildComp).dirProp).toEqual(null); - done(); + async.done(); }); - }); + })); - it('should support directives where a binding attribute is not given', function(done) { + it('should support directives where a binding attribute is not given', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({ // No attribute "el-prop" specified. @@ -239,11 +250,11 @@ export function main() { compiler.compile(MyComp).then((pv) => { createView(pv); - done(); + async.done(); }); - }); + })); - it('should support directives where a selector matches property binding', function(done) { + it('should support directives where a selector matches property binding', inject([AsyncTestCompleter], (async) => { tplResolver.setTemplate(MyComp, new Template({ inline: '

', @@ -263,11 +274,11 @@ export function main() { expect(view.nodes[0].id).toEqual('other_id'); expect(DOM.getInnerHTML(view.nodes[0].shadowRoot.childNodes[0])).toEqual('Matched on id with other_id'); - done(); + async.done(); }); - }); + })); - it('should support template directives via `