-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
283 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { raceWith } from 'rxjs/operators'; | ||
import { a$, b, b$, c, c$, d$, e$, f$ } from '../helpers'; | ||
|
||
describe('raceWith', () => { | ||
it('should support N arguments of different types', () => { | ||
const o1 = a$.pipe(raceWith(b$)); // $ExpectType Observable<A | B> | ||
const o2 = a$.pipe(raceWith(b$, c$)); // $ExpectType Observable<A | B | C> | ||
const o3 = a$.pipe(raceWith(b$, c$, d$)); // $ExpectType Observable<A | B | C | D> | ||
const o4 = a$.pipe(raceWith(b$, c$, d$, e$)); // $ExpectType Observable<A | B | C | D | E> | ||
const o5 = a$.pipe(raceWith(b$, c$, d$, e$, f$)); // $ExpectType Observable<A | B | C | D | E | F> | ||
}); | ||
}); | ||
|
||
it('should race observable inputs', () => { | ||
const o = a$.pipe(raceWith(Promise.resolve(b), [c])); // $ExpectType Observable<A | B | C> | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
import { expect } from 'chai'; | ||
import * as sinon from 'sinon'; | ||
import { hot, cold, expectObservable, expectSubscriptions } from '../helpers/marble-testing'; | ||
import { EMPTY, NEVER, of, timer, defer, Observable, throwError } from 'rxjs'; | ||
import { raceWith, mergeMap, map, finalize, startWith } from 'rxjs/operators'; | ||
|
||
/** @test {raceWith} */ | ||
describe('raceWith operator', () => { | ||
it('should race cold and cold', () => { | ||
const e1 = cold('---a-----b-----c----|'); | ||
const e1subs = '^ !'; | ||
const e2 = cold('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----b-----c----|'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should race hot and hot', () => { | ||
const e1 = hot('---a-----b-----c----|'); | ||
const e1subs = '^ !'; | ||
const e2 = hot('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----b-----c----|'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should race hot and cold', () => { | ||
const e1 = cold('---a-----b-----c----|'); | ||
const e1subs = '^ !'; | ||
const e2 = hot('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----b-----c----|'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should race 2nd and 1st', () => { | ||
const e1 = cold('------x-----y-----z----|'); | ||
const e1subs = '^ !'; | ||
const e2 = cold('---a-----b-----c----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----b-----c----|'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should race emit and complete', () => { | ||
const e1 = cold('-----|'); | ||
const e1subs = '^ !'; | ||
const e2 = hot('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '-----|'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should allow unsubscribing early and explicitly', () => { | ||
const e1 = cold('---a-----b-----c----|'); | ||
const e1subs = '^ !'; | ||
const e2 = hot('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----b---'; | ||
const unsub = ' !'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result, unsub).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should not break unsubscription chains when unsubscribed explicitly', () => { | ||
const e1 = hot('--a--^--b--c---d-| '); | ||
const e1subs = '^ ! '; | ||
const e2 = hot('---e-^---f--g---h-|'); | ||
const e2subs = '^ ! '; | ||
const expected = '---b--c--- '; | ||
const unsub = ' ! '; | ||
|
||
const result = e1.pipe( | ||
mergeMap((x: string) => of(x)), | ||
raceWith(e2), | ||
mergeMap((x: string) => of(x)) | ||
); | ||
|
||
expectObservable(result, unsub).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should never emit when given non emitting sources', () => { | ||
const e1 = cold('---|'); | ||
const e2 = cold('---|'); | ||
const e1subs = '^ !'; | ||
const expected = '---|'; | ||
|
||
const source = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(source).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
}); | ||
|
||
it('should throw when error occurs mid stream', () => { | ||
const e1 = cold('---a-----#'); | ||
const e1subs = '^ !'; | ||
const e2 = cold('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---a-----#'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should throw when error occurs before a winner is found', () => { | ||
const e1 = cold('---#'); | ||
const e1subs = '^ !'; | ||
const e2 = cold('------x-----y-----z----|'); | ||
const e2subs = '^ !'; | ||
const expected = '---#'; | ||
|
||
const result = e1.pipe(raceWith(e2)); | ||
|
||
expectObservable(result).toBe(expected); | ||
expectSubscriptions(e1.subscriptions).toBe(e1subs); | ||
expectSubscriptions(e2.subscriptions).toBe(e2subs); | ||
}); | ||
|
||
it('should allow observable emits immediately', (done: MochaDone) => { | ||
const e1 = of(true); | ||
const e2 = timer(200).pipe(map(_ => false)); | ||
|
||
e1.pipe(raceWith(e2)).subscribe(x => { | ||
expect(x).to.be.true; | ||
}, done, done); | ||
}); | ||
|
||
it('should ignore latter observables if a former one emits immediately', () => { | ||
const onNext = sinon.spy(); | ||
const onSubscribe = sinon.spy(); | ||
const e1 = of('a'); // Wins the race | ||
const e2 = defer(onSubscribe); // Should be ignored | ||
|
||
e1.pipe(raceWith(e2)).subscribe(onNext); | ||
expect(onNext.calledWithExactly('a')).to.be.true; | ||
expect(onSubscribe.called).to.be.false; | ||
}); | ||
|
||
it('should ignore latter observables if a former one completes immediately', () => { | ||
const onComplete = sinon.spy(); | ||
const onSubscribe = sinon.spy(); | ||
const e1 = EMPTY; // Wins the race | ||
const e2 = defer(onSubscribe); // Should be ignored | ||
|
||
e1.pipe(raceWith(e2)).subscribe({ complete: onComplete }); | ||
expect(onComplete.calledWithExactly()).to.be.true; | ||
expect(onSubscribe.called).to.be.false; | ||
}); | ||
|
||
it('should ignore latter observables if a former one errors immediately', () => { | ||
const onError = sinon.spy(); | ||
const onSubscribe = sinon.spy(); | ||
const e1 = throwError('kaboom'); // Wins the race | ||
const e2 = defer(onSubscribe); // Should be ignored | ||
|
||
e1.pipe(raceWith(e2)).subscribe({ error: onError }); | ||
expect(onError.calledWithExactly('kaboom')).to.be.true; | ||
expect(onSubscribe.called).to.be.false; | ||
}); | ||
|
||
it('should unsubscribe former observables if a latter one emits immediately', () => { | ||
const onNext = sinon.spy(); | ||
const onUnsubscribe = sinon.spy(); | ||
const e1 = NEVER.pipe(finalize(onUnsubscribe)); // Should be unsubscribed | ||
const e2 = of('b'); // Wins the race | ||
|
||
e1.pipe(raceWith(e2)).subscribe(onNext); | ||
expect(onNext.calledWithExactly('b')).to.be.true; | ||
expect(onUnsubscribe.calledOnce).to.be.true; | ||
}); | ||
|
||
it('should unsubscribe from immediately emitting observable on unsubscription', () => { | ||
const onNext = sinon.spy(); | ||
const onUnsubscribe = sinon.spy(); | ||
const e1 = <Observable<never>>NEVER.pipe(startWith('a'), finalize(onUnsubscribe)); // Wins the race | ||
const e2 = NEVER; // Loses the race | ||
|
||
const subscription = e1.pipe(raceWith(e2)).subscribe(onNext); | ||
expect(onNext.calledWithExactly('a')).to.be.true; | ||
expect(onUnsubscribe.called).to.be.false; | ||
subscription.unsubscribe(); | ||
expect(onUnsubscribe.calledOnce).to.be.true; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters