1

I want to implement a function which hits some apis asynchronously and does some calculations. However I would like to use promises (also because I thought its easy to write unit test for them)

This is the function I want to write.

const CalcFactory = (someApi1, someApi2, someApi3) => 
 async function calculation(params){
  return new Promise((res, rej) =>{
    const data1 = someApi1.getData() // getData is async
    someApi2.getData((err, data) =>{
       if(err)
         rej(err);
       else
         res();
      });
    });
 }

The question now is how to test and mock this? My first test is if all the api methods are beeing called but I already struggle with that.

const Calculator = CalcFactory(api1Mock, api2Mock, api3Mock);

if('should hit all external apis', () => {
return Calculator(somedada).then(()=>{
   expect(api1Mock.getData).toHaveBeenCalledWith(someData);
   expect(api2Mock.getData).toHaveBeenCalledWith(somedata);
   });

});

the mocks look like this:

const api1Mock = {
   someData: jest.fn(),
}

const api2Mock = {
someData: jest.fn().mockResolvedValue({
      data:{},
   })
}

However I always get a timeout when I run the test. I am also not really sure if this is a good approach to write the function but I really would like to use a promise.

1 Answer 1

1

There's getData in one place and someData in another. Considering the promise is not rejected, it's not a problem. Calculator(somedada) promise isn't resolved because someApi2.getData is incorrectly mocked and results in pending promise.

It's an antipattern to return a promise from async function without using await. This means that either it doesn't benefit from being async, or promise constructor contains too much besides promisfication of non-promise API.

In case the use of async is justified, it can be:

async function calculation(params){
  ...
  const data1 = someApi1.getData()
  const data2 = await new Promise((res, rej) =>{
      someApi2.getData((err, data) => {
       if(err)
         rej(err);
       else
         res();
      });
  });
  ...
}

In Node, error-first callbacks can be promisified with util.promisify.

And mocked someApi2.getData should use a callback like expected:

const api2Mock = {
  getData: jest.fn().mockImplementation(cb => cb(null, 'data'))
}

If someApi2.getData is used more than once, it makes sense to promisify it instead of using promise constructor every time.

Sign up to request clarification or add additional context in comments.

1 Comment

thank, I promisified someApi2.getData and just await the promise which works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.