await
for Observables
Subscribe for me, please!
Hi! I’d like to share a trick I use in my unit tests that takes away the need to unsubscribe in tests and provides an easy way to get to my emitted values.
Think of it like
await
forObservable
.
TL;DR;
See it live over at StackBlitz.
So what’s the problem?
Consider a test case where we need to subscribe to get our values and then assert against them:
// component
class MyComponent {
user$: Observable<User>; ngOnInit() {
this.user$ = this.userService.user$;
}
}// test file
let component: MyComponent;it('My component should gain the user on ngOnInit', () => {
component.ngOnInit(); const s = component.user$.subscribe((u) => {
expect(u).not.toBeNull();
s.unsubscribe();
});
});
We need to:
- Subscribe
- Get the values
- Unsubscribe
What if we had a function that subscribed, got the values, and unsubscribed for us?
it('My component should gain the user on ngOnInit', () => {
component.ngOnInit(); const [u] = subscribe(component.user$);
expect(u).not.toBeNull();
});
Nice huh? The function takes care to subscribe, provide the values, and unsubscribe! Think of it like await
for Observable
..
It returns an array. Array is live
- every new value gets pushed in. It takes as many values as told and unsubscribes after.
it('My component should gain the user on ngOnInit', () => {
const s$ = new Subject(); // this is 👇👇👇 where the magic happens
const values = subscribe(s$, 3); expect(values).toEqual([]);
s$.next(1);
expect(values).toEqual([1]);
s$.next(2);
s$.next(3);
expect(values).toEqual([1, 2, 3]);
s$.next(4);
expect(values).toEqual([1, 2, 3]); // 4 is missing because subscribe has unsubscribed
});
The source is a Subject
. It will emit values that will end up in an array of values
because we const values = subscribe(s$, 3)
. Since we passed in 3
as the second parameter it will unsubscribe after the 3-rd value gets emitted. Like pipe(take(3))
, only easier :) So when we emit 1, 2 and 3 they end up in the array values === [1, 2, 3]
.
In the following marble diagram the emissions
box represents all the emissions and the values
box shows what the subscribe
will provide:
It works for 1 value by default. It supports multiple values or a kill trigger observable.
Details
Detailed story link*
*it’s behind the paywall