cartant / rxjs-marbles

An RxJS marble testing library for any test framework
https://cartant.github.io/rxjs-marbles/
MIT License
300 stars 18 forks source link

How to actually deal with promises? #71

Open Maximaximum opened 4 years ago

Maximaximum commented 4 years ago

This is probably a duplicate of https://github.com/cartant/rxjs-marbles/issues/11, but the original issue never contained a valid example of a workaround for the issue with Promises.

And it would be really helpful if the library supported Promises out of the box.

Because right now I'm in a situation where after a code refactoring I cannot continue using rxjs-marbles in testing my Angular ngrx effect, because it consumes a service that returns a promise.

Any help appreciated.

Thanks

cartant commented 4 years ago

This library was written before RxJS had an official, public testing API. Now that it does, this library is little more than a thin wrapper around TestScheduler#run. Any support for promises would need to be added to the TestScheduler in RxJS. However, I have reservations about mixing the virtual times of marbles with the definitely not-virtual-times of promises.

Maximaximum commented 4 years ago

OK, I see your point, but how would you suggest to handle promises then? Because without a solution to this issue I'll have to go back to asynchronous testing of observables, which I wouldn't want to do.

cartant commented 4 years ago

There's no way around the asynchrony that's inherent in promises. Native promises cannot be monkey patched.

I would use the observe helper that's in this package. Also, IIRC, Ben talked a little about testing in this online meetup that he did a short while ago: https://www.youtube.com/watch?v=_2hvpWLyd0o

Maximaximum commented 4 years ago

@cartant thanks a lot for your reply!

However, as far as I could find out from this example https://github.com/cartant/rxjs-marbles/blob/master/examples/jasmine/observe-spec.ts the observe() helper does not help to use the rxjs-marbles-style assertions like

m.expect(effects.openSequence).toBeObservable(
  m.cold('(1234)', expectedActions)
);

And you'll have to revert to using the plain old async-style assertions. What's the benefit of using the observe helper altogether then?

cartant commented 4 years ago

It avoids some boilerplate. That's all.

Maximaximum commented 4 years ago

I see. Thank you!

I've watched the video you shared and I think the bottom line is, as Ben suggests: "Only use marble tests for testing custom rxjs operators, nothing more".

I tried to use marbles to test an ngrx effect (as suggested by this article https://christianlydemann.com/the-complete-guide-to-ngrx-testing/), but obviously this is not a good use case for marble tests.

It's a pity though, that there's no way to work around the Promise issue. It would be extremely convenient to use marbles for testing things like ngrx effects. Ngrx effects, similarly to operators, mostly have to do with combining different data streams, but they are too specific to be able to extract some generic functionality into custom rxjs operators.

Maximaximum commented 4 years ago

I'll just leave a link to the rxjs Known issues here, so that anyone scratching their head around these issues can easily find it: https://rxjs.dev/guide/testing/marble-testing#known-issues

Maximaximum commented 4 years ago

@cartant One more question please.

Is there a way to use both observe() (to get rid of the done callback) and marbles() (to create hot/cold observables for tests)? I couldn't find such an example

cartant commented 4 years ago

Nope. You cannot use hot and cold without the TestScheduler and virtual time. Use subjects for hot observables and of for cold, etc.