SimpleJ
SimpleJ

Reputation: 14788

Mocha tests wrapped in sinon.test are losing access to spy, mock, and stub

Our tests are organized like this:

describe("description", sinon.test(function() {
    const harness = this;
    it("should do something", function() {
        // do something with harness.spy, harness.mock, harness.stub
    });
}));

When run, these tests are all failing with TypeError: harness.spy is not a function. I've added some logs and found that harness.spy exists and is a function before the function passed to it is called, but inside the function passed to it, harness.spy is undefined.

Any help understanding what is happening here would be much appreciated.

Upvotes: 1

Views: 124

Answers (1)

Louis
Louis

Reputation: 151511

The problem is the order in which Mocha executes your code. Wrapping the callback to describe with sinon.test cannot work. That's because the callbacks to all describe finish executing before any of the tests in it even start executing. The way sinon.test works, it creates a new sandbox, instruments this with some of the methods of the sandbox (spy, stub, etc.), then calls its callback, and when the callback returns, sinon.test removes from this the methods that it added.

So necessarily, any of the setup performed by sinon.test wrapping a describe callback will be undone before any of the tests are run. Here's an example where I've put some console.log. You'll see both console.log statements execute before any test is run.

const sinon = require("sinon");

describe("description", sinon.test(function() {
    const harness = this;
    it("should do something", function() {
    });

    console.log("end of describe");
}));

console.log("outside");

You need to wrap the callbacks you pass to it, instead, like this:

const sinon = require("sinon");

describe("description", function() {
    it("should do something", sinon.test(function() {
        this.spy();
    }));
});

console.log("outside");

If the lifetime of the sandbox created by sinon.test does not work for you, then you have to create your sandbox and clean it "manually", like this:

const sinon = require("sinon");

describe("description", function() {
    let sandbox;
    before(function () {
        sandbox = sinon.sandbox.create();
    });
    after(function () {
        sandbox.restore();
    });
    it("should do something", function() {
        sandbox.spy();
    });
    it("should do something else", function() {
        // This uses the same sandbox as the previous test.
        sandbox.spy();
    });
});

Upvotes: 1

Related Questions