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.
|
||||
*/
|
||||
|
||||
export {PromisePipe} from './src/change_detection/pipes/promise_pipe';
|
||||
export {UpperCasePipe} from './src/change_detection/pipes/uppercase_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 {DatePipe} from './src/change_detection/pipes/date_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 {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
|
||||
import {ObservablePipeFactory} from './pipes/observable_pipe';
|
||||
import {PromisePipeFactory} from './pipes/promise_pipe';
|
||||
import {AsyncPipeFactory} from './pipes/async_pipe';
|
||||
import {UpperCasePipe} from './pipes/uppercase_pipe';
|
||||
import {LowerCasePipe} from './pipes/lowercase_pipe';
|
||||
import {JsonPipe} from './pipes/json_pipe';
|
||||
|
@ -75,11 +74,8 @@ export const iterableDiff: IterableDifferFactory[] =
|
|||
/**
|
||||
* Async binding to such types as Observable.
|
||||
*/
|
||||
export const async: List<PipeFactory> = CONST_EXPR([
|
||||
CONST_EXPR(new ObservablePipeFactory()),
|
||||
CONST_EXPR(new PromisePipeFactory()),
|
||||
CONST_EXPR(new NullPipeFactory())
|
||||
]);
|
||||
export const async: List<PipeFactory> =
|
||||
CONST_EXPR([CONST_EXPR(new AsyncPipeFactory()), CONST_EXPR(new NullPipeFactory())]);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ChangeDetector,
|
||||
ChangeDetectorRef,
|
||||
ProtoChangeDetector,
|
||||
DynamicChangeDetector
|
||||
} from 'angular2/src/change_detection/change_detection';
|
||||
|
@ -26,3 +27,7 @@ export class SpyPipeFactory extends SpyObject {}
|
|||
export class SpyDependencyProvider 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