ReactiveX / rxjs

A reactive programming library for JavaScript
https://rxjs.dev
Apache License 2.0
30.73k stars 3k forks source link

Would you be interested in async/await TestScheduler that works with promises? #5028

Open ashmind opened 5 years ago

ashmind commented 5 years ago

Feature Request

My goal is to simplify testing of promises passed into operators, e.g. switchMap. This is slightly simpler than #701 as for now promises can just resolve on the same frame, same as of(x). However I believe my solution can be extended to support full #701 in the future.

Note: I already have a solution -- but I would like to confirm that you would be interested in it before I spend more time polishing.

Is your feature request related to a problem? Please describe. I would like to use async/await in my Redux epics, but my team will only consider it if marble tests work.

Somewhat artificial test example (real cases are a bit more complicated):

it('mergeMap + promise', (() => {
  testScheduler.run(({ cold, expectObservable }) => {
      const observable = cold('(ab|)').pipe(mergeMap(x => {
        switch (x) {
          case 'a': return of('a');
          case 'b': return Promise.resolve('b');
        }
      }));
      expectObservable(observable).toBe('(ab|)');
  });
}));

Describe the solution you'd like My current solution looks like this:

it('mergeMap + promise', (async () => {
  await testScheduler.runAsync(({ cold, expectObservable }) => {
      const observable = cold('(ab|)').pipe(mergeMap(x => {
        switch (x) {
          case 'a': return of('a');
          case 'b': return Promise.resolve('b');
        }
      }));
      expectObservable(observable).toBe('(ab|)');
  });
}));

This is very similar to the current model, but async. This allows it to flush all promises between actions.

The test above passes on my (ugly/incomplete) prototype which you can see here: https://gist.github.com/ashmind/0cdf41c25a9e50c37a634d9a7bd0ab6b.

What I would like to understand is:

  1. Would you be interested in accepting that as a PR (obviously after some serious code cleanup), or should I release it as a separate library?
  2. If you are open to accepting it, should it be in TestScheduler or a separate class? What API design would you prefer? The only technical constraint for it is to return a promise (which test needs to await), other than that any design is fine.

Describe alternatives you've considered Alternative: Use observables for individual values in Redux epics (instead of async/await, e.g. for web requests). However given web requests return a single value I find this unnatural and a missed learning opportunity for any new developers in our codebase.

Additional context

It would be really great if someone could help with test cases -- I am only really using/learning rxjs for a week, so I am guaranteed to be missing things.

pbadenski commented 4 years ago

This is amazing, I'm surprised how it got no replies. Testing promises, and in general asynchronous code, is the biggest pain we've been experiencing with RxJS and caused us significant struggle with testing it.

felixfbecker commented 3 years ago

I'd also love to see this. Promises are a lot simpler to understand for many people and enough for many use cases, but it sucks when you can't compose them into testable Rx pipelines.

clayrisser commented 3 years ago

Yes, please, I would love to see this also.

kwonoj commented 3 years ago

In my personal opinion I think it's worth to consider indeed. may need organize internal impl / api surface though.

Not much helpful for users of core's testscheduler, but I adopted similar practice to rx-sandbox (https://github.com/kwonoj/rx-sandbox/releases/tag/v2.0.0-beta.3) as well. It requires 7.0.0-beta.