Skip to content

Commit b66592d

Browse files
adrianomelobenlesh
authored andcommitted
fix(buffer): change behavior of buffer to more closely match RxJS 4
The behavior of buffer operator was different from RxJS 4. This patch changes the behavior of buffer and adds tests from RxJS 4 and tests with never, empty and error.
1 parent 3d833f3 commit b66592d

File tree

2 files changed

+122
-28
lines changed

2 files changed

+122
-28
lines changed

spec/operators/buffer-spec.js

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,112 @@
11
/* globals describe, it, expect, expectObservable, hot */
22
var Rx = require('../../dist/cjs/Rx');
3+
var Observable = Rx.Observable;
34

45
describe('Observable.prototype.buffer', function () {
6+
it('should work with empty and empty selector', function () {
7+
var a = Observable.empty();
8+
var b = Observable.empty();
9+
var expected = '|';
10+
expectObservable(a.buffer(b)).toBe(expected);
11+
});
12+
it('should work with empty and non-empty selector', function () {
13+
var a = Observable.empty();
14+
var b = hot('-----a-----');
15+
var expected = '|';
16+
expectObservable(a.buffer(b)).toBe(expected);
17+
});
18+
it('should work with non-empty and empty selector', function () {
19+
var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|');
20+
var b = Observable.empty();
21+
var expected = '|';
22+
expectObservable(a.buffer(b)).toBe(expected);
23+
});
24+
it('should work with never and never selector', function () {
25+
var a = Observable.never();
26+
var b = Observable.never();
27+
var expected = '-';
28+
expectObservable(a.buffer(b)).toBe(expected);
29+
});
30+
it('should work with never and empty selector', function () {
31+
var a = Observable.never();
32+
var b = Observable.empty();
33+
var expected = '|';
34+
expectObservable(a.buffer(b)).toBe(expected);
35+
});
36+
it('should work with empty and never selector', function () {
37+
var a = Observable.empty();
38+
var b = Observable.never();
39+
var expected = '|';
40+
expectObservable(a.buffer(b)).toBe(expected);
41+
});
542
it('should emit buffers that close and reopen', function () {
6-
var e1 = hot('-a-b-c-d-e-f-g-h-i-|');
7-
var expected = '-----x-----y-----z-|';
8-
var interval = hot('-----1-----2-----3-|');
9-
10-
expectObservable(e1.buffer(interval)).toBe(expected, {x: ['a','b','c'], y: ['d','e','f'], z: ['g','h','i']});
43+
var a = hot('-a-b-c-d-e-f-g-h-i-|');
44+
var b = hot('-----1-----2-----3-|');
45+
var expected = '-----x-----y-----z-|';
46+
expectObservable(a.buffer(b)).toBe(expected, {x: ['a','b','c'], y: ['d','e','f'], z: ['g','h','i']});
47+
});
48+
it('should work with non-empty and throw selector', function () {
49+
var a = hot('---^--a--');
50+
var b = Observable.throw(new Error('too bad'));
51+
var expected = '#';
52+
expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad'));
53+
});
54+
it('should work with throw and non-empty selector', function () {
55+
var a = Observable.throw(new Error('too bad'));
56+
var b = hot('---^--a--');
57+
var expected = '#';
58+
expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad'));
59+
});
60+
it('should work with error', function () {
61+
var a = hot('---^-------#', null, new Error('too bad'));
62+
var b = hot('---^--------')
63+
var expected = '--------#';
64+
expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad'));
65+
});
66+
it('should work with error and non-empty selector', function () {
67+
var a = hot('---^-------#', null, new Error('too bad'));
68+
var b = hot('---^---a----')
69+
var expected = '----a---#';
70+
expectObservable(a.buffer(b)).toBe(expected, { a: [] }, new Error('too bad'));
71+
});
72+
it('should work with selector', function () {
73+
// Buffer Boundaries Simple (RxJS 4)
74+
var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|');
75+
var b = hot('--------^--a-------b---cd---------e---f---|')
76+
var expected = '---a-------b---cd---------e---f-|';
77+
expectObservable(a.buffer(b)).toBe(expected,
78+
{ a: ['3'], b: ['4', '5'], c: ['6'], d: [], e: ['7', '8', '9'], f: ['0'] });
79+
});
80+
it('should work with selector completed', function () {
81+
// Buffer Boundaries onCompletedBoundaries (RxJS 4)
82+
var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|');
83+
var b = hot('--------^--a-------b---cd|')
84+
var expected = '---a-------b---cd|';
85+
expectObservable(a.buffer(b)).toBe(expected,
86+
{ a: ['3'], b: ['4', '5'], c: ['6'], d: [] });
87+
});
88+
it('should work with non-empty and selector error', function () {
89+
// Buffer Boundaries onErrorSource (RxJS 4)
90+
var a = hot('--1--2--^--3-----#', {'3': 3}, new Error('too bad'));
91+
var b = hot('--------^--a--b---')
92+
var expected = '---a--b--#';
93+
expectObservable(a.buffer(b)).toBe(expected,
94+
{ a: [3], b: [] }, new Error('too bad'));
95+
});
96+
it('should work with non-empty and empty selector error', function () {
97+
var obj = { a: true, b: true, c: true };
98+
var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|');
99+
var b = hot('--------^----------------#', null, new Error('too bad'))
100+
var expected = '-----------------#';
101+
expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad'));
102+
});
103+
it('should work with non-empty and selector error', function () {
104+
// Buffer Boundaries onErrorBoundaries (RxJS 4)
105+
var obj = { a: true, b: true, c: true };
106+
var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|');
107+
var b = hot('--------^--a-------b---c-#', obj, new Error('too bad'))
108+
var expected = '---a-------b---c-#';
109+
expectObservable(a.buffer(b)).toBe(expected,
110+
{ a: ['3'], b: ['4', '5'], c: ['6'] }, new Error('too bad'));
11111
});
12-
});
112+
});

src/operators/buffer.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {errorObject} from '../util/errorObject';
88
import bindCallback from '../util/bindCallback';
99

1010
/**
11-
* buffers the incoming observable values until the passed `closingNotifier`
12-
* emits a value, at which point it emits the buffer on the returned observable
13-
* and starts a new buffer internally, awaiting the next time `closingNotifier`
14-
* emits.
15-
*
16-
* @param {Observable<any>} closingNotifier an observable, that signals the buffer
17-
* to be emitted from the returned observable
11+
* buffers the incoming observable values until the passed `closingNotifier` emits a value, at which point
12+
* it emits the buffer on the returned observable and starts a new buffer internally, awaiting the
13+
* next time `closingNotifier` emits
14+
*
15+
* @param {Observable<any>} closingNotifier an observable, that signals the buffer to be emitted from the returned observable
1816
* @returns {Observable<T[]>} an observable of buffers, which are arrays of values
1917
*/
2018
export default function buffer<T>(closingNotifier: Observable<any>): Observable<T[]> {
@@ -33,49 +31,45 @@ class BufferOperator<T, R> implements Operator<T, R> {
3331

3432
class BufferSubscriber<T> extends Subscriber<T> {
3533
buffer: T[] = [];
36-
34+
3735
constructor(destination: Subscriber<T>, closingNotifier: Observable<any>) {
3836
super(destination);
3937
this.add(closingNotifier._subscribe(new BufferClosingNotifierSubscriber(this)));
4038
}
41-
39+
4240
_next(value: T) {
4341
this.buffer.push(value);
4442
}
45-
43+
4644
_error(err: any) {
4745
this.destination.error(err);
4846
}
49-
47+
5048
_complete() {
51-
this.flushBuffer();
5249
this.destination.complete();
5350
}
54-
51+
5552
flushBuffer() {
5653
const buffer = this.buffer;
5754
this.buffer = [];
58-
59-
if (buffer.length > 0) {
60-
this.destination.next(buffer);
61-
}
55+
this.destination.next(buffer);
6256
}
6357
}
6458

6559
class BufferClosingNotifierSubscriber<T> extends Subscriber<T> {
6660
constructor(private parent: BufferSubscriber<any>) {
6761
super(null);
6862
}
69-
63+
7064
_next(value: T) {
7165
this.parent.flushBuffer();
7266
}
73-
67+
7468
_error(err: any) {
7569
this.parent.error(err);
7670
}
77-
71+
7872
_complete() {
79-
// noop
73+
this.parent.complete();
8074
}
81-
}
75+
}

0 commit comments

Comments
 (0)