spec-js/operators/filter-spec.js
"use strict";
var chai_1 = require('chai');
var Rx = require('../../dist/package/Rx');
var Observable = Rx.Observable;
/** @test {filter} */
describe('Observable.prototype.filter', function () {
function oddFilter(x) {
return (+x) % 2 === 1;
}
function isPrime(i) {
if (+i <= 1) {
return false;
}
var max = Math.floor(Math.sqrt(+i));
for (var j = 2; j <= max; ++j) {
if (+i % j === 0) {
return false;
}
}
return true;
}
asDiagram('filter(x => x % 2 === 1)')('should filter out even values', function () {
var source = hot('--0--1--2--3--4--|');
var subs = '^ !';
var expected = '-----1-----3-----|';
expectObservable(source.filter(oddFilter)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ !';
var expected = '--3---5----7-------|';
expectObservable(source.filter(isPrime)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter with an always-true predicate', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '--3-4-5-6--7-8--9--|';
var predicate = function () { return true; };
expectObservable(source.filter(predicate)).toBe(expected);
});
it('should filter with an always-false predicate', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '-------------------|';
var predicate = function () { return false; };
expectObservable(source.filter(predicate)).toBe(expected);
});
it('should filter in only prime numbers, source unsubscribes early', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ ! ';
var unsub = ' ! ';
var expected = '--3---5----7- ';
expectObservable(source.filter(isPrime), unsub).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers, source throws', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--#');
var subs = '^ !';
var expected = '--3---5----7-------#';
expectObservable(source.filter(isPrime)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers, but predicate throws', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ ! ';
var expected = '--3---5-# ';
var invoked = 0;
function predicate(x, index) {
invoked++;
if (invoked === 4) {
throw 'error';
}
return isPrime(x);
}
;
expectObservable(source.filter(predicate)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers, predicate with index', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ !';
var expected = '--3--------7-------|';
function predicate(x, i) {
return isPrime((+x) + i * 10);
}
expectObservable(source.filter(predicate)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should invoke predicate once for each checked value', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '--3---5----7-------|';
var invoked = 0;
var predicate = function (x) {
invoked++;
return isPrime(x);
};
var r = source
.filter(predicate)
.do(null, null, function () {
chai_1.expect(invoked).to.equal(7);
});
expectObservable(r).toBe(expected);
});
it('should filter in only prime numbers, predicate with index, ' +
'source unsubscribes early', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ ! ';
var unsub = ' ! ';
var expected = '--3--------7- ';
function predicate(x, i) {
return isPrime((+x) + i * 10);
}
expectObservable(source.filter(predicate), unsub).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers, predicate with index, source throws', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--#');
var subs = '^ !';
var expected = '--3--------7-------#';
function predicate(x, i) {
return isPrime((+x) + i * 10);
}
expectObservable(source.filter(predicate)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should filter in only prime numbers, predicate with index and throws', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ ! ';
var expected = '--3-----# ';
var invoked = 0;
function predicate(x, i) {
invoked++;
if (invoked === 4) {
throw 'error';
}
return isPrime((+x) + i * 10);
}
;
expectObservable(source.filter(predicate)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should compose with another filter to allow multiples of six', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '--------6----------|';
expectObservable(source
.filter(function (x) { return x % 2 === 0; })
.filter(function (x) { return x % 3 === 0; })).toBe(expected);
});
it('should be able to accept and use a thisArg', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '--------6----------|';
function Filterer() {
this.filter1 = function (x) { return x % 2 === 0; };
this.filter2 = function (x) { return x % 3 === 0; };
}
var filterer = new Filterer();
expectObservable(source
.filter(function (x) { return this.filter1(x); }, filterer)
.filter(function (x) { return this.filter2(x); }, filterer)
.filter(function (x) { return this.filter1(x); }, filterer)).toBe(expected);
});
it('should be able to use filter and map composed', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var expected = '----a---b----c-----|';
var values = { a: 16, b: 36, c: 64 };
expectObservable(source
.filter(function (x) { return x % 2 === 0; })
.map(function (x) { return x * x; })).toBe(expected, values);
});
it('should propagate errors from the source', function () {
var source = hot('--0--1--2--3--4--#');
var subs = '^ !';
var expected = '-----1-----3-----#';
expectObservable(source.filter(oddFilter)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should support Observable.empty', function () {
var source = cold('|');
var subs = '(^!)';
var expected = '|';
expectObservable(source.filter(oddFilter)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should support Observable.never', function () {
var source = cold('-');
var subs = '^';
var expected = '-';
expectObservable(source.filter(oddFilter)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should support Observable.throw', function () {
var source = cold('#');
var subs = '(^!)';
var expected = '#';
expectObservable(source.filter(oddFilter)).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should send errors down the error path', function (done) {
Observable.of(42).filter((function (x, index) {
throw 'bad';
}))
.subscribe(function (x) {
done(new Error('should not be called'));
}, function (err) {
chai_1.expect(err).to.equal('bad');
done();
}, function () {
done(new Error('should not be called'));
});
});
it('should not break unsubscription chain when unsubscribed explicitly', function () {
var source = hot('-1--2--^-3-4-5-6--7-8--9--|');
var subs = '^ ! ';
var unsub = ' ! ';
var expected = '--3---5----7- ';
var r = source
.mergeMap(function (x) { return Observable.of(x); })
.filter(isPrime)
.mergeMap(function (x) { return Observable.of(x); });
expectObservable(r, unsub).toBe(expected);
expectSubscriptions(source.subscriptions).toBe(subs);
});
it('should support type guards without breaking previous behavior', function () {
// tslint:disable no-unused-variable
// type guards with interfaces and classes
{
var Foo = (function () {
function Foo(bar, baz) {
if (bar === void 0) { bar = 'name'; }
if (baz === void 0) { baz = 42; }
this.bar = bar;
this.baz = baz;
}
return Foo;
}());
var isBar = function (x) { return x && x.bar !== undefined; };
var isBaz = function (x) { return x && x.baz !== undefined; };
var foo = new Foo();
Observable.of(foo).filter(function (foo) { return foo.baz === 42; })
.subscribe(function (x) { return x.baz; }); // x is still Foo
Observable.of(foo).filter(isBar)
.subscribe(function (x) { return x.bar; }); // x is Bar!
var foobar = new Foo(); // type is interface, not the class
Observable.of(foobar).filter(function (foobar) { return foobar.bar === 'name'; })
.subscribe(function (x) { return x.bar; }); // <-- x is still Bar
Observable.of(foobar).filter(isBar)
.subscribe(function (x) { return x.bar; }); // <--- x is Bar!
var barish = { bar: 'quack', baz: 42 }; // type can quack like a Bar
Observable.of(barish).filter(function (x) { return x.bar === 'quack'; })
.subscribe(function (x) { return x.bar; }); // x is still { bar: string; baz: number; }
Observable.of(barish).filter(isBar)
.subscribe(function (bar) { return bar.bar; }); // x is Bar!
}
// type guards with primitive types
{
var xs = Observable.from([1, 'aaa', 3, 'bb']);
// This type guard will narrow a `string | number` to a string in the examples below
var isString = function (x) { return typeof x === 'string'; };
xs.filter(isString)
.subscribe(function (s) { return s.length; }); // s is string
// In contrast, this type of regular boolean predicate still maintains the original type
xs.filter(function (x) { return typeof x === 'number'; })
.subscribe(function (x) { return x; }); // x is still string | number
xs.filter(function (x, i) { return typeof x === 'number' && x > i; })
.subscribe(function (x) { return x; }); // x is still string | number
}
// tslint:disable enable
});
});
//# sourceMappingURL=filter-spec.js.map