diff --git a/doc/marble-testing.md b/doc/marble-testing.md index 1628522a87..5615b7ecbd 100644 --- a/doc/marble-testing.md +++ b/doc/marble-testing.md @@ -44,7 +44,7 @@ testScheduler.run(helpers => { - `hot(marbleDiagram: string, values?: object, error?: any)` - creates a ["hot" observable](https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339) (like a subject) that will behave as though it's already "running" when the test begins. An interesting difference is that `hot` marbles allow a `^` character to signal where the "zero frame" is. That is the point at which the subscription to observables being tested begins. - `cold(marbleDiagram: string, values?: object, error?: any)` - creates a ["cold" observable](https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339) whose subscription starts when the test begins. -- `expectObservable(actual: Observable).toBe(marbleDiagram: string, values?: object, error?: any)` - schedules an assertion for when the TestScheduler flushes. +- `expectObservable(actual: Observable).toBe(marbleDiagram: string, values?: object, error?: any)` - schedules an assertion for when the TestScheduler flushes. Give `subscriptionMarbles` as parameter to change the schedule of subscription and unsubscription. If you don't provide the `subscriptionMarbles` parameter it will subscribe at the beginning and never unsubscribe. Read below about subscription marble diagram. - `expectSubscriptions(actualSubscriptionLogs: SubscriptionLog[]).toBe(subscriptionMarbles: string)` - like `expectObservable` schedules an assertion for when the testScheduler flushes. Both `cold()` and `hot()` return an observable with a property `subscriptions` of type `SubscriptionLog[]`. Give `subscriptions` as parameter to `expectSubscriptions` to assert whether it matches the `subscriptionsMarbles` marble diagram given in `toBe()`. Subscription marble diagrams are slightly different than Observable marble diagrams. Read more below. - `flush()` - immediately starts virtual time. Not often used since `run()` will automatically flush for you when your callback returns, but in some cases you may wish to flush more than once or otherwise have more control. diff --git a/spec/schedulers/TestScheduler-spec.ts b/spec/schedulers/TestScheduler-spec.ts index eeb996d61a..863c45f36c 100644 --- a/spec/schedulers/TestScheduler-spec.ts +++ b/spec/schedulers/TestScheduler-spec.ts @@ -248,6 +248,13 @@ describe('TestScheduler', () => { const expected = '--a'; expectObservable(source, unsubscribe).toBe(expected); }); + + it('should accept a subscription marble diagram', () => { + const source = hot('-a-b-c|'); + const subscribe = '---^'; + const expected = '---b-c|'; + expectObservable(source, subscribe).toBe(expected); + }); }); describe('expectSubscriptions()', () => { diff --git a/src/internal/testing/TestScheduler.ts b/src/internal/testing/TestScheduler.ts index 4874389511..7c7dc9e4ad 100644 --- a/src/internal/testing/TestScheduler.ts +++ b/src/internal/testing/TestScheduler.ts @@ -92,11 +92,13 @@ export class TestScheduler extends VirtualTimeScheduler { } expectObservable(observable: Observable, - unsubscriptionMarbles: string = null): ({ toBe: observableToBeFn }) { + subscriptionMarbles: string = null): ({ toBe: observableToBeFn }) { const actual: TestMessage[] = []; const flushTest: FlushableTest = { actual, ready: false }; - const unsubscriptionFrame = TestScheduler - .parseMarblesAsSubscriptions(unsubscriptionMarbles, this.runMode).unsubscribedFrame; + const subscriptionParsed = TestScheduler.parseMarblesAsSubscriptions(subscriptionMarbles, this.runMode); + const subscriptionFrame = subscriptionParsed.subscribedFrame === Number.POSITIVE_INFINITY ? + 0 : subscriptionParsed.subscribedFrame; + const unsubscriptionFrame = subscriptionParsed.unsubscribedFrame; let subscription: Subscription; this.schedule(() => { @@ -112,7 +114,7 @@ export class TestScheduler extends VirtualTimeScheduler { }, () => { actual.push({ frame: this.frame, notification: Notification.createComplete() }); }); - }, 0); + }, subscriptionFrame); if (unsubscriptionFrame !== Number.POSITIVE_INFINITY) { this.schedule(() => subscription.unsubscribe(), unsubscriptionFrame);