feat(pipe): added the Pipe decorator and the pipe property to View
BREAKING CHANGE:
Instead of configuring pipes via a Pipes object, now you can configure them by providing the pipes property to the View decorator.
@Pipe({
name: 'double'
})
class DoublePipe {
transform(value, args) { return value * 2; }
}
@View({
template: '{{ 10 | double}}'
pipes: [DoublePipe]
})
class CustomComponent {}
Closes #3572
This commit is contained in:
@@ -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/change_detection';
|
||||
import {AsyncPipe} from 'angular2/pipes';
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {DatePipe} from 'angular2/pipes';
|
||||
import {DateWrapper} from 'angular2/src/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe("DatePipe", () => {
|
||||
var date;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
date = DateWrapper.create(2015, 6, 15, 21, 43, 11);
|
||||
pipe = new DatePipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support date", () => { expect(pipe.supports(date)).toBe(true); });
|
||||
it("should support int", () => { expect(pipe.supports(123456789)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it('should format each component correctly', () => {
|
||||
expect(pipe.transform(date, ['y'])).toEqual('2015');
|
||||
expect(pipe.transform(date, ['yy'])).toEqual('15');
|
||||
expect(pipe.transform(date, ['M'])).toEqual('6');
|
||||
expect(pipe.transform(date, ['MM'])).toEqual('06');
|
||||
expect(pipe.transform(date, ['MMM'])).toEqual('Jun');
|
||||
expect(pipe.transform(date, ['MMMM'])).toEqual('June');
|
||||
expect(pipe.transform(date, ['d'])).toEqual('15');
|
||||
expect(pipe.transform(date, ['E'])).toEqual('Mon');
|
||||
expect(pipe.transform(date, ['EEEE'])).toEqual('Monday');
|
||||
expect(pipe.transform(date, ['H'])).toEqual('21');
|
||||
expect(pipe.transform(date, ['j'])).toEqual('9 PM');
|
||||
expect(pipe.transform(date, ['m'])).toEqual('43');
|
||||
expect(pipe.transform(date, ['s'])).toEqual('11');
|
||||
});
|
||||
|
||||
it('should format common multi component patterns', () => {
|
||||
expect(pipe.transform(date, ['yMEd'])).toEqual('Mon, 6/15/2015');
|
||||
expect(pipe.transform(date, ['MEd'])).toEqual('Mon, 6/15');
|
||||
expect(pipe.transform(date, ['MMMd'])).toEqual('Jun 15');
|
||||
expect(pipe.transform(date, ['yMMMMEEEEd'])).toEqual('Monday, June 15, 2015');
|
||||
expect(pipe.transform(date, ['jms'])).toEqual('9:43:11 PM');
|
||||
expect(pipe.transform(date, ['ms'])).toEqual('43:11');
|
||||
});
|
||||
|
||||
it('should format with pattern aliases', () => {
|
||||
expect(pipe.transform(date, ['medium'])).toEqual('Jun 15, 2015, 9:43:11 PM');
|
||||
expect(pipe.transform(date, ['short'])).toEqual('6/15/2015, 9:43 PM');
|
||||
expect(pipe.transform(date, ['fullDate'])).toEqual('Monday, June 15, 2015');
|
||||
expect(pipe.transform(date, ['longDate'])).toEqual('June 15, 2015');
|
||||
expect(pipe.transform(date, ['mediumDate'])).toEqual('Jun 15, 2015');
|
||||
expect(pipe.transform(date, ['shortDate'])).toEqual('6/15/2015');
|
||||
expect(pipe.transform(date, ['mediumTime'])).toEqual('9:43:11 PM');
|
||||
expect(pipe.transform(date, ['shortTime'])).toEqual('9:43 PM');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
proxy,
|
||||
SpyObject,
|
||||
IS_DARTIUM
|
||||
} from 'angular2/test_lib';
|
||||
import {Json, RegExp, NumberWrapper, StringWrapper} from 'angular2/src/facade/lang';
|
||||
|
||||
import {JsonPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("JsonPipe", () => {
|
||||
var regNewLine = '\n';
|
||||
var inceptionObj;
|
||||
var inceptionObjString;
|
||||
var pipe;
|
||||
var collection: number[];
|
||||
|
||||
function normalize(obj: string): string { return StringWrapper.replace(obj, regNewLine, ''); }
|
||||
|
||||
beforeEach(() => {
|
||||
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
|
||||
inceptionObjString = "{\n" + " \"dream\": {\n" + " \"dream\": {\n" +
|
||||
" \"dream\": \"Limbo\"\n" + " }\n" + " }\n" + "}";
|
||||
|
||||
|
||||
pipe = new JsonPipe();
|
||||
collection = [];
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return JSON-formatted string",
|
||||
() => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); });
|
||||
|
||||
it("should return JSON-formatted string even when normalized", () => {
|
||||
var dream1 = normalize(pipe.transform(inceptionObj));
|
||||
var dream2 = normalize(inceptionObjString);
|
||||
expect(dream1).toEqual(dream2);
|
||||
});
|
||||
|
||||
it("should return JSON-formatted string similar to Json.stringify", () => {
|
||||
var dream1 = normalize(pipe.transform(inceptionObj));
|
||||
var dream2 = normalize(Json.stringify(inceptionObj));
|
||||
expect(dream1).toEqual(dream2);
|
||||
});
|
||||
|
||||
it("should return same ref when nothing has changed since the last call", () => {
|
||||
expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString);
|
||||
expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString);
|
||||
});
|
||||
|
||||
|
||||
it("should return a new value when something changed but the ref hasn't", () => {
|
||||
var stringCollection = '[]';
|
||||
var stringCollectionWith1 = '[\n' +
|
||||
' 1' +
|
||||
'\n]';
|
||||
|
||||
expect(pipe.transform(collection)).toEqual(stringCollection);
|
||||
|
||||
collection.push(1);
|
||||
|
||||
expect(pipe.transform(collection)).toEqual(stringCollectionWith1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("onDestroy", () => {
|
||||
it("should do nothing when no latest value",
|
||||
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {LimitToPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("LimitToPipe", () => {
|
||||
var list;
|
||||
var str;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
list = [1, 2, 3, 4, 5];
|
||||
str = 'tuvwxyz';
|
||||
pipe = new LimitToPipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support strings", () => { expect(pipe.supports(str)).toBe(true); });
|
||||
it("should support lists", () => { expect(pipe.supports(list)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it('should return the first X items when X is positive', () => {
|
||||
expect(pipe.transform(list, [3])).toEqual([1, 2, 3]);
|
||||
expect(pipe.transform(str, [3])).toEqual('tuv');
|
||||
});
|
||||
|
||||
it('should return the last X items when X is negative', () => {
|
||||
expect(pipe.transform(list, [-3])).toEqual([3, 4, 5]);
|
||||
expect(pipe.transform(str, [-3])).toEqual('xyz');
|
||||
});
|
||||
|
||||
it('should return a copy of input array if X is exceeds array length', () => {
|
||||
expect(pipe.transform(list, [20])).toEqual(list);
|
||||
expect(pipe.transform(list, [-20])).toEqual(list);
|
||||
});
|
||||
|
||||
it('should return the entire string if X exceeds input length', () => {
|
||||
expect(pipe.transform(str, [20])).toEqual(str);
|
||||
expect(pipe.transform(str, [-20])).toEqual(str);
|
||||
});
|
||||
|
||||
it('should not modify the input list', () => {
|
||||
expect(pipe.transform(list, [3])).toEqual([1, 2, 3]);
|
||||
expect(list).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {LowerCasePipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("LowerCasePipe", () => {
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new LowerCasePipe();
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return lowercase", () => {
|
||||
var val = pipe.transform(upper);
|
||||
expect(val).toEqual(lower);
|
||||
});
|
||||
|
||||
it("should lowercase when there is a new value", () => {
|
||||
var val = pipe.transform(upper);
|
||||
expect(val).toEqual(lower);
|
||||
var val2 = pipe.transform('WAT');
|
||||
expect(val2).toEqual('wat');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {DecimalPipe, PercentPipe, CurrencyPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("DecimalPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new DecimalPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(12345, [])).toEqual('12,345');
|
||||
expect(pipe.transform(123, ['.2'])).toEqual('123.00');
|
||||
expect(pipe.transform(1, ['3.'])).toEqual('001');
|
||||
expect(pipe.transform(1.1, ['3.4-5'])).toEqual('001.1000');
|
||||
|
||||
expect(pipe.transform(1.123456, ['3.4-5'])).toEqual('001.12346');
|
||||
expect(pipe.transform(1.1234, [])).toEqual('1.123');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe("PercentPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new PercentPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(1.23, [])).toEqual('123%');
|
||||
expect(pipe.transform(1.2, ['.2'])).toEqual('120.00%');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe("CurrencyPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new CurrencyPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(123, [])).toEqual('USD123');
|
||||
expect(pipe.transform(12, ['EUR', false, '.2'])).toEqual('EUR12.00');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {UpperCasePipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("UpperCasePipe", () => {
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new UpperCasePipe();
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it("should return uppercase", () => {
|
||||
var val = pipe.transform(lower);
|
||||
expect(val).toEqual(upper);
|
||||
});
|
||||
|
||||
it("should uppercase when there is a new value", () => {
|
||||
var val = pipe.transform(lower);
|
||||
expect(val).toEqual(upper);
|
||||
var val2 = pipe.transform('wat');
|
||||
expect(val2).toEqual('WAT');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user