I have a function which returns list of products after reading from a json file.
I have created a stub to mock the behaviour of fs.readfile but I want to check the exception thrown from the function and for that I want to override the default stub to return null. How do I achieve this
my function
async getAllProducts() {
try {
// let rawData = fs.readFileSync("data/products.json");
// let data = JSON.parse(rawData);
// return data;
return JSON.parse(await fs.promises.readFile("data/products.json"));
} catch (error) {
if (error.message === "Unexpected end of JSON input") {
throw new NoProductsExistError("The File is Empty");
}
throw new FileReadingError("Error Reading File");
}
}
my spec.js file
// const assert = require("assert");
const chai = require("chai");
const expect = chai.expect;
const sinon = require("sinon");
const dao = require("./dao");
const fs = require("fs");
var sandbox;
beforeEach(() => {
sandbox = sinon.createSandbox();
sandbox
.stub(fs.promises, "readFile")
.withArgs("data/products.json")
.returns(
JSON.stringify([
{
productId: 101,
productName: "Sony XB450AP Wired Headset",
},
{
productId: 102,
productName: "Sony 1000XM3 Wired Headset",
}
])
);
});
describe("getAllProducts", () => {
it("should return all products", async () => {
// Here we are using the default stub of sinon got from the beforeEach
expect(await dao.getAllProducts()).to.deep.equal([
{
productId: 101,
productName: "Sony XB450AP Wired Headset",
},
{
productId: 102,
productName: "Sony 1000XM3 Wired Headset",
}
]);
});
it("should throw Error on Empty File", async () => {
// WANT TO OVERRIDE THE DEFAULT STUB TO RETURN NOTHING
// BELOW STUB DOES NOT WORK AND GIVES "TypeError: Attempted to wrap readFile which is already wrapped" ERROR
sinon
.stub(fs.promises, "readFile")
.withArgs("data/products.json")
.returns();
expect(await dao.getAllProducts()).to.throw(NoProductsExistError);
});
});
How do I make the second stub work. Any help is much appreciated
It is better for testing if you stub/mock a dependency only once and then reset that stub/mock before each test case. Define what the dependency should do for each test case.
// const assert = require("assert");
const chai = require("chai");
const expect = chai.expect;
const sinon = require("sinon");
const dao = require("./dao");
const fs = require("fs");
describe("getAllProducts", () => {
var sandbox;
var fsReadFileStub;
before(() => {
sandbox = sinon.createSandbox();
fsReadFileStub = sandbox.stub(fs.promises, "readFile")
});
afterEach(() => {
fsReadFileStub.reset();
})
it("should return all products", async () => {
fsReadFileStub.withArgs("data/products.json")
.returns(
JSON.stringify([
{
productId: 101,
productName: "Sony XB450AP Wired Headset",
},
{
productId: 102,
productName: "Sony 1000XM3 Wired Headset",
}
])
);
expect(await dao.getAllProducts()).to.deep.equal([
{
productId: 101,
productName: "Sony XB450AP Wired Headset",
},
{
productId: 102,
productName: "Sony 1000XM3 Wired Headset",
}
]);
});
it("should throw Error on Empty File", async () => {
fsReadFileStub
.stub(fs.promises, "readFile")
.withArgs("data/products.json")
.returns();
expect(await dao.getAllProducts()).to.throw(NoProductsExistError);
});
});