0

I'm fairly new to node and its testing ecosystem, so please forgive me if this is a bit sloppy.

I'm trying to stub a function that is set as a prototype property. This function, Validate.prototype.isAllowed, is being called inside my server code:

// Server
var router = require('express').Router();
var Validate = require('path/to/validator');
router.post('/jokes', function(req, res) {
  var validate = new Validate();
  if (!validate.isAllowed(req, 'jokes-create')) return res.end(403);
  res.end(200);
});

The validator code looks like this:

// Validator
var validate = function() {};
validate.prototype.isAllowed = function(req, action) {
  return true; // make things simple
};
module.exports = validate;

I run API tests against the server that was previously started. Here's my Mocha test where I use sinon to stub the prototype function call:

// Test
var Validate = require('path/to/validator');
var sinon = require('sinon');
var request = require('supertest-as-promised');
it('Fails with insufficient permissions', function(done) {
  sinon.stub(Validate.prototype, 'isAllowed', function() {
    return false;
  });
  request('www.example.com')
    .post('/jokes')
    .expect(403)
    .then(function() {
      Validate.prototype.isAllowed.restore();
      done();
    })
    .catch(done);
});

I observe that the stub function is never called and the test never passes. Where's the gotcha?

I've also tried to add two parameters to the stub, but that didn't seem to help. Looks like this question talks about the same problem, but for regular instance methods. Also, if I move sinon.stub() bit from the test to the server, the desired stub takes effect. I have a feeling that my test just won't patch the running server code...

Community
  • 1
  • 1
sakovias
  • 1,356
  • 1
  • 17
  • 26

2 Answers2

0

I think that inside your test you should be creating a new validator and then you create a stub for that validator, insteading of creating a stub for the prototype.

Try this:

it('Fails with insufficient permissions', function(done) {
  var validate = new Validate();
  sinon.stub(validate, 'isAllowed', function() {
    return false;
  });
  request('www.example.com')
    .post('/jokes')
    .expect(403)
    .then(function() {
      validate.isAllowed.restore();
      done();
    })
    .catch(done);
});

Also, I'm not familiar with the .restore() function, but since isAllowed is a function, I believe calling

validate.isAllowed.restore();

will not work. (Or am I missing something?)

Roberto Soares
  • 244
  • 1
  • 11
  • Unfortunately this doesn't work. This stubs `isAllowed` method on an instance of `Validate`, but this instance will never be used -- server instantiates a new validator on every call to the server route. – sakovias Jan 19 '16 at 02:49
  • Makes sense. Is your original function being called? The one defined outside the test. – Roberto Soares Jan 19 '16 at 02:54
  • Yes, it is. Another observation is that if I move `sinon.stub()` to the server code (right before the route handler definition) the stubbed method is getting called. Looks like the library on the server is not getting stubbed otherwise... – sakovias Jan 19 '16 at 03:02
  • 1
    I see. Sorry for not being able to help. I, too, am new to this. What I would try to do is log both of those validators (test and server) and check their prototypes, I think you're altering two different prototypes, but I'm just guessing. Either that or your validator is getting called after the stub and redefining the prototype. – Roberto Soares Jan 19 '16 at 03:16
0

The problem was that server and test were in separate processeses. The server should be started from within the test process for the stubs to work.

Here's an example self-contained Gist that illustrates the idea.

sakovias
  • 1,356
  • 1
  • 17
  • 26