admin管理员组

文章数量:1415111

I have an async function that looks something like this:

const myMethod = async () => {
  await Promise.all(
    someIds.map((id) => {
      someMethodThatReturnsPromise(id);
    }); 
  );
  doSomethingElseAfterPromisesResolve();
};

This function contains a bug because it uses curly braces in its map function but doesn't return each promise. The Promise.all consumes the undefined return value and silently proceeds to the next statement, without waiting. The problem can be corrected by using parentheses instead of braces, or by including an explicit return statement.

My question is, how can I test this? I know I can use Promise.resolve() or Promise.reject() to simulate different states of the promise, and mock the return values of the inner method, but that doesn't really cover the problem. Outside a full blown integration test, how can I prevent the above error with a test?

I have an async function that looks something like this:

const myMethod = async () => {
  await Promise.all(
    someIds.map((id) => {
      someMethodThatReturnsPromise(id);
    }); 
  );
  doSomethingElseAfterPromisesResolve();
};

This function contains a bug because it uses curly braces in its map function but doesn't return each promise. The Promise.all consumes the undefined return value and silently proceeds to the next statement, without waiting. The problem can be corrected by using parentheses instead of braces, or by including an explicit return statement.

My question is, how can I test this? I know I can use Promise.resolve() or Promise.reject() to simulate different states of the promise, and mock the return values of the inner method, but that doesn't really cover the problem. Outside a full blown integration test, how can I prevent the above error with a test?

Share Improve this question asked May 23, 2018 at 21:28 Damon BlackDamon Black 651 silver badge5 bronze badges 8
  • Do you mean test it in your application, or in unit testing? – Barmar Commented May 23, 2018 at 21:31
  • 2 why not having a style checker that tells you not to forget your returns? sounds like a better prevention mechanism... – JSelser Commented May 23, 2018 at 21:34
  • Barmar - I was looking for a unit test to cover the problem. It's our teams practice to write tests covering any bugs we fix. – Damon Black Commented May 23, 2018 at 21:38
  • 1 JSelser - I found this - looks like it might do the trick: eslint/docs/rules/array-callback-return – Damon Black Commented May 23, 2018 at 21:50
  • 1 @JSelser Yes, array-callback-return looks like a good rule because the lack of return in these methods always indicates a mistake or misused method. Still, as any other code, this one needs to be tested. That it wasn't possible to detect the mistake suggests that unit tests don't provide enough coverage. – Estus Flask Commented May 24, 2018 at 5:25
 |  Show 3 more ments

2 Answers 2

Reset to default 2

Well, the issue is not that Promise.all() accepts null, it doesnt. What it accepts is arrays of the kind of [null] or [undefined] (which are 2 different things, actually)

As I mentioned in my ments, testing Promise.all() is not something I would do, it's third party code, you should be testing your own, so I think having a linter check for such bugs is a far superior solution

That being said, you are entitled to your opinions, I'll merely point out a possibility for achieving what you want. That is: monkey patching

You could overwrite the Promise.all() like so:

let originalAll = Promise.all;

Promise.all = (promises) => {
  // you could check several other things
  // but this covers what you wanted, right?
  let isArrayWithBlanks = promises.includes(null) || promises.includes(undefined);

  return isArrayWithBlanks
    ? Promise.reject("NO!")
    : originalAll(promises);
};

Now you can easily write a test given you use this monkey patched Promise.all throughout your project. You decide where to place that code

Hope this helps

I would stub both the someMethodThatReturnsPromise and doSomethingElseAfterPromisesResolve functions, returning any value from both.

Then ensure that someIds has multiple values.

Your assertions could then be:

  1. someMethodThatReturnsPromise is called once for each item in the someIds array
  2. doSomethingElseAfterPromisesResolve is called

本文标签: javascriptTesting PromiseallStack Overflow