I am having real issues stubbing one particular thing using sinon. I have a simple function I am testing
const floatAPIModels = require("models/float/floatAPIModels");
const insertFloatData = async (databaseConnection, endpoint, endpointData) => {
try {
const floatModel = floatAPIModels(databaseConnection);
await databaseConnection.sync();
if (endpoint === "people") {
endpointData.forEach(async (record) => {
await floatModel.Person.upsert(record);
});
}
return true;
} catch (error) {
console.log("Unable to insert data into the database:", error);
return error;
}
};
The problem is with floatAPIModels being an Object that returns things. My implementation is this
const { DataTypes } = require("sequelize");
const floatAPIModels = (sequelize) => {
const Person = sequelize.define(
"Person",
{
people_id: { type: DataTypes.INTEGER, primaryKey: true },
job_title: { type: DataTypes.STRING(200), allowNull: true },
employee_type: { type: DataTypes.BOOLEAN, allowNull: true },
active: { type: DataTypes.BOOLEAN, allowNull: true },
start_date: { type: DataTypes.DATE, allowNull: true },
end_date: { type: DataTypes.DATE, allowNull: true },
department_name: { type: DataTypes.STRING, allowNull: true },
default_hourly_rate: { type: DataTypes.FLOAT, allowNull: true },
created: { type: DataTypes.DATE, allowNull: true },
modified: { type: DataTypes.DATE, allowNull: true },
},
{
timestamps: true,
tableName: "Person",
}
);
return {
Person,
};
};
module.exports = floatAPIModels;
I have removed some things to cut down on code. At the moment I am doing something like this
const { expect } = require("chai");
const sinon = require("sinon");
const floatAPIModels = require("src/models/float/floatAPIModels");
const floatService = require("src/services/float/floatService");
describe("insertFloatData", () => {
let databaseConnection;
let floatModelMock;
beforeEach(() => {
databaseConnection = {};
floatModelMock = {
Person: { upsert: sinon.stub().resolves() },
};
sinon.stub(floatAPIModels, "Person").returns(floatModelMock.Person);
});
afterEach(() => {
sinon.restore();
});
it("should insert endpointData into the 'people' endpoint", async () => {
const endpoint = "people";
const endpointData = [{ record: "data" }];
await floatService.insertFloatData(databaseConnection, endpoint, endpointData);
expect(floatModelMock.Person.upsert.calledOnce).to.be.true;
expect(floatModelMock.Person.upsert.firstCall.args[0]).to.deep.equal(endpointData[0]);
});
});
With the above, I get
TypeError: Cannot stub non-existent property Person
But I have tried default, and a lot of other ways, but none of them seems to work.
How can I properly stub this and get the unit test working?
Thanks
floatAPIModels
is a function that returns { Person }
object. There is no Person
property on this function. That's why you got the error.
In order to stub the floatAPIModels
function, I will use the proxyquire module to do this.
E.g.
model.js
:
const { DataTypes } = require("sequelize");
const floatAPIModels = (sequelize) => {
const Person = sequelize.define(
"Person",
{
people_id: { type: DataTypes.INTEGER, primaryKey: true },
// rest fields, don't matter for this test
// ...
},
{ timestamps: true, tableName: "Person", }
);
return {
Person,
};
};
module.exports = floatAPIModels;
service.js
:
const floatAPIModels = require("./model");
const insertFloatData = async (databaseConnection, endpoint, endpointData) => {
try {
const floatModel = floatAPIModels(databaseConnection);
await databaseConnection.sync();
if (endpoint === "people") {
endpointData.forEach(async (record) => {
await floatModel.Person.upsert(record);
});
}
return true;
} catch (error) {
console.log("Unable to insert data into the database:", error);
return error;
}
};
module.exports = { insertFloatData }
service.test.js
:
const sinon = require("sinon");
const proxyquire = require('proxyquire');
describe("insertFloatData", () => {
let databaseConnection;
beforeEach(() => {
databaseConnection = {
define: sinon.stub(),
sync: sinon.stub()
};
});
afterEach(() => {
sinon.restore();
});
it("should insert endpointData into the 'people' endpoint", async () => {
const endpoint = "people";
const endpointData = [{ record: "data" }];
const PersonStub = {
upsert: sinon.stub()
}
const floatAPIModelsStub = sinon.stub().returns({ Person: PersonStub })
const floatService = proxyquire('./service', {
'./model': floatAPIModelsStub
})
await floatService.insertFloatData(databaseConnection, endpoint, endpointData);
sinon.assert.calledOnce(PersonStub.upsert)
sinon.assert.match(PersonStub.upsert.firstCall.args[0], endpointData[0])
});
});
Test result:
insertFloatData
✓ should insert endpointData into the 'people' endpoint (4168ms)
1 passing (4s)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 76.47 | 50 | 66.67 | 76.47 |
model.js | 60 | 100 | 0 | 60 | 4-24
service.js | 83.33 | 50 | 100 | 83.33 | 14-15
------------|---------|----------|---------|---------|-------------------