spec-js/operators/groupBy-spec.js
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var chai_1 = require('chai');
var Rx = require('../../dist/cjs/Rx');
var groupBy_1 = require('../../dist/cjs/operator/groupBy');
var Observable = Rx.Observable;
var ReplaySubject = Rx.ReplaySubject;
/** @test {groupBy} */
describe('Observable.prototype.groupBy', function () {
asDiagram('groupBy(i => i % 2)')('should group numbers by odd/even', function () {
var e1 = hot('--1---2---3---4---5---|');
var expected = '--x---y---------------|';
var x = cold('1-------3-------5---|');
var y = cold('2-------4-------|');
var expectedValues = { x: x, y: y };
var source = e1
.groupBy(function (val) { return parseInt(val) % 2; });
expectObservable(source).toBe(expected, expectedValues);
});
function reverseString(str) {
return str.split('').reverse().join('');
}
function mapObject(obj, fn) {
var out = {};
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
out[p] = fn(obj[p]);
}
}
return out;
}
it('should group values', function (done) {
var expectedGroups = [
{ key: 1, values: [1, 3] },
{ key: 0, values: [2] }
];
Observable.of(1, 2, 3)
.groupBy(function (x) { return x % 2; })
.subscribe(function (g) {
var expectedGroup = expectedGroups.shift();
chai_1.expect(g.key).to.equal(expectedGroup.key);
g.subscribe(function (x) {
chai_1.expect(x).to.deep.equal(expectedGroup.values.shift());
});
}, null, done);
});
it('should group values with an element selector', function (done) {
var expectedGroups = [
{ key: 1, values: ['1!', '3!'] },
{ key: 0, values: ['2!'] }
];
Observable.of(1, 2, 3)
.groupBy(function (x) { return x % 2; }, function (x) { return x + '!'; })
.subscribe(function (g) {
var expectedGroup = expectedGroups.shift();
chai_1.expect(g.key).to.equal(expectedGroup.key);
g.subscribe(function (x) {
chai_1.expect(x).to.deep.equal(expectedGroup.values.shift());
});
}, null, done);
});
it('should group values with a duration selector', function () {
var expectedGroups = [
{ key: 1, values: [1, 3] },
{ key: 0, values: [2, 4] },
{ key: 1, values: [5] },
{ key: 0, values: [6] }
];
var resultingGroups = [];
Observable.of(1, 2, 3, 4, 5, 6)
.groupBy(function (x) { return x % 2; }, function (x) { return x; }, function (g) { return g.skip(1); })
.subscribe(function (g) {
var group = { key: g.key, values: [] };
g.subscribe(function (x) {
group.values.push(x);
});
resultingGroups.push(group);
});
chai_1.expect(resultingGroups).to.deep.equal(expectedGroups);
});
it('should group values with a subject selector', function (done) {
var expectedGroups = [
{ key: 1, values: [3] },
{ key: 0, values: [2] }
];
Observable.of(1, 2, 3)
.groupBy(function (x) { return x % 2; }, null, null, function () { return new ReplaySubject(1); })
.delay(5)
.subscribe(function (g) {
var expectedGroup = expectedGroups.shift();
chai_1.expect(g.key).to.equal(expectedGroup.key);
g.subscribe(function (x) {
chai_1.expect(x).to.deep.equal(expectedGroup.values.shift());
});
}, null, done);
});
it('should handle an empty Observable', function () {
var e1 = cold('|');
var e1subs = '(^!)';
var expected = '|';
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should handle a never Observable', function () {
var e1 = cold('-');
var e1subs = '^';
var expected = '-';
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should handle a just-throw Observable', function () {
var e1 = cold('#');
var e1subs = '(^!)';
var expected = '#';
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should handle an Observable with a single value', function () {
var values = { a: ' foo' };
var e1 = hot('^--a--|', values);
var e1subs = '^ !';
var expected = '---g--|';
var g = cold('a--|', values);
var expectedValues = { g: g };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------------|';
var w = cold('a-b---d---------i-----l-|', values);
var x = cold('c-------g-h---------|', values);
var y = cold('e---------j-k---|', values);
var z = cold('f-------------|', values);
var expectedValues = { w: w, x: x, y: y, z: z };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should emit GroupObservables', function () {
var values = {
a: ' foo',
b: ' FoO '
};
var e1 = hot('-1--2--^-a-b----|', values);
var e1subs = '^ !';
var expected = '--g------|';
var expectedValues = { g: 'foo' };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.do(function (group) {
chai_1.expect(group.key).to.equal('foo');
chai_1.expect(group instanceof groupBy_1.GroupedObservable).to.be.true;
})
.map(function (group) { return group.key; });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector, assert GroupSubject key', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------------|';
var expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.map(function (g) { return g.key; });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector, but outer throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------------#';
var expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.map(function (g) { return g.key; });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector, inners propagate error from outer', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------------#';
var w = cold('a-b---d---------i-----l-#', values);
var x = cold('c-------g-h---------#', values);
var y = cold('e---------j-k---#', values);
var z = cold('f-------------#', values);
var expectedValues = { w: w, x: x, y: y, z: z };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow outer to be unsubscribed early', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var unsub = ' !';
var e1subs = '^ !';
var expected = '--w---x---y-';
var expectedValues = { w: 'foo', x: 'bar', y: 'baz' };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.map(function (group) { return group.key; });
expectObservable(source, unsub).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should unsubscribe from the source when the outer and inner subscriptions are disposed', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--(a|)';
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.take(1)
.mergeMap(function (group) { return group.take(1); });
expectObservable(source).toBe(expected, values);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should not break unsubscription chain when unsubscribed explicitly', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--w---x---y-';
var unsub = ' !';
var expectedValues = { w: 'foo', x: 'bar', y: 'baz' };
var source = e1
.mergeMap(function (x) { return Observable.of(x); })
.groupBy(function (x) { return x.toLowerCase().trim(); })
.mergeMap(function (group) { return Observable.of(group.key); });
expectObservable(source, unsub).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector which eventually throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------#';
var w = cold('a-b---d---------i-#', values);
var x = cold('c-------g-h---#', values);
var y = cold('e---------#', values);
var z = cold('f-------#', values);
var expectedValues = { w: w, x: x, y: y, z: z };
var invoked = 0;
var source = e1
.groupBy(function (val) {
invoked++;
if (invoked === 10) {
throw 'error';
}
return val.toLowerCase().trim();
});
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should group values with a keySelector and elementSelector, ' +
'but elementSelector throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var reversedValues = mapObject(values, reverseString);
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--w---x---y-z-------#';
var w = cold('a-b---d---------i-#', reversedValues);
var x = cold('c-------g-h---#', reversedValues);
var y = cold('e---------#', reversedValues);
var z = cold('f-------#', reversedValues);
var expectedValues = { w: w, x: x, y: y, z: z };
var invoked = 0;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) {
invoked++;
if (invoked === 10) {
throw 'error';
}
return reverseString(val);
});
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow the outer to be unsubscribed early but inners continue', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var unsub = ' !';
var expected = '--w---x---';
var w = cold('a-b---d---------i-----l-|', values);
var x = cold('c-------g-h---------|', values);
var expectedValues = { w: w, x: x };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); });
expectObservable(source, unsub).toBe(expected, expectedValues);
});
it('should allow an inner to be unsubscribed early but other inners continue', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var expected = '--w---x---y-z-------------|';
var w = '--a-b---d-';
var unsubw = ' !';
var x = '------c-------g-h---------|';
var y = '----------e---------j-k---|';
var z = '------------f-------------|';
var expectedGroups = {
w: Rx.TestScheduler.parseMarbles(w, values),
x: Rx.TestScheduler.parseMarbles(x, values),
y: Rx.TestScheduler.parseMarbles(y, values),
z: Rx.TestScheduler.parseMarbles(z, values)
};
var fooUnsubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(unsubw)
.unsubscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.map(function (group) {
var arr = [];
var subscription = group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
}).subscribe(function (value) {
arr.push(value);
});
if (group.key === 'foo') {
rxTestScheduler.schedule(function () {
subscription.unsubscribe();
}, fooUnsubscriptionFrame - rxTestScheduler.frame);
}
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
});
it('should allow inners to be unsubscribed early at different times', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var expected = '--w---x---y-z-------------|';
var w = '--a-b---d-';
var unsubw = ' !';
var x = '------c------';
var unsubx = ' !';
var y = '----------e------';
var unsuby = ' !';
var z = '------------f-------';
var unsubz = ' !';
var expectedGroups = {
w: Rx.TestScheduler.parseMarbles(w, values),
x: Rx.TestScheduler.parseMarbles(x, values),
y: Rx.TestScheduler.parseMarbles(y, values),
z: Rx.TestScheduler.parseMarbles(z, values)
};
var unsubscriptionFrames = {
foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame,
bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame,
baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame,
qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame
};
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.map(function (group) {
var arr = [];
var subscription = group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
}).subscribe(function (value) {
arr.push(value);
});
rxTestScheduler.schedule(function () {
subscription.unsubscribe();
}, unsubscriptionFrames[group.key] - rxTestScheduler.frame);
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
});
it('should allow subscribing late to an inner Observable, outer completes', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('--a-b---d---------i-----l-|', values);
var subs = '^ !';
var expected = '----------------------------|';
e1.groupBy(function (val) { return val.toLowerCase().trim(); })
.subscribe(function (group) {
rxTestScheduler.schedule(function () {
expectObservable(group).toBe(expected);
}, 260);
});
expectSubscriptions(e1.subscriptions).toBe(subs);
});
it('should allow subscribing late to an inner Observable, outer throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('--a-b---d---------i-----l-#', values);
var subs = '^ !';
var expected = '----------------------------#';
e1.groupBy(function (val) { return val.toLowerCase().trim(); })
.subscribe(function (group) {
rxTestScheduler.schedule(function () {
expectObservable(group).toBe(expected);
}, 260);
}, function () {
//noop
});
expectSubscriptions(e1.subscriptions).toBe(subs);
});
it('should allow subscribing late to inner, unsubscribe outer early', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('--a-b---d---------i-----l-#', values);
var unsub = ' !';
var e1subs = '^ !';
var expectedOuter = '--w----------';
var expectedInner = '-------------';
var outerValues = { w: 'foo' };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); })
.do(function (group) {
rxTestScheduler.schedule(function () {
expectObservable(group).toBe(expectedInner);
}, 260);
})
.map(function (group) { return group.key; });
expectObservable(source, unsub).toBe(expectedOuter, outerValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow using a keySelector, elementSelector, and durationSelector', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var reversedValues = mapObject(values, reverseString);
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--v---w---x-y-----z-------|';
var v = cold('a-b---(d|)', reversedValues);
var w = cold('c-------g-(h|)', reversedValues);
var x = cold('e---------j-(k|)', reversedValues);
var y = cold('f-------------|', reversedValues);
var z = cold('i-----l-|', reversedValues);
var expectedValues = { v: v, w: w, x: x, y: y, z: z };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return reverseString(val); }, function (group) { return group.skip(2); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow using a keySelector, elementSelector, and durationSelector that throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var reversedValues = mapObject(values, reverseString);
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var expected = '--v---w---x-y-----z-------|';
var v = cold('a-b---(d#)', reversedValues);
var w = cold('c-------g-(h#)', reversedValues);
var x = cold('e---------j-(k#)', reversedValues);
var y = cold('f-------------|', reversedValues);
var z = cold('i-----l-|', reversedValues);
var expectedValues = { v: v, w: w, x: x, y: y, z: z };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return reverseString(val); }, function (group) { return group.skip(2).map(function () { throw 'error'; }); });
expectObservable(source).toBe(expected, expectedValues);
});
it('should allow using a keySelector and a durationSelector, outer throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values);
var e1subs = '^ !';
var expected = '--v---w---x-y-----z-------#';
var v = cold('a-b---(d|)', values);
var w = cold('c-------g-(h|)', values);
var x = cold('e---------j-(k|)', values);
var y = cold('f-------------#', values);
var z = cold('i-----l-#', values);
var expectedValues = { v: v, w: w, x: x, y: y, z: z };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(2); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow using a durationSelector, and outer unsubscribed early', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var unsub = ' !';
var expected = '--v---w---x-';
var v = cold('a-b---(d|)', values);
var w = cold('c-------g-(h|)', values);
var x = cold('e---------j-(k|)', values);
var expectedValues = { v: v, w: w, x: x };
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(2); });
expectObservable(source, unsub).toBe(expected, expectedValues);
});
it('should allow using a durationSelector, outer and all inners unsubscribed early', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var unsub = ' !';
var expected = '--v---w---x-';
var v = '--a-b---(d|)';
var w = '------c-----';
var x = '----------e-';
var expectedGroups = {
v: Rx.TestScheduler.parseMarbles(v, values),
w: Rx.TestScheduler.parseMarbles(w, values),
x: Rx.TestScheduler.parseMarbles(x, values)
};
var unsubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(unsub)
.unsubscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(2); })
.map(function (group) {
var arr = [];
var subscription = group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
rxTestScheduler.schedule(function () {
subscription.unsubscribe();
}, unsubscriptionFrame - rxTestScheduler.frame);
return arr;
});
expectObservable(source, unsub).toBe(expected, expectedGroups);
});
it('should dispose a durationSelector after closing the group', function () {
var obs = hot('-0-1--------2-|');
var sub = '^ !';
var unsubs = [
'-^--!',
'---^--!',
'------------^-!',
];
var dur = '---s';
var durations = [
cold(dur),
cold(dur),
cold(dur)
];
var unsubscribedFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(sub)
.unsubscribedFrame;
obs.groupBy(function (val) { return val; }, function (val) { return val; }, function (group) { return durations[group.key]; }).subscribe();
rxTestScheduler.schedule(function () {
durations.forEach(function (d, i) {
expectSubscriptions(d.subscriptions).toBe(unsubs[i]);
});
}, unsubscribedFrame);
});
it('should allow using a durationSelector, but keySelector throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--v---w---x-y-----z-#';
var v = cold('a-b---(d|)', values);
var w = cold('c-------g-(h|)', values);
var x = cold('e---------#', values);
var y = cold('f-------#', values);
var z = cold('i-#', values);
var expectedValues = { v: v, w: w, x: x, y: y, z: z };
var invoked = 0;
var source = e1
.groupBy(function (val) {
invoked++;
if (invoked === 10) {
throw 'error';
}
return val.toLowerCase().trim();
}, function (val) { return val; }, function (group) { return group.skip(2); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow using a durationSelector, but elementSelector throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ ! ';
var expected = '--v---w---x-y-----z-# ';
var v = cold('a-b---(d|) ', values);
var w = cold('c-------g-(h|) ', values);
var x = cold('e---------# ', values);
var y = cold('f-------# ', values);
var z = cold('i-# ', values);
var expectedValues = { v: v, w: w, x: x, y: y, z: z };
var invoked = 0;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) {
invoked++;
if (invoked === 10) {
throw 'error';
}
return val;
}, function (group) { return group.skip(2); });
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow using a durationSelector which eventually throws', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ ! ';
var expected = '--v---w---x-(y#) ';
var v = cold('a-b---(d|) ', values);
var w = cold('c-----# ', values);
var x = cold('e-# ', values);
var y = cold('# ', values);
var expectedValues = { v: v, w: w, x: x, y: y };
var invoked = 0;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) {
invoked++;
if (invoked === 4) {
throw 'error';
}
return group.skip(2);
});
expectObservable(source).toBe(expected, expectedValues);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow an inner to be unsubscribed early but other inners continue, ' +
'with durationSelector', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var reversedValues = mapObject(values, reverseString);
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--v---w---x-y-----z-------|';
var v = '--a-b---';
var unsubv = ' !';
var w = '------c-------g-(h|)';
var x = '----------e---------j-(k|)';
var y = '------------f-------------|';
var z = '------------------i-----l-|';
var expectedGroups = {
v: Rx.TestScheduler.parseMarbles(v, reversedValues),
w: Rx.TestScheduler.parseMarbles(w, reversedValues),
x: Rx.TestScheduler.parseMarbles(x, reversedValues),
y: Rx.TestScheduler.parseMarbles(y, reversedValues),
z: Rx.TestScheduler.parseMarbles(z, reversedValues)
};
var fooUnsubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(unsubv)
.unsubscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return reverseString(val); }, function (group) { return group.skip(2); })
.map(function (group, index) {
var arr = [];
var subscription = group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
if (group.key === 'foo' && index === 0) {
rxTestScheduler.schedule(function () {
subscription.unsubscribe();
}, fooUnsubscriptionFrame - rxTestScheduler.frame);
}
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should allow inners to be unsubscribed early at different times, with durationSelector', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values);
var e1subs = '^ !';
var expected = '--v---w---x-y-----z-------|';
var v = '--a-b---';
var unsubv = ' !';
var w = '------c---';
var unsubw = ' !';
var x = '----------e---------j-';
var unsubx = ' !';
var y = '------------f----';
var unsuby = ' !';
var z = '------------------i----';
var unsubz = ' !';
var expectedGroups = {
v: Rx.TestScheduler.parseMarbles(v, values),
w: Rx.TestScheduler.parseMarbles(w, values),
x: Rx.TestScheduler.parseMarbles(x, values),
y: Rx.TestScheduler.parseMarbles(y, values),
z: Rx.TestScheduler.parseMarbles(z, values)
};
var unsubscriptionFrames = {
foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubv).unsubscribedFrame,
bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame,
baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame,
qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame,
foo2: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame
};
var hasUnsubscribed = {};
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(2); })
.map(function (group) {
var arr = [];
var subscription = group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
var unsubscriptionFrame = hasUnsubscribed[group.key] ?
unsubscriptionFrames[group.key + '2'] :
unsubscriptionFrames[group.key];
rxTestScheduler.schedule(function () {
subscription.unsubscribe();
hasUnsubscribed[group.key] = true;
}, unsubscriptionFrame - rxTestScheduler.frame);
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should return inners that when subscribed late exhibit hot behavior', function () {
var values = {
a: ' foo',
b: ' FoO ',
c: 'baR ',
d: 'foO ',
e: ' Baz ',
f: ' qux ',
g: ' bar',
h: ' BAR ',
i: 'FOO ',
j: 'baz ',
k: ' bAZ ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-| ', values);
var e1subs = '^ ! ';
var expected = '--v---w---x-y-------------| ';
var subv = ' ^ '; // foo
var v = ' --b---d---------i-----l-| '; // foo
var subw = ' ^ '; // bar
var w = ' --------g-h---------| '; // bar
var subx = ' ^ '; // baz
var x = ' ----------j-k---| '; // baz
var suby = ' ^'; // qux
var y = ' ------------------|'; // qux
var expectedGroups = {
v: Rx.TestScheduler.parseMarbles(v, values),
w: Rx.TestScheduler.parseMarbles(w, values),
x: Rx.TestScheduler.parseMarbles(x, values),
y: Rx.TestScheduler.parseMarbles(y, values),
};
var subscriptionFrames = {
foo: Rx.TestScheduler.parseMarblesAsSubscriptions(subv).subscribedFrame,
bar: Rx.TestScheduler.parseMarblesAsSubscriptions(subw).subscribedFrame,
baz: Rx.TestScheduler.parseMarblesAsSubscriptions(subx).subscribedFrame,
qux: Rx.TestScheduler.parseMarblesAsSubscriptions(suby).subscribedFrame,
};
var result = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }).map(function (group) {
var innerNotifications = [];
var subscriptionFrame = subscriptionFrames[group.key];
rxTestScheduler.schedule(function () {
group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
innerNotifications.push(value);
});
}, subscriptionFrame - rxTestScheduler.frame);
return innerNotifications;
});
expectObservable(result).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should return inner group that when subscribed late emits complete()', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b---d---------i-----l-|', values);
var e1subs = '^ !';
var expected = '--g-----------------------|';
var innerSub = ' ^';
var g = '--------------------------------|';
var expectedGroups = {
g: Rx.TestScheduler.parseMarbles(g, values)
};
var innerSubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(innerSub)
.subscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(7); })
.map(function (group) {
var arr = [];
rxTestScheduler.schedule(function () {
group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
}, innerSubscriptionFrame - rxTestScheduler.frame);
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should return inner group that when subscribed late emits error()', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b---d---------i-----l-#', values);
var e1subs = '^ !';
var expected = '--g-----------------------#';
var innerSub = ' ^';
var g = '--------------------------------#';
var expectedGroups = {
g: Rx.TestScheduler.parseMarbles(g, values)
};
var innerSubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(innerSub)
.subscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(7); })
.map(function (group) {
var arr = [];
rxTestScheduler.schedule(function () {
group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
}, innerSubscriptionFrame - rxTestScheduler.frame);
return arr;
});
expectObservable(source).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(e1subs);
});
it('should return inner that does not throw when faulty outer is unsubscribed early', function () {
var values = {
a: ' foo',
b: ' FoO ',
d: 'foO ',
i: 'FOO ',
l: ' fOo '
};
var e1 = hot('-1--2--^-a-b---d---------i-----l-#', values);
var unsub = ' !';
var expectedSubs = '^ !';
var expected = '--g----';
var innerSub = ' ^';
var g = '-';
var expectedGroups = {
g: Rx.TestScheduler.parseMarbles(g, values)
};
var innerSubscriptionFrame = Rx.TestScheduler
.parseMarblesAsSubscriptions(innerSub)
.subscribedFrame;
var source = e1
.groupBy(function (val) { return val.toLowerCase().trim(); }, function (val) { return val; }, function (group) { return group.skip(7); })
.map(function (group) {
var arr = [];
rxTestScheduler.schedule(function () {
group
.materialize()
.map(function (notification) {
return { frame: rxTestScheduler.frame, notification: notification };
})
.subscribe(function (value) {
arr.push(value);
});
}, innerSubscriptionFrame - rxTestScheduler.frame);
return arr;
});
expectObservable(source, unsub).toBe(expected, expectedGroups);
expectSubscriptions(e1.subscriptions).toBe(expectedSubs);
});
it('should not break lift() composability', function (done) {
var MyCustomObservable = (function (_super) {
__extends(MyCustomObservable, _super);
function MyCustomObservable() {
_super.apply(this, arguments);
}
MyCustomObservable.prototype.lift = function (operator) {
var observable = new MyCustomObservable();
observable.source = this;
observable.operator = operator;
return observable;
};
return MyCustomObservable;
}(Rx.Observable));
var result = new MyCustomObservable(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
}).groupBy(function (x) { return x % 2; }, function (x) { return x + '!'; });
chai_1.expect(result instanceof MyCustomObservable).to.be.true;
var expectedGroups = [
{ key: 1, values: ['1!', '3!'] },
{ key: 0, values: ['2!'] }
];
result
.subscribe(function (g) {
var expectedGroup = expectedGroups.shift();
chai_1.expect(g.key).to.equal(expectedGroup.key);
g.subscribe(function (x) {
chai_1.expect(x).to.deep.equal(expectedGroup.values.shift());
});
}, function (x) {
done(new Error('should not be called'));
}, function () {
done();
});
});
});
//# sourceMappingURL=groupBy-spec.js.map