Skip to content

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 ​

  1. Always provide callbacks - When using fake.yields() or fake.yieldsAsync(), ensure the fake is called with a callback as the last argument
  2. Type check arguments - Only pass functions to sinon.fake() when wrapping behavior
  3. Use empty fakes - If you don't need specific behavior, call sinon.fake() without arguments to create an empty fake