mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(): Fixes ALL dartanalyzer problems (so far).
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
import {
|
||||
inject,
|
||||
injectAsync,
|
||||
ComponentFixture,
|
||||
TestComponentBuilder,
|
||||
beforeEachProviders,
|
||||
} from 'angular2/testing';
|
||||
import {
|
||||
it,
|
||||
iit,
|
||||
describe,
|
||||
ddescribe,
|
||||
expect,
|
||||
inject,
|
||||
injectAsync,
|
||||
TestComponentBuilder,
|
||||
beforeEachProviders,
|
||||
beforeEach,
|
||||
} from 'angular2/testing';
|
||||
} from '../../core/facade/testing';
|
||||
import {provide, Component, DebugElement} from 'angular2/core';
|
||||
import {By} from 'angular2/platform/browser';
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import {Component, ViewEncapsulation, Input, HostBinding, HostListener, ChangeDetectionStrategy} from 'angular2/core';
|
||||
import {
|
||||
Component,
|
||||
ViewEncapsulation,
|
||||
Input,
|
||||
HostBinding,
|
||||
HostListener,
|
||||
ChangeDetectionStrategy,
|
||||
} from 'angular2/core';
|
||||
import {TimerWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
// TODO(jelbourn): Ink ripples.
|
||||
// TODO(jelbourn): Make the `isMouseDown` stuff done with one global listener.
|
||||
@@ -37,7 +45,7 @@ export class MdButton {
|
||||
// button continues to look :active after clicking.
|
||||
// @see http://marcysutton.com/button-focus-hell/
|
||||
this.isMouseDown = true;
|
||||
setTimeout(() => { this.isMouseDown = false; }, 100);
|
||||
TimerWrapper.setTimeout(() => { this.isMouseDown = false; }, 100);
|
||||
}
|
||||
|
||||
setKeyboardFocus($event: any) {
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
import {
|
||||
inject,
|
||||
injectAsync,
|
||||
ComponentFixture,
|
||||
TestComponentBuilder,
|
||||
beforeEachProviders,
|
||||
} from 'angular2/testing';
|
||||
import {
|
||||
it,
|
||||
iit,
|
||||
describe,
|
||||
ddescribe,
|
||||
expect,
|
||||
inject,
|
||||
injectAsync,
|
||||
TestComponentBuilder,
|
||||
beforeEachProviders,
|
||||
beforeEach,
|
||||
} from 'angular2/testing';
|
||||
} from '../../core/facade/testing';
|
||||
import {
|
||||
getComputedStyle
|
||||
} from '../../core/facade/html';
|
||||
import {provide, Component, DebugElement} from 'angular2/core';
|
||||
import {By} from 'angular2/platform/browser';
|
||||
|
||||
import {MdSidenav, MdSidenavLayout, MD_SIDENAV_DIRECTIVES} from './sidenav';
|
||||
import {AsyncTestFn, FunctionWithParamTokens} from 'angular2/testing';
|
||||
import {ComponentFixture} from 'angular2/testing';
|
||||
import {EventEmitter} from 'angular2/core';
|
||||
import {Predicate} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/promise';
|
||||
import {TimerWrapper} from 'angular2/src/facade/async';
|
||||
import {MdSidenav, MdSidenavLayout, MD_SIDENAV_DIRECTIVES} from './sidenav';
|
||||
|
||||
|
||||
function wait(msec: number) {
|
||||
let completer = PromiseWrapper.completer();
|
||||
TimerWrapper.setTimeout(completer.resolve, msec);
|
||||
TimerWrapper.setTimeout(() => {
|
||||
completer.resolve(null);
|
||||
}, msec);
|
||||
return completer.promise;
|
||||
}
|
||||
|
||||
@@ -38,7 +42,7 @@ function waitOnEvent(fixture: ComponentFixture,
|
||||
let completer = PromiseWrapper.completer();
|
||||
let component: any = fixture.debugElement.query(by).componentInstance;
|
||||
component[propertyName].subscribe(() => {
|
||||
completer.resolve();
|
||||
completer.resolve(null);
|
||||
});
|
||||
return completer.promise;
|
||||
}
|
||||
@@ -63,7 +67,7 @@ export function main() {
|
||||
testComponent = fixture.debugElement.componentInstance;
|
||||
fixture.detectChanges();
|
||||
return wait(1);
|
||||
}).then((f) => {
|
||||
}).then((_: any) => {
|
||||
let openButtonElement = fixture.debugElement.query(By.css('.open'));
|
||||
openButtonElement.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
@@ -81,8 +85,8 @@ export function main() {
|
||||
|
||||
let sidenavElement = fixture.debugElement.query(By.css('md-sidenav'));
|
||||
let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop'));
|
||||
expect(window.getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('visible');
|
||||
expect(window.getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('visible');
|
||||
expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('visible');
|
||||
expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('visible');
|
||||
|
||||
// Close it.
|
||||
let closeButtonElement = fixture.debugElement.query(By.css('.close'));
|
||||
@@ -107,10 +111,10 @@ export function main() {
|
||||
|
||||
let sidenavElement = fixture.debugElement.query(By.css('md-sidenav'));
|
||||
let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop'));
|
||||
expect(window.getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('hidden');
|
||||
expect(window.getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('hidden');
|
||||
expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('hidden');
|
||||
expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('hidden');
|
||||
})
|
||||
.then(done, done.fail);
|
||||
.then((_: any) => { done(); });
|
||||
}, 8000);
|
||||
|
||||
it('open() and close() return a promise that resolves after the animation ended',
|
||||
@@ -149,7 +153,7 @@ export function main() {
|
||||
})
|
||||
.then((_: any) => promise)
|
||||
.then((_: any) => expect(called).toBe(true))
|
||||
.then(done, done.fail);
|
||||
.then((_: any) => { done(); });
|
||||
}, 8000);
|
||||
|
||||
it('open() twice returns the same promise', (done: any) => {
|
||||
@@ -175,7 +179,7 @@ export function main() {
|
||||
promise = sidenav.close();
|
||||
expect(sidenav.close()).toBe(promise);
|
||||
})
|
||||
.then(done, done.fail);
|
||||
.then((_: any) => { done(); });
|
||||
});
|
||||
|
||||
it('open() then close() cancel animations when called too fast',
|
||||
@@ -183,7 +187,6 @@ export function main() {
|
||||
let fixture: ComponentFixture;
|
||||
let sidenav: MdSidenav;
|
||||
|
||||
let openPromise: Promise<void>;
|
||||
let closePromise: Promise<void>;
|
||||
let openCalled: boolean = false;
|
||||
let openCancelled: boolean = false;
|
||||
@@ -194,7 +197,7 @@ export function main() {
|
||||
fixture = f;
|
||||
sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance;
|
||||
|
||||
openPromise = sidenav.open().then((_: any) => {
|
||||
sidenav.open().then((_: any) => {
|
||||
openCalled = true;
|
||||
},
|
||||
() => {
|
||||
@@ -208,7 +211,7 @@ export function main() {
|
||||
.then((_: any) => {
|
||||
closePromise = sidenav.close().then((_: any) => {
|
||||
closeCalled = true;
|
||||
}, done.fail);
|
||||
});
|
||||
return wait(1);
|
||||
})
|
||||
.then((_: any) => {
|
||||
@@ -220,17 +223,15 @@ export function main() {
|
||||
expect(openCancelled).toBe(true);
|
||||
expect(closeCalled).toBe(true);
|
||||
})
|
||||
.then(done, done.fail);
|
||||
.then((_: any) => { done(); });
|
||||
}, 8000);
|
||||
|
||||
it('close() then open() cancel animations when called too fast',
|
||||
(done: any) => {
|
||||
let testComponent: BasicTestApp;
|
||||
let fixture: ComponentFixture;
|
||||
let sidenav: MdSidenav;
|
||||
|
||||
let openPromise: Promise<void>;
|
||||
let closePromise: Promise<void>;
|
||||
let closeCalled: boolean = false;
|
||||
let closeCancelled: boolean = false;
|
||||
let openCalled: boolean = false;
|
||||
@@ -250,10 +251,9 @@ export function main() {
|
||||
})
|
||||
.then((_: any) => {
|
||||
// Then close and check behavior.
|
||||
closePromise = sidenav.close().then((_: any) => {
|
||||
sidenav.close().then((_: any) => {
|
||||
closeCalled = true;
|
||||
},
|
||||
() => {
|
||||
}, () => {
|
||||
closeCancelled = true;
|
||||
});
|
||||
})
|
||||
@@ -276,7 +276,7 @@ export function main() {
|
||||
expect(closeCancelled).toBe(true);
|
||||
expect(openCalled).toBe(true);
|
||||
})
|
||||
.then(done, done.fail);
|
||||
.then((_: any) => { done(); });
|
||||
}, 8000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
Component,
|
||||
ContentChildren,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Host,
|
||||
HostBinding,
|
||||
HostListener,
|
||||
@@ -14,7 +13,8 @@ import {
|
||||
Type,
|
||||
ChangeDetectionStrategy
|
||||
} from 'angular2/core';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/promise';
|
||||
import {PromiseWrapper, ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
||||
import {iterateListLike} from 'angular2/src/facade/collection';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {CONST_EXPR, isPresent} from 'angular2/src/facade/lang';
|
||||
import {Dir} from '../../directives/dir/dir';
|
||||
@@ -128,9 +128,6 @@ export class MdSidenav {
|
||||
this.onCloseStart.emit(null);
|
||||
}
|
||||
|
||||
let emitter = isOpen ? this.onOpen : this.onClose;
|
||||
let other = isOpen ? this.onClose : this.onOpen;
|
||||
|
||||
if (isOpen) {
|
||||
if (this.openPromise_ == null) {
|
||||
let completer = PromiseWrapper.completer();
|
||||
@@ -259,13 +256,13 @@ export class MdSidenavLayout implements AfterContentInit {
|
||||
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
|
||||
// properties to point to the proper start/end.
|
||||
if (dir_ != null) {
|
||||
dir_.dirChange.subscribe(() => this.validateDrawers_());
|
||||
dir_.dirChange.add(() => this.validateDrawers_());
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
// On changes, assert on consistency.
|
||||
this.sidenavs_.changes.subscribe(() => this.validateDrawers_());
|
||||
ObservableWrapper.subscribe(this.sidenavs_.changes, () => this.validateDrawers_());
|
||||
this.validateDrawers_();
|
||||
}
|
||||
|
||||
@@ -294,17 +291,17 @@ export class MdSidenavLayout implements AfterContentInit {
|
||||
}
|
||||
|
||||
// Ensure that we have at most one start and one end sidenav.
|
||||
this.sidenavs_.toArray().forEach(drawer => {
|
||||
if (drawer.align == 'end') {
|
||||
iterateListLike(this.sidenavs_, (sidenav: any) => {
|
||||
if (sidenav.align == 'end') {
|
||||
if (this.end_ != null) {
|
||||
throw new MdDuplicatedSidenavException('end');
|
||||
}
|
||||
this.end_ = drawer;
|
||||
this.end_ = sidenav;
|
||||
} else {
|
||||
if (this.start_ != null) {
|
||||
throw new MdDuplicatedSidenavException('start');
|
||||
}
|
||||
this.start_ = drawer;
|
||||
this.start_ = sidenav;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
* TODO(hansl): Implement this properly in Dart.
|
||||
*/
|
||||
class OneOf {
|
||||
const OneOf(List<string> values);
|
||||
const OneOf(List<String> values);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import "dart:html";
|
||||
|
||||
CssStyleDeclaration getComputedStyle(element, [String pseudoElement]) {
|
||||
return element.getComputedStyle(pseudoElement);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
export function getComputedStyle(element: HTMLElement, pseudoElt?: string) {
|
||||
return window.getComputedStyle(element, pseudoElt);
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
library testing.matchers;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:guinness/guinness.dart' as gns;
|
||||
|
||||
import 'package:angular2/src/platform/dom/dom_adapter.dart' show DOM;
|
||||
|
||||
import 'package:angular2/src/facade/lang.dart' show isString;
|
||||
|
||||
Expect expect(actual, [matcher]) {
|
||||
final expect = new Expect(actual);
|
||||
if (matcher != null) expect.to(matcher);
|
||||
return expect;
|
||||
}
|
||||
|
||||
const _u = const Object();
|
||||
|
||||
bool elementContainsStyle(element, styles) {
|
||||
var allPassed = true;
|
||||
if (isString(styles)) {
|
||||
allPassed = DOM.hasStyle(element, styles);
|
||||
} else {
|
||||
styles.forEach((prop, style) {
|
||||
allPassed = allPassed && DOM.hasStyle(element, prop, style);
|
||||
});
|
||||
}
|
||||
return allPassed;
|
||||
}
|
||||
|
||||
expectErrorMessage(actual, expectedMessage) {
|
||||
expect(actual.toString()).toContain(expectedMessage);
|
||||
}
|
||||
|
||||
expectException(Function actual, expectedMessage) {
|
||||
try {
|
||||
actual();
|
||||
} catch (e, s) {
|
||||
expectErrorMessage(e, expectedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
class Expect extends gns.Expect {
|
||||
Expect(actual) : super(actual);
|
||||
|
||||
NotExpect get not => new NotExpect(actual);
|
||||
|
||||
void toEqual(expected) => toHaveSameProps(expected);
|
||||
void toContainError(message) => expectErrorMessage(this.actual, message);
|
||||
void toThrowError([message = ""]) => toThrowWith(message: message);
|
||||
void toThrowErrorWith(message) => expectException(this.actual, message);
|
||||
void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future);
|
||||
void toHaveCssClass(className) =>
|
||||
gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className));
|
||||
void toHaveCssStyle(styles) {
|
||||
gns.guinness.matchers.toBeTrue(elementContainsStyle(actual, styles));
|
||||
}
|
||||
void toImplement(expected) => toBeA(expected);
|
||||
void toBeNaN() =>
|
||||
gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0);
|
||||
void toHaveText(expected) => _expect(elementText(actual), expected);
|
||||
void toHaveBeenCalledWith([a = _u, b = _u, c = _u, d = _u, e = _u, f = _u]) =>
|
||||
_expect(_argsMatch(actual, a, b, c, d, e, f), true,
|
||||
reason: 'method invoked with correct arguments');
|
||||
Function get _expect => gns.guinness.matchers.expect;
|
||||
|
||||
// TODO(tbosch): move this hack into Guinness
|
||||
_argsMatch(spyFn, [a0 = _u, a1 = _u, a2 = _u, a3 = _u, a4 = _u, a5 = _u]) {
|
||||
var calls = spyFn.calls;
|
||||
final toMatch = _takeDefined([a0, a1, a2, a3, a4, a5]);
|
||||
if (calls.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
gns.SamePropsMatcher matcher = new gns.SamePropsMatcher(toMatch);
|
||||
for (var i = 0; i < calls.length; i++) {
|
||||
var call = calls[i];
|
||||
// TODO: create a better error message, not just 'Expected: <true> Actual: <false>'.
|
||||
// For hacking this is good:
|
||||
// print(call.positionalArguments);
|
||||
if (matcher.matches(call.positionalArguments, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
List _takeDefined(List iter) => iter.takeWhile((_) => _ != _u).toList();
|
||||
}
|
||||
|
||||
class NotExpect extends gns.NotExpect {
|
||||
NotExpect(actual) : super(actual);
|
||||
|
||||
void toEqual(expected) => toHaveSameProps(expected);
|
||||
void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future);
|
||||
void toHaveCssClass(className) =>
|
||||
gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className));
|
||||
void toHaveCssStyle(styles) {
|
||||
gns.guinness.matchers.toBeFalse(elementContainsStyle(actual, styles));
|
||||
}
|
||||
void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null);
|
||||
Function get _expect => gns.guinness.matchers.expect;
|
||||
}
|
||||
|
||||
String elementText(n) {
|
||||
hasNodes(n) {
|
||||
var children = DOM.childNodes(n);
|
||||
return children != null && children.length > 0;
|
||||
}
|
||||
|
||||
if (n is Iterable) {
|
||||
return n.map(elementText).join("");
|
||||
}
|
||||
|
||||
if (DOM.isCommentNode(n)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (DOM.isElementNode(n) && DOM.tagName(n) == 'CONTENT') {
|
||||
return elementText(DOM.getDistributedNodes(n));
|
||||
}
|
||||
|
||||
if (DOM.hasShadowRoot(n)) {
|
||||
return elementText(DOM.childNodesAsList(DOM.getShadowRoot(n)));
|
||||
}
|
||||
|
||||
if (hasNodes(n)) {
|
||||
return elementText(DOM.childNodesAsList(n));
|
||||
}
|
||||
|
||||
return DOM.getText(n);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import {Injector, Provider, PLATFORM_INITIALIZER} from 'angular2/core';
|
||||
import {BaseException, ExceptionHandler} from 'angular2/src/facade/exceptions';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {FunctionWrapper, isPresent, Type} from 'angular2/src/facade/lang';
|
||||
|
||||
export class TestInjector {
|
||||
private _instantiated: boolean = false;
|
||||
|
||||
private _injector: Injector = null;
|
||||
|
||||
private _providers: Array<Type | Provider | any[]> = [];
|
||||
|
||||
reset() {
|
||||
this._injector = null;
|
||||
this._providers = [];
|
||||
this._instantiated = false;
|
||||
}
|
||||
|
||||
platformProviders: Array<Type | Provider | any[]> = [];
|
||||
|
||||
applicationProviders: Array<Type | Provider | any[]> = [];
|
||||
|
||||
addProviders(providers: Array<Type | Provider | any[]>) {
|
||||
if (this._instantiated) {
|
||||
throw new BaseException('Cannot add providers after test injector is instantiated');
|
||||
}
|
||||
this._providers = ListWrapper.concat(this._providers, providers);
|
||||
}
|
||||
|
||||
createInjector() {
|
||||
var rootInjector = Injector.resolveAndCreate(this.platformProviders);
|
||||
this._injector = rootInjector.resolveAndCreateChild(
|
||||
ListWrapper.concat(this.applicationProviders, this._providers));
|
||||
this._instantiated = true;
|
||||
return this._injector;
|
||||
}
|
||||
|
||||
execute(fn: FunctionWithParamTokens): any {
|
||||
if (!this._instantiated) {
|
||||
this.createInjector();
|
||||
}
|
||||
return fn.execute(this._injector);
|
||||
}
|
||||
}
|
||||
|
||||
var _testInjector: TestInjector = null;
|
||||
|
||||
export function getTestInjector() {
|
||||
if (_testInjector == null) {
|
||||
_testInjector = new TestInjector();
|
||||
}
|
||||
return _testInjector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the providers that the test injector should use. These should be providers
|
||||
* common to every test in the suite.
|
||||
*
|
||||
* This may only be called once, to set up the common providers for the current test
|
||||
* suite on teh current platform. If you absolutely need to change the providers,
|
||||
* first use `resetBaseTestProviders`.
|
||||
*
|
||||
* Test Providers for individual platforms are available from
|
||||
* 'angular2/platform/testing/<platform_name>'.
|
||||
*/
|
||||
export function setBaseTestProviders(platformProviders: Array<Type | Provider | any[]>,
|
||||
applicationProviders: Array<Type | Provider | any[]>) {
|
||||
var testInjector = getTestInjector();
|
||||
if (testInjector.platformProviders.length > 0 || testInjector.applicationProviders.length > 0) {
|
||||
throw new BaseException('Cannot set base providers because it has already been called');
|
||||
}
|
||||
testInjector.platformProviders = platformProviders;
|
||||
testInjector.applicationProviders = applicationProviders;
|
||||
var injector = testInjector.createInjector();
|
||||
let inits: Function[] = <Function[]>injector.getOptional(PLATFORM_INITIALIZER);
|
||||
if (isPresent(inits)) {
|
||||
inits.forEach(init => init());
|
||||
}
|
||||
testInjector.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the providers for the test injector.
|
||||
*/
|
||||
export function resetBaseTestProviders() {
|
||||
var testInjector = getTestInjector();
|
||||
testInjector.platformProviders = [];
|
||||
testInjector.applicationProviders = [];
|
||||
testInjector.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows injecting dependencies in `beforeEach()` and `it()`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* beforeEach(inject([Dependency, AClass], (dep, object) => {
|
||||
* // some code that uses `dep` and `object`
|
||||
* // ...
|
||||
* }));
|
||||
*
|
||||
* it('...', inject([AClass], (object) => {
|
||||
* object.doSomething();
|
||||
* expect(...);
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* Notes:
|
||||
* - 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: any[], fn: Function): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows injecting dependencies in `beforeEach()` and `it()`. The test must return
|
||||
* a promise which will resolve when all asynchronous activity is complete.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* it('...', injectAsync([AClass], (object) => {
|
||||
* return object.doSomething().then(() => {
|
||||
* expect(...);
|
||||
* });
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @param {Array} tokens
|
||||
* @param {Function} fn
|
||||
* @return {FunctionWithParamTokens}
|
||||
*/
|
||||
export function injectAsync(tokens: any[], fn: Function): FunctionWithParamTokens {
|
||||
return new FunctionWithParamTokens(tokens, fn, true);
|
||||
}
|
||||
|
||||
export class FunctionWithParamTokens {
|
||||
constructor(private _tokens: any[], private _fn: Function, public isAsync: boolean) {}
|
||||
|
||||
/**
|
||||
* Returns the value of the executed function.
|
||||
*/
|
||||
execute(injector: Injector): any {
|
||||
var params = this._tokens.map(t => injector.get(t));
|
||||
return FunctionWrapper.apply(this._fn, params);
|
||||
}
|
||||
|
||||
hasToken(token: any): boolean { return this._tokens.indexOf(token) > -1; }
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
library angular2.src.testing.testing_internal;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:guinness/guinness.dart' as gns;
|
||||
export 'package:guinness/guinness.dart'
|
||||
hide
|
||||
Expect,
|
||||
expect,
|
||||
NotExpect,
|
||||
beforeEach,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
SpyObject,
|
||||
SpyFunction;
|
||||
|
||||
export 'matchers.dart' show expect, Expect, NotExpect;
|
||||
|
||||
import 'package:angular2/src/core/reflection/reflection.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
|
||||
|
||||
import 'package:angular2/src/core/di/provider.dart' show bind;
|
||||
import 'package:angular2/src/facade/collection.dart' show StringMapWrapper;
|
||||
|
||||
import 'test_injector.dart';
|
||||
export 'test_injector.dart' show inject;
|
||||
|
||||
TestInjector _testInjector = getTestInjector();
|
||||
bool _isCurrentTestAsync;
|
||||
Future _currentTestFuture;
|
||||
bool _inIt = false;
|
||||
|
||||
class AsyncTestCompleter {
|
||||
final _completer = new Completer();
|
||||
|
||||
AsyncTestCompleter() {
|
||||
_currentTestFuture = this.future;
|
||||
}
|
||||
|
||||
void done() {
|
||||
_completer.complete();
|
||||
}
|
||||
|
||||
Future get future => _completer.future;
|
||||
}
|
||||
|
||||
void testSetup() {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
// beforeEach configuration:
|
||||
// - Priority 3: clear the bindings before each test,
|
||||
// - Priority 2: collect the bindings before each test, see beforeEachProviders(),
|
||||
// - Priority 1: create the test injector to be used in beforeEach() and it()
|
||||
|
||||
gns.beforeEach(() {
|
||||
_testInjector.reset();
|
||||
_currentTestFuture = null;
|
||||
}, priority: 3);
|
||||
|
||||
var completerProvider = 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;
|
||||
_testInjector.addProviders([completerProvider]);
|
||||
}, priority: 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows overriding default providers defined in test_injector.js.
|
||||
*
|
||||
* The given function must return a list of DI providers.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* beforeEachProviders(() => [
|
||||
* bind(Compiler).toClass(MockCompiler),
|
||||
* bind(SomeToken).toValue(myValue),
|
||||
* ]);
|
||||
*/
|
||||
void beforeEachProviders(Function fn) {
|
||||
gns.beforeEach(() {
|
||||
var providers = fn();
|
||||
if (providers != null) _testInjector.addProviders(providers);
|
||||
}, priority: 2);
|
||||
}
|
||||
|
||||
@Deprecated('using beforeEachProviders instead')
|
||||
void beforeEachBindings(Function fn) {
|
||||
beforeEachProviders(fn);
|
||||
}
|
||||
|
||||
void beforeEach(fn) {
|
||||
if (fn is! FunctionWithParamTokens) fn =
|
||||
new FunctionWithParamTokens([], fn, false);
|
||||
gns.beforeEach(() {
|
||||
_testInjector.execute(fn);
|
||||
});
|
||||
}
|
||||
|
||||
void _it(gnsFn, name, fn) {
|
||||
if (fn is! FunctionWithParamTokens) fn =
|
||||
new FunctionWithParamTokens([], fn, false);
|
||||
gnsFn(name, () {
|
||||
_inIt = true;
|
||||
_testInjector.execute(fn);
|
||||
_inIt = false;
|
||||
if (_isCurrentTestAsync) return _currentTestFuture;
|
||||
});
|
||||
}
|
||||
|
||||
void it(name, fn, [timeOut = null]) {
|
||||
_it(gns.it, name, fn);
|
||||
}
|
||||
|
||||
void iit(name, fn, [timeOut = null]) {
|
||||
_it(gns.iit, name, fn);
|
||||
}
|
||||
|
||||
void xit(name, fn, [timeOut = null]) {
|
||||
_it(gns.xit, name, fn);
|
||||
}
|
||||
|
||||
class SpyFunction extends gns.SpyFunction {
|
||||
SpyFunction(String name) : super(name);
|
||||
|
||||
// TODO: vsavkin move to guinness
|
||||
andReturn(value) {
|
||||
return andCallFake(([a0, a1, a2, a3, a4, a5]) => value);
|
||||
}
|
||||
}
|
||||
|
||||
class SpyObject extends gns.SpyObject {
|
||||
final Map<String, SpyFunction> _spyFuncs = {};
|
||||
|
||||
SpyObject([arg]) {}
|
||||
|
||||
SpyFunction spy(String funcName) =>
|
||||
_spyFuncs.putIfAbsent(funcName, () => new SpyFunction(funcName));
|
||||
|
||||
void prop(String funcName, value) {
|
||||
_spyFuncs
|
||||
.putIfAbsent("get:${funcName}", () => new SpyFunction(funcName))
|
||||
.andReturn(value);
|
||||
}
|
||||
|
||||
static stub([object = null, config = null, overrides = null]) {
|
||||
if (object is! SpyObject) {
|
||||
overrides = config;
|
||||
config = object;
|
||||
object = new SpyObject();
|
||||
}
|
||||
|
||||
var m = StringMapWrapper.merge(config, overrides);
|
||||
StringMapWrapper.forEach(m, (value, key) {
|
||||
object.spy(key).andReturn(value);
|
||||
});
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
bool isInInnerZone() => Zone.current['_innerZone'] == true;
|
||||
@@ -0,0 +1,8 @@
|
||||
export {
|
||||
it,
|
||||
iit,
|
||||
describe,
|
||||
ddescribe,
|
||||
expect,
|
||||
beforeEach,
|
||||
} from 'angular2/testing';
|
||||
@@ -1,4 +1,5 @@
|
||||
import {Directive, HostBinding, EventEmitter, Output, Input} from 'angular2/core';
|
||||
import {EventEmitter} from 'angular2/src/facade/async';
|
||||
import {Directive, HostBinding, Output, Input} from 'angular2/core';
|
||||
import {OneOf} from "../../core/annotations/one-of";
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user