4

I am using Slack API and I want to test does it work fine with response status code. Here is sending function :

    sendMsg(msg) {
      return this.slack.webhook({text: msg}, (err, res) => {
        if (err) {
            throw err;
        }
        console.log(res.statusCode) // = 200
        return res.statusCode;
      });
    }

And my test:

    it('Checks connection with Slack', (() => {
      let slack = new Slack();
      let res = slack.sendMsg('test');
      expect(res).to.equal(200);
    }));

But ofc. it's giving me request object to slack. I want to wait for response object from slack API. Thanks in advance.

bdddd
  • 103
  • 1
  • 10
  • Does the `sendMsg` function return a promise? If not, I think it needs to take its own callback. – Frank Modica Nov 29 '18 at 17:42
  • Idk, it's 3rd party lib for slack. :( – bdddd Nov 29 '18 at 17:46
  • You should probably look up what the slack API returns, because you're returning it to the caller of `sendMsg`. Your `sendMsg` function is written kind of like it's returning a promise from `slack.webhook`, but it uses a callback too. I don't think the caller of `sendMsg` will ever get a result. – Frank Modica Nov 29 '18 at 17:48
  • Slack API returns response object with status codes etc. I want to grab it in test. `sendMsg` is 100% my func. – bdddd Nov 29 '18 at 17:54
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – nicholaswmin Nov 29 '18 at 18:39

2 Answers2

0

It looks like slack.webhook takes in a callback, which is how you retrieve the status. The problem is that the caller of sendMsg has no way of getting that status.

One way to solve this is to have sendMsg take in a callback:

sendMsg(msg, onStatusReceived) {
  this.slack.webhook({text: msg}, (err, res) => {
    if (err) {
        throw err;
    }
    console.log(res.statusCode) // = 200
    onStatusReceived(res.statusCode);
  });
}

Then in your test, use done to end the test when the callback is invoked:

it('Checks connection with Slack', (done) => {
  let slack = new Slack();
  slack.sendMsg('message', status => {
    expect(status).to.equal(200);
    done();
  });
});

Another way is to have sendMsg wrap slack.webhook in a promise, so the caller can do sendMsg().then(...).

Frank Modica
  • 10,238
  • 3
  • 23
  • 39
  • I copy-paste your code and it throws `Uncaught TypeError: onStatusReceived is not a function` which is clearly not function but parameter. – bdddd Nov 29 '18 at 18:27
  • 1
    It throws that error in the test? Or in your actual code? Any code calling `sendMsg` now needs to pass in a callback to retrieve the status. – Frank Modica Nov 29 '18 at 18:30
  • During the test. In normal request it's fine. I edited my code a bit, function takes some text in real life. – bdddd Nov 29 '18 at 18:32
  • Updated my example – Frank Modica Nov 29 '18 at 18:34
  • @bdddd You should also use the callback to pass any errors to the calling code, instead of throwing the error. Throwing poses the danger of crashing the process if that particular slack webhook (or whatever it is) fails. See [Error-first callbacks](http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/). – nicholaswmin Nov 29 '18 at 18:35
  • @NicholasKyriakides Good point, I just tried to get a working example up for now but errors should be handled too. – Frank Modica Nov 29 '18 at 18:37
  • I'm sure you did, I was telling that to the OP :). – nicholaswmin Nov 29 '18 at 18:37
  • Much thanks Frank, sure I am callbacking error too @Nicholas Kyriakides. – bdddd Nov 29 '18 at 18:41
  • @bdddd Read the "Error-first" callback link I gave you. Without understanding that concept 100%, you won't be able to do nearly anything productive in Node.js save for simple "Hello World" programs. It's the only concept I know that's a must to know before fiddling with Node.js. Sure there are `Promise`s now which are just another way of managing async code, but many libs still use the old callback way. – nicholaswmin Nov 29 '18 at 18:42
  • @NicholasKyriakides Thanks. – bdddd Nov 29 '18 at 18:46
0

one of the ways I handled a returning callback to test is as follows:

it('receives successful response', async () => { 

nock('https://localhost')
            .persist()
            .log(console.log)
            .post(‘/getData’, (unitData, callback) => {
                return true;
            })
            .delayBody(1000)
            .reply(200, {statusCode: 'Some Status'});

const getSomeData = await getResponse(unitData, function callBack(unitData, error, data){
     expect(data.statusCode).to.be.equal(200); 
}) })

getResponse Function (returning callback):

getResponse(unitData, function callBack(unitData, error, data){ 
   try {
    return request.post(unitData, function (err, resp) {
        if (!err && resp.statusCode === 200) {
            if (resp.body.error) {
                return callback(obj, JSON.stringify(resp.body.error), null); 
            }
            return callback(obj, null, resp); 
        } else {
            if (err == null) {  
                err = { statusCode: resp.statusCode, error: 'Error occured.' };
            }
            return callback(obj, err, null); 
        }
    });
} catch (err) {
    return callback(obj, err, null);
}
}
QauseenMZ
  • 1,081
  • 8
  • 6