Sinon error Attempted to wrap function which is already wrapped

前端 未结 9 581
滥情空心
滥情空心 2020-12-24 04:01

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 usin

相关标签:
9条回答
  • 2020-12-24 04:40

    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();
        });
    });
    
    0 讨论(0)
  • 2020-12-24 04:40

    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);
    };

    0 讨论(0)
  • 2020-12-24 04:42

    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();
      });
    }
    
    0 讨论(0)
  • 2020-12-24 04:44

    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);
    });
    
    0 讨论(0)
  • 2020-12-24 04:44

    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();
    });
    
    0 讨论(0)
  • 2020-12-24 04:58

    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');
      });
    });
    
    0 讨论(0)
提交回复
热议问题