diff --git a/spec/helpers/doNotUnsubscribe.ts b/spec/helpers/doNotUnsubscribe.ts new file mode 100644 index 0000000000..29341119a6 --- /dev/null +++ b/spec/helpers/doNotUnsubscribe.ts @@ -0,0 +1,16 @@ +/// +import * as Rx from '../../dist/cjs/Rx'; + +export function doNotUnsubscribe(ob: Rx.Observable): Rx.Observable { + return ob.lift(new DoNotUnsubscribeOperator()); +} + +class DoNotUnsubscribeOperator implements Rx.Operator { + call(subscriber: Rx.Subscriber, source: any): any { + return source.subscribe(new DoNotUnsubscribeSubscriber(subscriber)); + } +} + +class DoNotUnsubscribeSubscriber extends Rx.Subscriber { + unsubscribe() {} // tslint:disable-line no-empty +} diff --git a/spec/operators/find-spec.ts b/spec/operators/find-spec.ts index b9094cef02..56d7748bb3 100644 --- a/spec/operators/find-spec.ts +++ b/spec/operators/find-spec.ts @@ -1,6 +1,7 @@ import {expect} from 'chai'; import * as Rx from '../../dist/cjs/Rx'; import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports +import { doNotUnsubscribe } from '../helpers/doNotUnsubscribe'; declare const { asDiagram }; declare const hot: typeof marbleTestingSignature.hot; @@ -162,6 +163,33 @@ describe('Observable.prototype.find', () => { expectSubscriptions(source.subscriptions).toBe(subs); }); + it('should unsubscribe from source when complete, even if following operator does not unsubscribe', () => { + const values = {a: 3, b: 9, c: 15, d: 20}; + const source = hot('---a--b--c--d---|', values); + const subs = '^ ! '; + const expected = '---------(c|) '; + + const predicate = function (x) { return x % 5 === 0; }; + + expectObservable((source).find(predicate).let(doNotUnsubscribe)).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should unsubscribe from source when predicate function errors,' + + ' even if followring operator does not unsubscribe', () => { + + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '--#'; + + const predicate = function (value) { + throw 'error'; + }; + + expectObservable((source).find(predicate).let(doNotUnsubscribe)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + it('should support type guards without breaking previous behavior', () => { // tslint:disable no-unused-variable diff --git a/src/operator/find.ts b/src/operator/find.ts index 110c813958..5e2f825c24 100644 --- a/src/operator/find.ts +++ b/src/operator/find.ts @@ -85,6 +85,7 @@ export class FindValueSubscriber extends Subscriber { destination.next(value); destination.complete(); + this.unsubscribe(); } protected _next(value: T): void { @@ -97,6 +98,7 @@ export class FindValueSubscriber extends Subscriber { } } catch (err) { this.destination.error(err); + this.unsubscribe(); } }