Sinon error Attempted to wrap function which is already wrapped

node.jsSinon

node.js Problem Overview


Though there is a same question here but I could not find answer to my problem so here goes my question:

I am testing my node js app using mocha and chai. I am using sinion to wrap my function.

describe('App Functions', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('get results',function(done) {
     testApp.someFun
  });
}

describe('App Errors', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('throws errors',function(done) {
     testApp.someFun
  });
}

When I try to run this test it gives me error

Attempted to wrap getObj which is already wrapped

I also tried putting

beforeEach(function () {
  sandbox = sinon.sandbox.create();
});

afterEach(function () {
  sandbox.restore();
});

in each describe, but still giving me same error.

node.js Solutions


Solution 1 - node.js

You should restore the getObj in after() function, please try it as below.

describe('App Functions', function(){
	var mockObj;
    before(function () {
			mockObj = sinon.stub(testApp, 'getObj', () => {
				 console.log('this is sinon test 1111');
			});
    });

    after(function () {
        testApp.getObj.restore(); // Unwraps the spy
    });

	it('get results',function(done) {
        testApp.getObj();
    });
});

describe('App Errors', function(){
	var mockObj;
    before(function () {
			mockObj = sinon.stub(testApp, 'getObj', () => {
				 console.log('this is sinon test 1111');
			});
    });

    after( function () {
        testApp.getObj.restore(); // Unwraps the spy
    });

    it('throws errors',function(done) {
	     testApp.getObj();
	});
});

Update 2022/01/22

Using sinon's sanbox you could created stub mocks with sandbox.stub() and restores all fakes created through sandbox.restore(), Arjun Malik give an good example

Solution 2 - node.js

This error is due to not restoring the stub function properly. Use sandbox and then create the stub using the sandbox. After each test inside the suite, restore the sandbox

  beforeEach(() => {
      sandbox = sinon.createSandbox();
      mockObj = sandbox.stub(testApp, 'getObj', fake_function)
  });

  afterEach(() => {
      sandbox.restore();
  });

Solution 3 - node.js

For cases where you need to restore all the methods of one object, you can use the sinon.restore(obj).

Example:

before(() => {
    userRepositoryMock = sinon.stub(userRepository);
});

after(() => {
    sinon.restore(userRepository);
});

Solution 4 - node.js

I was also hitting this using the before() and after() hooks of Mocha. I was also using the restore() as mentioned everywhere. Single test file ran fine, multiple did not. Finally found about Mocha root-level-hooks: I did not have my before() and after() inside my own describe(). So it finds all files with before() at the root-level and executes those before starting any tests.

So make sure you have a similar pattern:

describe('my own describe', () => {
  before(() => {
    // setup stub code here
    sinon.stub(myObj, 'myFunc').callsFake(() => {
      return 'bla';
    });
  });
  after(() => {
    myObj.myFunc.restore();
  });
  it('Do some testing now', () => {
    expect(myObj.myFunc()).to.be.equal('bla');
  });
});

Solution 5 - node.js

For anyone running into this issue, if you stub or spy on the entire object, and you later do

> sandbox.restore()

You'll still get the error. You have to stub/spy the individual methods.

I wasted forever trying to figure out what was wrong.

sinon-7.5.0

Solution 6 - node.js

It is advised to initialize stubs in 'beforeEach' and restore them in 'afterEach'. But in case you are feeling adventurous, the following works too.

describe('App Functions', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('get results',function(done) {
     testApp.someFun
     mockObj .restore();
  });
}

describe('App Errors', function(){

  let mockObj = sinon.stub(testApp, 'getObj', (dbUrl) => {
     //some stuff
  });
  it('throws errors',function(done) {
     testApp.someFun
     mockObj .restore();
  });
}

Solution 7 - node.js

Even with sandbox it could give you the error. Especially when tests run in parallel for ES6 classes.

const sb = sandbox.create();

before(() => {
  sb.stub(MyObj.prototype, 'myFunc').callsFake(() => {
    return 'whatever';
  });
});
after(() => {
  sb.restore();
});

this could throw the same error if another test is trying to stub myFunc from the Prototype. I was able to fix that but I am not proud of it...

const sb = sandbox.create();

before(() => {
  MyObj.prototype.myFunc = sb.stub().callsFake(() => {
    return 'whatever';
  });
});
after(() => {
  sb.restore();
});

Solution 8 - node.js

Just a heads-up, because this took me about an hour to figure out:

If you have two (or more) test files, and find yourself still getting "already wrapped" error no matter what you try, make sure your beforeEach and afterEach stub / replace handlers are INSIDE the test file's describe block.

If you put them in the global test scope, i.e. OUTSIDE the describe('my test description', () => {}) construct, sinon will attempt it twice and throw this.

Solution 9 - node.js

I ran into this with spies. This behaviour makes sinon pretty inflexible to work with. I created a helper function that attempts to remove any existing spy before setting a new one. That way I don't have to worry about any before/after state. A similar approach might work for stubs too.

import sinon, { SinonSpy } from 'sinon';

/**
 * When you set a spy on a method that already had one set in a previous test,
 * sinon throws an "Attempted to wrap [function] which is already wrapped" error
 * rather than replacing the existing spy. This helper function does exactly that.
 *
 * @param {object} obj
 * @param {string} method
 */
export const spy = function spy<T>(obj: T, method: keyof T): SinonSpy {
  // try to remove any existing spy in case it exists
  try {
    // @ts-ignore
    obj[method].restore();
  } catch (e) {
    // noop
  }
  return sinon.spy(obj, method);
};

Solution 10 - node.js

I met this behavior because the function was spy-ed somewhere else. So, I removed the predefined spy like below and created my own.

obj.func.restore()
let spy = sinon.spy(obj, 'func')

It works.

Solution 11 - node.js

function stub(obj, method) {
     // try to remove any existing stub in case it exists
      try {
        obj[method].restore();
      } catch (e) {
        // eat it.
      }
      return sinon.stub(obj, method);
    }

and use this function when creating stubs in tests. It will resolve 'Sinon error Attempted to wrap function which is already wrapped' error.

example:

stub(Validator.prototype, 'canGeneratePayment').returns(Promise.resolve({ indent: dTruckIndent }));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrovyView Question on Stackoverflow
Solution 1 - node.jszangwView Answer on Stackoverflow
Solution 2 - node.jsArjun MalikView Answer on Stackoverflow
Solution 3 - node.jsRenan FerreiraView Answer on Stackoverflow
Solution 4 - node.jsWilfred DittmerView Answer on Stackoverflow
Solution 5 - node.jsKhon LieuView Answer on Stackoverflow
Solution 6 - node.jsKarnaView Answer on Stackoverflow
Solution 7 - node.jsToninoView Answer on Stackoverflow
Solution 8 - node.jsAmc_rttyView Answer on Stackoverflow
Solution 9 - node.jsPhilView Answer on Stackoverflow
Solution 10 - node.jsDevExciteView Answer on Stackoverflow
Solution 11 - node.jsgramchaView Answer on Stackoverflow