Subscribe for me, please!

await for Observables

Georgi Parlakov

--

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 for Observable.

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:

  1. Subscribe
  2. Get the values
  3. 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

--

--

Georgi Parlakov
Georgi Parlakov

Written by Georgi Parlakov

Angular and DotNet dev. RxJs explorer. Testing proponent. A dad. Educative.io course author. https://gparlakov.github.io/

No responses yet