'Calling original function from Sinon.js Stub

I'm trying to intercept a call with Sinon.js so I can do some logging and then execute the original call. I don't see a way to do this with sinon.spy(), but I think I can do it with sinon.stub().

I provided a custom function:

sinon.stub(servicecore.ServiceWrapper.prototype, '_invoke', function(method, name, body, headers, callback) {
    console.log('---- ServiceWrapper._invoke called! ----');

// How do I call the original function?

});

The problem I have is executing the original function, so my application behaves the same. Any idea?



Solution 1:[1]

You could use a closure. For example:

var obj = {
    foo: function () {
        console.log('foo');
    }
};

var stub = (function () {
    var originalFoo = obj.foo;
    return sinon.stub(obj, 'foo', function () {
        console.log('stub');
        originalFoo();
    });
}());

JSFiddle

Solution 2:[2]

Sinon stores a reference to the original function in the wrappedMethod property of the stub (docs were just recently added in 2020). This can be called in the fake method.

sinon.stub(Array.prototype, 'sort').callsFake(
  function () {
    console.log(`sorting array ${this}`);
    return Array.prototype.sort.wrappedMethod.apply(this, arguments);
  }
);

const array = ['C', 'A', 'B'].sort();
console.log(`sorted array is ${array}`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/7.3.2/sinon.min.js"></script>

And so the OP's code would be:

sinon.stub(servicecore.ServiceWrapper.prototype, '_invoke').callsFake(function(method, name, body, headers, callback) {
    console.log('---- ServiceWrapper._invoke called! ----');
    return servicecore.ServiceWrapper.prototype._invoke.wrappedMethod.apply(this, arguments);
});

Solution 3:[3]

You can access the original method stored the in stub using the wrappedMethod property.

It is useful to reference the stub using a closure, avoid a messy this context, and allowing you to use a lambda function for the fake callback.

const stub = sinon.stub(patchSync, 'patchRemote').callsFake((...args) => {
  console.log('before call')
  const result =  stub.wrappedMethod(...args)
  console.log('after call')
  return result
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 psquared
Solution 2 Wombat
Solution 3