Sinon withArgs Custom Matcher

1.4k Views Asked by At

I'm trying to use a custom matcher to stub a function that executes twice in my test function from my node.js server. The function that I am testing uses fs.readFileSync() twice using different parameters. I figured I could use stub.withArgs() twice with custom matchers to return different values for both.

let sandbox = sinon.createSandbox()

before(function(done) {
  let myStub = sandbox.stub(fs, 'readFileSync')
  myStub.withArgs(sinon.match(function (val) { return val.includes('.json')})).returns('some json value')
  myStub.withArgs(sinon.match(function (val) { return val.includes('.py')})).returns('some python value')
})

The problem I'm facing is that I'm always getting a 400 status code when using chai-http to test my rest endpoint whenever I stub fs.readFileSync(). My stub implementation seems to prevent the rest endpoint from even executing functions inside the rest endpoint. When the matcher function triggers, I can verify (with logging) that it goes through my node_modules to see if there are any fs.readFileSync() functions that needs to return an alternate value.

When I run my mocha tests, with some logging inside the custom matcher, I can verify that node_modules like raw-body have their fs.readFileSync() functions stubbed, but shouldn't return alternate values, because the matcher returns false (since the parameters don't pass my matcher). But for some reason, none of my fs.readFileSync() functions are getting stubbed and are not even getting executed, because my rest endpoint just ends up returning a 400 empty response.

Is there a special way to stub functions like fs.readFileSync when testing with chai-http? I was able to successfully stub fs.writeFileSync() before, but I'm having trouble stubbing fs.readFileSync().

1

There are 1 best solutions below

0
andreyunugro On

I can confirmed with this test example that stub.withArgs() with sinon matchers works.

// File test.js
const sinon = require('sinon');
const fs = require('fs');
const { expect } = require('chai');

describe('readFileSync', () => {
  const sandbox = sinon.createSandbox();

  before(() => {
    const stub = sandbox.stub(fs, 'readFileSync');
    stub.withArgs(sinon.match(function (val) { return val.includes('.json')})).returns('some json value');
    stub.withArgs(sinon.match(function (val) { return val.includes('.py')})).returns('some python value');
  });

  after(() => {
    sandbox.restore();
  });

  it('json file', () => {
    const test = fs.readFileSync('test.spec.json');
    expect(test).to.equal('some json value');
  });

  it('python file', () => {
    const test = fs.readFileSync('test.spec.py');
    expect(test).to.equal('some python value');
  });

  it('other file', () => {
    const test = fs.readFileSync('test.txt');
    expect(test).to.be.an('undefined');
  });

  it('combine together', () => {
    const test = fs.readFileSync('test.txt.py.json');
    // Why detected as python?
    // Because python defined last.
    expect(test).to.equal('some python value');
  });
});

When I run it from terminal using mocha:

$ npx mocha test.js


  readFileSync
    ✓ json value
    ✓ python value
    ✓ other value
    ✓ combine together


  4 passing (6ms)