feat(refactor): replaced ObservablePipe and PromisePipe with AsyncPipe
This commit is contained in:
parent
bd498977bd
commit
106a28b8dc
|
@ -4,10 +4,9 @@
|
||||||
* This module provides advanced support for extending change detection.
|
* This module provides advanced support for extending change detection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {PromisePipe} from './src/change_detection/pipes/promise_pipe';
|
|
||||||
export {UpperCasePipe} from './src/change_detection/pipes/uppercase_pipe';
|
export {UpperCasePipe} from './src/change_detection/pipes/uppercase_pipe';
|
||||||
export {LowerCasePipe} from './src/change_detection/pipes/lowercase_pipe';
|
export {LowerCasePipe} from './src/change_detection/pipes/lowercase_pipe';
|
||||||
export {ObservablePipe} from './src/change_detection/pipes/observable_pipe';
|
export {AsyncPipe} from './src/change_detection/pipes/async_pipe';
|
||||||
export {JsonPipe} from './src/change_detection/pipes/json_pipe';
|
export {JsonPipe} from './src/change_detection/pipes/json_pipe';
|
||||||
export {DatePipe} from './src/change_detection/pipes/date_pipe';
|
export {DatePipe} from './src/change_detection/pipes/date_pipe';
|
||||||
export {DecimalPipe, PercentPipe, CurrencyPipe} from './src/change_detection/pipes/number_pipe';
|
export {DecimalPipe, PercentPipe, CurrencyPipe} from './src/change_detection/pipes/number_pipe';
|
||||||
|
|
|
@ -7,8 +7,7 @@ import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs
|
||||||
import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
|
import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
|
||||||
import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||||
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
|
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
|
||||||
import {ObservablePipeFactory} from './pipes/observable_pipe';
|
import {AsyncPipeFactory} from './pipes/async_pipe';
|
||||||
import {PromisePipeFactory} from './pipes/promise_pipe';
|
|
||||||
import {UpperCasePipe} from './pipes/uppercase_pipe';
|
import {UpperCasePipe} from './pipes/uppercase_pipe';
|
||||||
import {LowerCasePipe} from './pipes/lowercase_pipe';
|
import {LowerCasePipe} from './pipes/lowercase_pipe';
|
||||||
import {JsonPipe} from './pipes/json_pipe';
|
import {JsonPipe} from './pipes/json_pipe';
|
||||||
|
@ -75,11 +74,8 @@ export const iterableDiff: IterableDifferFactory[] =
|
||||||
/**
|
/**
|
||||||
* Async binding to such types as Observable.
|
* Async binding to such types as Observable.
|
||||||
*/
|
*/
|
||||||
export const async: List<PipeFactory> = CONST_EXPR([
|
export const async: List<PipeFactory> =
|
||||||
CONST_EXPR(new ObservablePipeFactory()),
|
CONST_EXPR([CONST_EXPR(new AsyncPipeFactory()), CONST_EXPR(new NullPipeFactory())]);
|
||||||
CONST_EXPR(new PromisePipeFactory()),
|
|
||||||
CONST_EXPR(new NullPipeFactory())
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uppercase text transform.
|
* Uppercase text transform.
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
import {isBlank, isPresent, isPromise, CONST, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
import {Observable, Promise, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {Pipe, WrappedValue, PipeFactory} from './pipe';
|
||||||
|
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||||
|
|
||||||
|
|
||||||
|
class ObservableStrategy {
|
||||||
|
createSubscription(async: any, updateLatestValue: any): any {
|
||||||
|
return ObservableWrapper.subscribe(async, updateLatestValue, e => { throw e; });
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(subscription: any): void { ObservableWrapper.dispose(subscription); }
|
||||||
|
|
||||||
|
onDestroy(subscription: any): void { ObservableWrapper.dispose(subscription); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class PromiseStrategy {
|
||||||
|
createSubscription(async: any, updateLatestValue: any): any {
|
||||||
|
return async.then(updateLatestValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(subscription: any): void {}
|
||||||
|
|
||||||
|
onDestroy(subscription: any): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _promiseStrategy = new PromiseStrategy();
|
||||||
|
var _observableStrategy = new ObservableStrategy();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements async bindings to Observable and Promise.
|
||||||
|
*
|
||||||
|
* # Example
|
||||||
|
*
|
||||||
|
* In this example we bind the description observable to the DOM. The async pipe will convert an
|
||||||
|
*observable to the
|
||||||
|
* latest value it emitted. It will also request a change detection check when a new value is
|
||||||
|
*emitted.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @Component({
|
||||||
|
* selector: "task-cmp",
|
||||||
|
* changeDetection: ON_PUSH
|
||||||
|
* })
|
||||||
|
* @View({
|
||||||
|
* template: "Task Description {{ description | async }}"
|
||||||
|
* })
|
||||||
|
* class Task {
|
||||||
|
* description:Observable<string>;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class AsyncPipe implements Pipe {
|
||||||
|
_latestValue: Object = null;
|
||||||
|
_latestReturnedValue: Object = null;
|
||||||
|
|
||||||
|
_subscription: Object = null;
|
||||||
|
_obj: Observable | Promise<any> = null;
|
||||||
|
private _strategy: any = null;
|
||||||
|
|
||||||
|
constructor(public _ref: ChangeDetectorRef) {}
|
||||||
|
|
||||||
|
supports(obj: any): boolean { return true; }
|
||||||
|
|
||||||
|
onDestroy(): void {
|
||||||
|
if (isPresent(this._subscription)) {
|
||||||
|
this._dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform(obj: Observable | Promise<any>, args?: any[]): any {
|
||||||
|
if (isBlank(this._obj)) {
|
||||||
|
if (isPresent(obj)) {
|
||||||
|
this._subscribe(obj);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj !== this._obj) {
|
||||||
|
this._dispose();
|
||||||
|
return this.transform(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._latestValue === this._latestReturnedValue) {
|
||||||
|
return this._latestReturnedValue;
|
||||||
|
} else {
|
||||||
|
this._latestReturnedValue = this._latestValue;
|
||||||
|
return WrappedValue.wrap(this._latestValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribe(obj: Observable | Promise<any>): void {
|
||||||
|
this._obj = obj;
|
||||||
|
this._strategy = this._selectStrategy(obj);
|
||||||
|
this._subscription =
|
||||||
|
this._strategy.createSubscription(obj, value => this._updateLatestValue(obj, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectStrategy(obj: Observable | Promise<any>) {
|
||||||
|
if (isPromise(obj)) {
|
||||||
|
return _promiseStrategy;
|
||||||
|
} else if (ObservableWrapper.isObservable(obj)) {
|
||||||
|
return _observableStrategy;
|
||||||
|
} else {
|
||||||
|
throw new BaseException(`Async pipe does not support object '${obj}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dispose(): void {
|
||||||
|
this._strategy.dispose(this._subscription);
|
||||||
|
this._latestValue = null;
|
||||||
|
this._latestReturnedValue = null;
|
||||||
|
this._subscription = null;
|
||||||
|
this._obj = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateLatestValue(async: any, value: Object) {
|
||||||
|
if (async === this._obj) {
|
||||||
|
this._latestValue = value;
|
||||||
|
this._ref.requestCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a factory for [AsyncPipe].
|
||||||
|
*/
|
||||||
|
@CONST()
|
||||||
|
export class AsyncPipeFactory implements PipeFactory {
|
||||||
|
supports(obj: any): boolean { return true; }
|
||||||
|
create(cdRef: ChangeDetectorRef): Pipe { return new AsyncPipe(cdRef); }
|
||||||
|
}
|
|
@ -1,94 +0,0 @@
|
||||||
import {Observable, ObservableWrapper} from 'angular2/src/facade/async';
|
|
||||||
import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
|
|
||||||
import {Pipe, WrappedValue, PipeFactory} from './pipe';
|
|
||||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements async bindings to Observable.
|
|
||||||
*
|
|
||||||
* # Example
|
|
||||||
*
|
|
||||||
* In this example we bind the description observable to the DOM. The async pipe will convert an
|
|
||||||
*observable to the
|
|
||||||
* latest value it emitted. It will also request a change detection check when a new value is
|
|
||||||
*emitted.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* @Component({
|
|
||||||
* selector: "task-cmp",
|
|
||||||
* changeDetection: ON_PUSH
|
|
||||||
* })
|
|
||||||
* @View({
|
|
||||||
* template: "Task Description {{ description | async }}"
|
|
||||||
* })
|
|
||||||
* class Task {
|
|
||||||
* description:Observable<string>;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export class ObservablePipe implements Pipe {
|
|
||||||
_latestValue: Object = null;
|
|
||||||
_latestReturnedValue: Object = null;
|
|
||||||
|
|
||||||
_subscription: Object = null;
|
|
||||||
_observable: Observable = null;
|
|
||||||
|
|
||||||
constructor(public _ref: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
supports(obs: any): boolean { return ObservableWrapper.isObservable(obs); }
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
if (isPresent(this._subscription)) {
|
|
||||||
this._dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transform(obs: Observable, args: List<any> = null): any {
|
|
||||||
if (isBlank(this._subscription)) {
|
|
||||||
this._subscribe(obs);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obs !== this._observable) {
|
|
||||||
this._dispose();
|
|
||||||
return this.transform(obs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._latestValue === this._latestReturnedValue) {
|
|
||||||
return this._latestReturnedValue;
|
|
||||||
} else {
|
|
||||||
this._latestReturnedValue = this._latestValue;
|
|
||||||
return WrappedValue.wrap(this._latestValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribe(obs: Observable): void {
|
|
||||||
this._observable = obs;
|
|
||||||
this._subscription = ObservableWrapper.subscribe(obs, value => this._updateLatestValue(value),
|
|
||||||
e => { throw e; });
|
|
||||||
}
|
|
||||||
|
|
||||||
_dispose(): void {
|
|
||||||
ObservableWrapper.dispose(this._subscription);
|
|
||||||
this._latestValue = null;
|
|
||||||
this._latestReturnedValue = null;
|
|
||||||
this._subscription = null;
|
|
||||||
this._observable = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateLatestValue(value: Object) {
|
|
||||||
this._latestValue = value;
|
|
||||||
this._ref.requestCheck();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a factory for [ObervablePipe].
|
|
||||||
*/
|
|
||||||
@CONST()
|
|
||||||
export class ObservablePipeFactory implements PipeFactory {
|
|
||||||
supports(obs: any): boolean { return ObservableWrapper.isObservable(obs); }
|
|
||||||
|
|
||||||
create(cdRef: ChangeDetectorRef): Pipe { return new ObservablePipe(cdRef); }
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
|
||||||
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
|
|
||||||
import {Pipe, PipeFactory, WrappedValue} from './pipe';
|
|
||||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements async bindings to Promise.
|
|
||||||
*
|
|
||||||
* # Example
|
|
||||||
*
|
|
||||||
* In this example we bind the description promise to the DOM.
|
|
||||||
* The async pipe will convert a promise to the value with which it is resolved. It will also
|
|
||||||
* request a change detection check when the promise is resolved.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* @Component({
|
|
||||||
* selector: "task-cmp",
|
|
||||||
* changeDetection: ON_PUSH
|
|
||||||
* })
|
|
||||||
* @View({
|
|
||||||
* template: "Task Description {{ description | async }}"
|
|
||||||
* })
|
|
||||||
* class Task {
|
|
||||||
* description:Promise<string>;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export class PromisePipe implements Pipe {
|
|
||||||
_latestValue: Object = null;
|
|
||||||
_latestReturnedValue: Object = null;
|
|
||||||
_sourcePromise: Promise<any>;
|
|
||||||
|
|
||||||
constructor(public _ref: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
supports(promise: any): boolean { return isPromise(promise); }
|
|
||||||
|
|
||||||
onDestroy(): void {
|
|
||||||
if (isPresent(this._sourcePromise)) {
|
|
||||||
this._latestValue = null;
|
|
||||||
this._latestReturnedValue = null;
|
|
||||||
this._sourcePromise = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transform(promise: Promise<any>, args: List<any> = null): any {
|
|
||||||
if (isBlank(this._sourcePromise)) {
|
|
||||||
this._sourcePromise = promise;
|
|
||||||
promise.then((val) => {
|
|
||||||
if (this._sourcePromise === promise) {
|
|
||||||
this._updateLatestValue(val);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promise !== this._sourcePromise) {
|
|
||||||
this._sourcePromise = null;
|
|
||||||
return this.transform(promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._latestValue === this._latestReturnedValue) {
|
|
||||||
return this._latestReturnedValue;
|
|
||||||
} else {
|
|
||||||
this._latestReturnedValue = this._latestValue;
|
|
||||||
return WrappedValue.wrap(this._latestValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateLatestValue(value: Object) {
|
|
||||||
this._latestValue = value;
|
|
||||||
this._ref.requestCheck();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a factory for [PromisePipe].
|
|
||||||
*/
|
|
||||||
@CONST()
|
|
||||||
export class PromisePipeFactory implements PipeFactory {
|
|
||||||
supports(promise: any): boolean { return isPromise(promise); }
|
|
||||||
|
|
||||||
create(cdRef: ChangeDetectorRef): Pipe { return new PromisePipe(cdRef); }
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
ChangeDetector,
|
ChangeDetector,
|
||||||
|
ChangeDetectorRef,
|
||||||
ProtoChangeDetector,
|
ProtoChangeDetector,
|
||||||
DynamicChangeDetector
|
DynamicChangeDetector
|
||||||
} from 'angular2/src/change_detection/change_detection';
|
} from 'angular2/src/change_detection/change_detection';
|
||||||
|
@ -26,3 +27,7 @@ export class SpyPipeFactory extends SpyObject {}
|
||||||
export class SpyDependencyProvider extends SpyObject {}
|
export class SpyDependencyProvider extends SpyObject {}
|
||||||
|
|
||||||
export class SpyIterableDifferFactory extends SpyObject {}
|
export class SpyIterableDifferFactory extends SpyObject {}
|
||||||
|
|
||||||
|
export class SpyChangeDetectorRef extends SpyObject {
|
||||||
|
constructor() { super(ChangeDetectorRef); }
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
import {
|
||||||
|
ddescribe,
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
iit,
|
||||||
|
xit,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
AsyncTestCompleter,
|
||||||
|
SpyChangeDetectorRef,
|
||||||
|
inject,
|
||||||
|
SpyObject
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
import {WrappedValue} from 'angular2/src/change_detection/pipes/pipe';
|
||||||
|
import {AsyncPipe} from 'angular2/src/change_detection/pipes/async_pipe';
|
||||||
|
import {
|
||||||
|
EventEmitter,
|
||||||
|
ObservableWrapper,
|
||||||
|
PromiseWrapper,
|
||||||
|
TimerWrapper
|
||||||
|
} from 'angular2/src/facade/async';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe("AsyncPipe", () => {
|
||||||
|
|
||||||
|
describe('Observable', () => {
|
||||||
|
var emitter;
|
||||||
|
var pipe;
|
||||||
|
var ref;
|
||||||
|
var message = new Object();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
emitter = new EventEmitter();
|
||||||
|
ref = new SpyChangeDetectorRef();
|
||||||
|
pipe = new AsyncPipe(ref);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("transform", () => {
|
||||||
|
it("should return null when subscribing to an observable",
|
||||||
|
() => { expect(pipe.transform(emitter)).toBe(null); });
|
||||||
|
|
||||||
|
it("should return the latest available value wrapped",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(emitter)).toEqual(new WrappedValue(message));
|
||||||
|
async.done();
|
||||||
|
}, 0)
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it("should return same value when nothing has changed since the last call",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
expect(pipe.transform(emitter)).toBe(message);
|
||||||
|
async.done();
|
||||||
|
}, 0)
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should dispose of the existing subscription when subscribing to a new observable",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
|
||||||
|
var newEmitter = new EventEmitter();
|
||||||
|
expect(pipe.transform(newEmitter)).toBe(null);
|
||||||
|
|
||||||
|
// this should not affect the pipe
|
||||||
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(newEmitter)).toBe(null);
|
||||||
|
async.done();
|
||||||
|
}, 0)
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should request a change detection check upon receiving a new value",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(ref.spy('requestCheck')).toHaveBeenCalled();
|
||||||
|
async.done();
|
||||||
|
}, 0)
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("onDestroy", () => {
|
||||||
|
it("should do nothing when no subscription",
|
||||||
|
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
||||||
|
|
||||||
|
it("should dispose of the existing subscription", inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(emitter);
|
||||||
|
pipe.onDestroy();
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(emitter)).toBe(null);
|
||||||
|
async.done();
|
||||||
|
}, 0)
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Promise", () => {
|
||||||
|
var message = new Object();
|
||||||
|
var pipe;
|
||||||
|
var completer;
|
||||||
|
var ref;
|
||||||
|
// adds longer timers for passing tests in IE
|
||||||
|
var timer = (!isBlank(DOM) && DOM.getUserAgent().indexOf("Trident") > -1) ? 50 : 0;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
completer = PromiseWrapper.completer();
|
||||||
|
ref = new SpyChangeDetectorRef();
|
||||||
|
pipe = new AsyncPipe(ref);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("transform", () => {
|
||||||
|
it("should return null when subscribing to a promise",
|
||||||
|
() => { expect(pipe.transform(completer.promise)).toBe(null); });
|
||||||
|
|
||||||
|
it("should return the latest available value", inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
|
||||||
|
completer.resolve(message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
||||||
|
async.done();
|
||||||
|
}, timer)
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should return unwrapped value when nothing has changed since the last call",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
completer.resolve(message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
expect(pipe.transform(completer.promise)).toBe(message);
|
||||||
|
async.done();
|
||||||
|
}, timer)
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should dispose of the existing subscription when subscribing to a new promise",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
|
||||||
|
var newCompleter = PromiseWrapper.completer();
|
||||||
|
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
||||||
|
|
||||||
|
// this should not affect the pipe, so it should return WrappedValue
|
||||||
|
completer.resolve(message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
||||||
|
async.done();
|
||||||
|
}, timer)
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should request a change detection check upon receiving a new value",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
completer.resolve(message);
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(ref.spy('requestCheck')).toHaveBeenCalled();
|
||||||
|
async.done();
|
||||||
|
}, timer)
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("onDestroy", () => {
|
||||||
|
it("should do nothing when no source",
|
||||||
|
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
||||||
|
|
||||||
|
it("should dispose of the existing source", inject([AsyncTestCompleter], (async) => {
|
||||||
|
pipe.transform(completer.promise);
|
||||||
|
expect(pipe.transform(completer.promise)).toBe(null);
|
||||||
|
completer.resolve(message)
|
||||||
|
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(() => {
|
||||||
|
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
||||||
|
pipe.onDestroy();
|
||||||
|
expect(pipe.transform(completer.promise)).toBe(null);
|
||||||
|
async.done();
|
||||||
|
}, timer);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('null', () => {
|
||||||
|
it('should return null when given null', () => {
|
||||||
|
var pipe = new AsyncPipe(null);
|
||||||
|
expect(pipe.transform(null, [])).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('other types', () => {
|
||||||
|
it('should throw when given an invalid object', () => {
|
||||||
|
var pipe = new AsyncPipe(null);
|
||||||
|
expect(() => pipe.transform(<any>"some bogus object", [])).toThrowError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,125 +0,0 @@
|
||||||
import {
|
|
||||||
ddescribe,
|
|
||||||
describe,
|
|
||||||
it,
|
|
||||||
iit,
|
|
||||||
xit,
|
|
||||||
expect,
|
|
||||||
beforeEach,
|
|
||||||
afterEach,
|
|
||||||
AsyncTestCompleter,
|
|
||||||
inject,
|
|
||||||
proxy,
|
|
||||||
SpyObject
|
|
||||||
} from 'angular2/test_lib';
|
|
||||||
|
|
||||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
|
||||||
import {WrappedValue} from 'angular2/src/change_detection/pipes/pipe';
|
|
||||||
import {ObservablePipe} from 'angular2/src/change_detection/pipes/observable_pipe';
|
|
||||||
import {ChangeDetectorRef} from 'angular2/src/change_detection/change_detector_ref';
|
|
||||||
import {EventEmitter, ObservableWrapper, TimerWrapper} from 'angular2/src/facade/async';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
describe("ObservablePipe", () => {
|
|
||||||
var emitter;
|
|
||||||
var pipe;
|
|
||||||
var ref;
|
|
||||||
var message = new Object();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
emitter = new EventEmitter();
|
|
||||||
ref = new SpyChangeDetectorRef();
|
|
||||||
pipe = new ObservablePipe(ref);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("supports", () => {
|
|
||||||
it("should support observables", () => { expect(pipe.supports(emitter)).toBe(true); });
|
|
||||||
|
|
||||||
it("should not support other objects", () => {
|
|
||||||
expect(pipe.supports("string")).toBe(false);
|
|
||||||
expect(pipe.supports(null)).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("transform", () => {
|
|
||||||
it("should return null when subscribing to an observable",
|
|
||||||
() => { expect(pipe.transform(emitter)).toBe(null); });
|
|
||||||
|
|
||||||
it("should return the latest available value wrapped",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(emitter)).toEqual(new WrappedValue(message));
|
|
||||||
async.done();
|
|
||||||
}, 0)
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it("should return same value when nothing has changed since the last call",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
expect(pipe.transform(emitter)).toBe(message);
|
|
||||||
async.done();
|
|
||||||
}, 0)
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("should dispose of the existing subscription when subscribing to a new observable",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
|
|
||||||
var newEmitter = new EventEmitter();
|
|
||||||
expect(pipe.transform(newEmitter)).toBe(null);
|
|
||||||
|
|
||||||
// this should not affect the pipe
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(newEmitter)).toBe(null);
|
|
||||||
async.done();
|
|
||||||
}, 0)
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("should request a change detection check upon receiving a new value",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(ref.spy('requestCheck')).toHaveBeenCalled();
|
|
||||||
async.done();
|
|
||||||
}, 0)
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("onDestroy", () => {
|
|
||||||
it("should do nothing when no subscription",
|
|
||||||
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
|
||||||
|
|
||||||
it("should dispose of the existing subscription", inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(emitter);
|
|
||||||
pipe.onDestroy();
|
|
||||||
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(emitter)).toBe(null);
|
|
||||||
async.done();
|
|
||||||
}, 0)
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(ChangeDetectorRef)
|
|
||||||
class SpyChangeDetectorRef extends SpyObject {
|
|
||||||
constructor() { super(ChangeDetectorRef); }
|
|
||||||
noSuchMethod(m) { return super.noSuchMethod(m) }
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
import {
|
|
||||||
ddescribe,
|
|
||||||
describe,
|
|
||||||
it,
|
|
||||||
iit,
|
|
||||||
xit,
|
|
||||||
expect,
|
|
||||||
beforeEach,
|
|
||||||
afterEach,
|
|
||||||
AsyncTestCompleter,
|
|
||||||
inject,
|
|
||||||
proxy,
|
|
||||||
SpyObject
|
|
||||||
} from 'angular2/test_lib';
|
|
||||||
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
|
||||||
import {PromisePipe} from 'angular2/src/change_detection/pipes/promise_pipe';
|
|
||||||
import {WrappedValue} from 'angular2/src/change_detection/pipes/pipe';
|
|
||||||
import {ChangeDetectorRef} from 'angular2/src/change_detection/change_detector_ref';
|
|
||||||
import {PromiseWrapper, TimerWrapper} from 'angular2/src/facade/async';
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
describe("PromisePipe", () => {
|
|
||||||
var message = new Object();
|
|
||||||
var pipe;
|
|
||||||
var completer;
|
|
||||||
var ref;
|
|
||||||
// adds longer timers for passing tests in IE
|
|
||||||
var timer = (!isBlank(DOM) && DOM.getUserAgent().indexOf("Trident") > -1) ? 50 : 0;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
completer = PromiseWrapper.completer();
|
|
||||||
ref = new SpyChangeDetectorRef();
|
|
||||||
pipe = new PromisePipe(ref);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("supports", () => {
|
|
||||||
it("should support promises", () => { expect(pipe.supports(completer.promise)).toBe(true); });
|
|
||||||
|
|
||||||
it("should not support other objects", () => {
|
|
||||||
expect(pipe.supports("string")).toBe(false);
|
|
||||||
expect(pipe.supports(null)).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("transform", () => {
|
|
||||||
it("should return null when subscribing to a promise",
|
|
||||||
() => { expect(pipe.transform(completer.promise)).toBe(null); });
|
|
||||||
|
|
||||||
it("should return the latest available value", inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
|
|
||||||
completer.resolve(message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
|
||||||
async.done();
|
|
||||||
}, timer)
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("should return unwrapped value when nothing has changed since the last call",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
completer.resolve(message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
expect(pipe.transform(completer.promise)).toBe(message);
|
|
||||||
async.done();
|
|
||||||
}, timer)
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("should dispose of the existing subscription when subscribing to a new promise",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
|
|
||||||
var newCompleter = PromiseWrapper.completer();
|
|
||||||
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
|
||||||
|
|
||||||
// this should not affect the pipe, so it should return WrappedValue
|
|
||||||
completer.resolve(message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
|
||||||
async.done();
|
|
||||||
}, timer)
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("should request a change detection check upon receiving a new value",
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
completer.resolve(message);
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(ref.spy('requestCheck')).toHaveBeenCalled();
|
|
||||||
async.done();
|
|
||||||
}, timer)
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("onDestroy", () => {
|
|
||||||
it("should do nothing when no source",
|
|
||||||
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
|
||||||
|
|
||||||
it("should dispose of the existing source", inject([AsyncTestCompleter], (async) => {
|
|
||||||
pipe.transform(completer.promise);
|
|
||||||
expect(pipe.transform(completer.promise)).toBe(null);
|
|
||||||
completer.resolve(message)
|
|
||||||
|
|
||||||
|
|
||||||
TimerWrapper.setTimeout(() => {
|
|
||||||
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
|
||||||
pipe.onDestroy();
|
|
||||||
expect(pipe.transform(completer.promise)).toBe(null);
|
|
||||||
async.done();
|
|
||||||
}, timer);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(ChangeDetectorRef)
|
|
||||||
class SpyChangeDetectorRef extends SpyObject {
|
|
||||||
constructor() { super(ChangeDetectorRef); }
|
|
||||||
noSuchMethod(m) { return super.noSuchMethod(m) }
|
|
||||||
}
|
|
Loading…
Reference in New Issue