Error Handling in Fakes
Fakes validate their usage and throw errors when used incorrectly. Understanding these errors helps you use fakes correctly.
Creating Fakes
Invalid Argument Type
When creating a fake with sinon.fake(f), if you provide an argument, it must be a function.
js
import tap from "tap";
import * as sinon from "sinon";
tap.test("sinon.fake throws when passed a non-function argument", (t) => {
t.throws(
() => sinon.fake("not a function"),
/Expected f argument to be a Function/,
"throws TypeError when argument is not a function"
);
t.throws(
() => sinon.fake(42),
/Expected f argument to be a Function/,
"throws TypeError when argument is a number"
);
t.throws(
() => sinon.fake({}),
/Expected f argument to be a Function/,
"throws TypeError when argument is an object"
);
t.end();
});Yield Methods
Missing Callback
Both fake.yields() and fake.yieldsAsync() expect the last argument to be a callback function. If you call the fake without a callback, it will throw an error.
For fake.yields():
js
import tap from "tap";
import * as sinon from "sinon";
import fs from "fs";
tap.test("fake.yields", (t) => {
const fake = sinon.fake.yields(null, "file content");
const anotherFake = sinon.fake();
sinon.replace(fs, "readFile", fake);
fs.readFile("somefile", (err, data) => {
// called with fake values given to yields as arguments
t.equal(err, null, "callback receives null error");
t.equal(data, "file content", "callback receives file content");
// since yields is synchronous, anotherFake is not called yet
t.notOk(anotherFake.called, "anotherFake not called yet");
sinon.restore();
t.end();
});
anotherFake();
});
tap.test("fake.yields throws when last argument is not a function", (t) => {
const fake = sinon.fake.yields("error", "data");
t.throws(
() => fake("not a callback"),
/Expected last argument to be a function/,
"throws TypeError when last argument is not a function"
);
t.end();
});For fake.yieldsAsync():
js
import tap from "tap";
import * as sinon from "sinon";
import fs from "fs";
tap.test("fake.yieldsAsync", (t) => {
const fake = sinon.fake.yieldsAsync(null, "file content");
const anotherFake = sinon.fake();
sinon.replace(fs, "readFile", fake);
fs.readFile("somefile", (err, data) => {
// called with fake values given to yields as arguments
t.equal(err, null, "callback receives null error");
t.equal(data, "file content", "callback receives file content");
// since yields is asynchronous, anotherFake is called first
t.ok(anotherFake.called, "anotherFake was called before callback");
sinon.restore();
t.end();
});
anotherFake();
});
tap.test(
"fake.yieldsAsync throws when last argument is not a function",
(t) => {
const fake = sinon.fake.yieldsAsync("error", "data");
t.throws(
() => fake("not a callback"),
/Expected last argument to be a function/,
"throws TypeError when last argument is not a function"
);
t.end();
}
);Best Practices
- Always provide callbacks - When using
fake.yields()orfake.yieldsAsync(), ensure the fake is called with a callback as the last argument - Type check arguments - Only pass functions to
sinon.fake()when wrapping behavior - Use empty fakes - If you don't need specific behavior, call
sinon.fake()without arguments to create an empty fake
