Home Manual Reference Source Test Repository

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/package/Rx');
var groupBy_1 = require('../../dist/package/operators/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