-1

Hi I am write a unit test case of this function. When I run this function from the unit test case then it covers all statements but setInterval complete lines are not covered.

Does anyone know how to cover it in javascript? I am using mocha.

const open = async function (config) {

    ...... set of lines..

    let retryIn = setInterval(async () => {
        try {
            client = await connect(config);
            clearInterval(retryIn);
            return client;
        } catch (err) {
           //error
        }
    }, 20000);

};

I am simply calling it like this

it("###test", async () => {
        open(config);
    });
});
N Sharma
  • 33,489
  • 95
  • 256
  • 444
  • https://stackoverflow.com/questions/35778661/mocha-and-chai-test-fails-when-testing-function-with-setinterval – Hyyan Abo Fakher Aug 24 '18 at 11:49
  • 1
    Not related to your question. But what exactly should the `setInterval` do in your case? This construct looks completely wrong. If you abuse a thrown exception of `connect` to force a re-try of the connection after 20sec, then you really should change that, especially if that code runs in node. An unhandled rejection of a Promise will exit node applications in future. – t.niese Aug 24 '18 at 11:49
  • @NSharma It still looks extremely suspicious. Because then your code would only make _"sense"_ if `await connect` waits more then 20sec, but even then it looks like a wrong handling of an error case. – t.niese Aug 24 '18 at 11:55
  • @t.niese see this updated code, this is my code, `connect` method throws an error – N Sharma Aug 24 '18 at 12:07
  • @NSharma Not related to your question but is `connnect` tries to connect to a socket ?! if this is the case , then [this might help](https://stackoverflow.com/questions/42304996/javascript-using-promises-on-websocket/) – Hyyan Abo Fakher Aug 24 '18 at 13:08

3 Answers3

2

First of all, you should never use setInterval in the case where you want to retry a task that has failed. You should use setTimeout instead.

Besides that, you cannot return a value from a classical callback base function like setInterval or setTimeout. So in its current form, the promise returned when calling open will be resolved before any connection is made.

With await/async you can create a clean and simple setup for such a situation:

function wait(seconds) {
  return new Promise((resolve, _) => setTimeout(resolve, seconds))
}

async function connect() {
  throw new Error('failed')
}

async function open(config) {
  let client;

  while (client === undefined /* || retries > maxRetries*/ ) {
    try {
      client = await connect(config);
    } catch (err) {
      // if connection failed due to an error, wait n seconds and retry
      console.log('failed wait 2 seconds for reconnect');
      await wait(2000)
      // ++retries
    }
  }


  if (!client) {
    throw new Error('connection failed due to max number of retries reached.')
  }
  
  return client
}


async function main() {
  let connection = await open()
}

main().catch(err => console.log(err))

You can further extend this snippet by adding a retry limit. See the comments for a rough idea on how that can be achieved.

To test the above code, you would write:

it("###test", function() {
  return open(config);
});
leitdeux
  • 94
  • 1
  • 6
t.niese
  • 39,256
  • 9
  • 74
  • 101
1

Someone posted an answer about fake timers and then deleted it , The answer was correct so I re-posted again.

You can use sinonjs to create fake timers

Fake timers are synchronous implementations of setTimeout and friends that Sinon.JS can overwrite the global functions with to allow you to more easily test code using them

But from your code, it seems you are trying to test async code, in mocha, this can be achieved like this

describe('somthing', () => {
  it('the result is 2', async () => {
    const x = await add(1, 1)
    expect(x).to.equal(4);
  });
});

With something closer to your code

async function open() {

  return new Promise((resolve, reject) => {

    setTimeout(() => {
      resolve('done')
    }, 1000);
  });
};

describe('somthing', () => {
  it('###test', async () => {
    const x = await open()
    chai.expect(x).to.equal("done");
  });
});
Hyyan Abo Fakher
  • 3,497
  • 3
  • 21
  • 35
0

Just wrap to Promise

const open = async function (config) {
    ...... set of lines..
    return new Promise((resolve, reject) => {
      let retryIn = setInterval(async () => {
        client = await connect(asConfigParam);
        clearInterval(retryIn);
        return client;
      }, 20000);
      return resolve(retryIn);
    });
};


it("###test", async () => {
        const result = await open(config);
        console.log('result', result)
});
аlex
  • 5,426
  • 1
  • 29
  • 38
  • This does not make sense, what do you think that `result` would be and how that would help to do unit tests? – t.niese Aug 24 '18 at 12:03