Ronan Quigley
Ronan Quigley

Reputation: 851

Cannot stub functions inside a module when using sinon and babel-plugin-rewire

In a mocha/chai setup, I'm trying to use babel-plugin-rewire in conjunction with sinon for testing and stubbing functions within the same module. These are the example files below:

Firstly, an index.js and test file that uses both sinon and babel-plugin-rewire. Rewiring works, but for some reason, my stubs don't work. The function it is applied to is never stubbed and only the original value is returned:

// index.js

function foo() {
  return "foo";
}

export function bar() {
  return foo();
}

export function jar() {
  return "jar";
}

//index.test.js

import chai from "chai";
import sinon from "sinon";
import * as index from "./index";
const expect = chai.expect;

const sandbox = sinon.sandbox.create();

describe("babel-plugin-rewire", () => {
  it("should be able to rewire", () => {
    index.default.__set__("foo", () => {
      return "rewired"; // successfullly rewires
    });
    expect(index.bar()).to.equal("rewired"); // works fine
    index.default.__ResetDependency__("foo");
    expect(index.bar()).to.equal("bar"); // works fine
  });
});

describe("sinon", () => {
  afterEach(() => {
    sandbox.restore();
  });

  it("should call the original jar", () => {
    expect(index.jar()).to.equal("jar"); // works fine
  });

  it("should call the stubbed jar", () => {
    sandbox.stub(index, "jar").returns("stub");
    expect(index.jar()).to.equal("stub"); // fails
  });
});

And here is two example files solely using sinon stubs. The same thing happens:

// stub.js
export function stub() {
  return "stub me";
}

// stub.test.js
import * as stub from "./stub";
import sinon from "sinon";
import chai from "chai";

const expect = chai.expect;
const sandbox = sinon.createSandbox();

const text = "I have been stubbed";

describe("sinon stubs", () => {
  afterEach(() => {
    sandbox.restore();
  });
  it("should stub", () => {
    sandbox.stub(stub, "stub").returns(text);
    expect(stub.stub()).to.equal(text); // fails
  });
});

And this here is the babelrc that is being used for mocha

{
   "presets": [
     "@babel/preset-env"
   ],
   "plugins": [
     "rewire"
   ]
}

If I remove rewire from the plugins, the problem goes away. Though obviously this means I can't use rewire, which as I mentioned earlier I need in order to stub functions within the same dependency. Is this a bug with the module or am I missing something here?

Upvotes: 3

Views: 1450

Answers (1)

Daniel Cortes
Daniel Cortes

Reputation: 654

I had the same problem with one of my tests. There was an action that after signing out the user, triggered a page redirect. The redirect itself was implemented in separate file.

import * as utils from '../utils.js';
import sinon from 'sinon';

it('will dispatch an action and redirect the user when singing out', () => {
    const redirectStub = sinon.stub(utils, 'redirect').returns(true);
    // dispatch and assertion of action omitted
    expect(redirectStub.calledOnce).toBeTruthy();
    redirectStub.restore();
});

Then, for various reasons, I had to add babel-rewire-plugin to my tests. This, broke that specific test above. The calledOnce or any other sinon methods were always returning false.

Unfortunately, I wasn't able to make the spying/stubbing work anymore. I had to rewrite my test like this:

import { __RewireAPI__ } from '../utils.js';
import sinon from 'sinon';

it('will dispatch an action and redirect the user when singing out', () => {
    __RewireAPI__.__Rewire__('redirect', () => true);
    // dispatch and assertion of action omitted
    __RewireAPI__.ResetDependencty('redirect');
});

As you can see, there are no spies or stubs assertions anymore. I rewired the redirect method and then reset it.

There is a babel-plugin-rewire-exports library however, that seems to allow you to both rewire and spy/stub. I haven't tried it myself, but it can be an option if you don't want to rewrite your tests. Here is the link.

Upvotes: 2

Related Questions