Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get callback arguments from sinon.spy inside promise javascript

I'm running a test using mocha and sinon to get a callback value from inside a promise scope of HTTP-request and it doesn't work due to the async nature of promises. It's because by the time sinon.spy checks on callback, It would have been vanished already and become empty or undefined. Here's the testing code:

 it('should issue GET /messages ', function() {
  server.respondWith('GET', `${apiUrl}/messages?counter=0`, JSON.stringify([]));
  let callback = sinon.spy();
  Babble.getMessages(0, callback);
  server.respond();
  sinon.assert.calledWith(callback, []);
});

and the promise:

function requestPoll(props) {
    return new Promise(function(resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.open(props.method, props.action);
            xhr.timeout = 500; // time in milliseconds
            if (props.method === 'post' ) {
                    xhr.setRequestHeader('Content-Type', 'application/json');
            }
            xhr.addEventListener('load', function(e) {
                    resolve(e.target.responseText);
            });

            xhr.send(JSON.stringify(props.data));


    });
}

and the call which I'm trying to get callback from on sinon.spy

getMessages: function(counter, callback){

            requestPoll({

                            method: "GET",
                            action: "http://localhost:9090/messages?counter="+counter

            }).then(function(result){

                    callback(result);
            });


        }

sinon.spy says it didn't have any arguments (due to async functionality). I tried to look for a way to get result outside the scope and put it on callback.yet I found out it was impossible. also tried resolve and promise return but didn't succeed.

How can I make this unit test pass?

Edit:
this is my attempt:

getMessages: function(counter, callback){

            var res;
            res = httpRequestAsync("GET",'',"http://localhost:9097/messages?counter=",counter);

            console.log(res);
            if(res!="")
                    callback( JSON.parse(res) );                      
        }

I put the request in a separate function:

function httpRequestAsync(method,data,theUrl,counter)
    {

            return requestPoll({

                    method: method,
                    action: theUrl+counter,
                    data: data

            }).then(JSON.parse);

    }

It returned res as the promise and inside its prototype there's the promised value I need. enter image description here

How can I access that promised value over there?

like image 807
Shaked Avatar asked Jul 21 '26 09:07

Shaked


1 Answers

I recommend you not to mix promises and callbacks. If you already have promise based function stick with it

First make getMessages not to break promise chaing. Make it return a Promise

getMessages: function(counter) {
  return requestPoll({
    method: "GET",
    action: "http://localhost:9090/messages?counter=" + counter
  }).then(JSON.parse)
}

Then use this promise in your test

it('should issue GET /messages ', function() {
  server.respondWith('GET', `${apiUrl}/messages?counter=0`, JSON.stringify([{testdata}]));
  const gettingMessages = Babble.getMessages(0);
  server.respond();

  // return a promise so testing framework knows the test is async
  return gettingMessages.then(function(messages) {
      // make assertion messages is actually testdata
  })
})
like image 64
Yury Tarabanko Avatar answered Jul 23 '26 22:07

Yury Tarabanko