Reputation: 1947
I have a method that takes an observable as an input and switches to new observable. Alternatively, I could use map instead of switchMap. How can this be tested using marbles?
mapFirstToStr(ob: Observable<boolean>): Observable<string> {
return ob.pipe(
first(),
switchMap(val => of(val ? 'A' : 'B'))
);
}
This doesn't work:
const source = cold('a', { a: true });
const expected = cold('b', { b: 'B' });
expect(mapFirstToStr(source)).toBeObservable(expected);
I get the following error:
Expected value to equal: [{"frame": 0, "notification": {"error": undefined, "hasValue": true, > "kind": "N", "value": "B"}}]
Received: [{"frame": 0, "notification": {"error": undefined, "hasValue": true, > "kind": "N", "value": "B"}}, {"frame": 0, "notification": {"error": > undefined, "hasValue": false, "kind": "C", "value": undefined}}]
Upvotes: 1
Views: 451
Reputation: 2210
Based on the official docs for the first
operator:
If called with no arguments, first emits the first value of the source Observable, then completes.
So, when your ob
observable emits the first value, the stream immediately completes. From the error log you printed here, you can see that array that was received contains two objects. They are both emitted on the same frame (0
), and the second one has notification.kind
value of C
which means that it is a C
omplete event.
So, you have to have expected marbles like this: '(b|)'
.
The one thing that bothers me is that the output values do not match. Based on the two cold
observables you created, you emit true
in the source
observable. When you call mapFirstToStr(source)
, it gets through first
operator and then through switchMap
. Arrow function in switchMap
returns an observable with the value based on condition in ternary operator. Since the received value is true
, ternary condition val ? 'A' : 'B'
returns 'A'
. Thus, the value in expected
observable can not be 'B'
(which is the value from the error logs), but 'A'
.
So, either you emit the first value false
:
const source = cold('a', { a: false });
const expected = cold('(b|)', { b: 'B' });
expect(mapFirstToStr(source)).toBeObservable(expected);
Or you expect 'A'
:
const source = cold('a', { a: true });
const expected = cold('(b|)', { b: 'A' });
expect(mapFirstToStr(source)).toBeObservable(expected);
Upvotes: 1