Proxyquire with a nested dependency

So I've got a test file and 2 modules. moduleA has a dependency, moduleB
// moduleA.js
const ModuleB = require('./moduleB');

function functionA() {
return 20 + ModuleB.functionB();
};

module.exports = { functionA };


// moduleB.js
const functionB = () => {
return 10;
}

module.exports = { functionB }
// moduleA.js
const ModuleB = require('./moduleB');

function functionA() {
return 20 + ModuleB.functionB();
};

module.exports = { functionA };


// moduleB.js
const functionB = () => {
return 10;
}

module.exports = { functionB }
My test file stubs out functionB (returned from moduleB) using proxyquire:
const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('Unit Tests', function() {
it('should work', () => {
const mockedFn = sinon.stub();
mockedFn.returns(30);

const copyModuleA = proxyquire('./moduleA', {
'./moduleB': {
functionB: mockedFn
}
});

console.log(copyModuleA.functionA());
})
});
const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('Unit Tests', function() {
it('should work', () => {
const mockedFn = sinon.stub();
mockedFn.returns(30);

const copyModuleA = proxyquire('./moduleA', {
'./moduleB': {
functionB: mockedFn
}
});

console.log(copyModuleA.functionA());
})
});
So it outputs 50 (stubbed functionB 30 + functionA 20) Now I'm trying to take this example into my code: moduleA in this case is a file called validation.js. It is dependent on moduleB, in this case a sequelize model, Person. validation.js exports module.exports = { validateLogin };, a function that calls validate, which returns a function that uses Person.findOne() So in my mind, as with the simple example, I need to create a stub, point to the validation module in proxyquire, and reference the dependency and its findOne function. Like this:
1 Reply
JWode
JWode2y ago
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});
This should stub Person.findOne in validation.js. But it doesn't seem to. And I have no idea why.
let validationModule;

describe('Unit Tests', () => {
before(() => {
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});

})
it.only('should return 422 if custom email validation fails', async() => {

const wrongEmailReq = { body: {email: '[email protected]'} };

const res = {
statusCode: 500,
status: (code) => {this.statusCode = code; return this},
};

const validationFn = validationModule.validateLogin();
const wrongEmail = await validationFn(wrongEmailReq, res, ()=>{});

expect(wrongEmail.errors[0].msg).to.be.equal('Custom Authorisation Error');

return;
})
let validationModule;

describe('Unit Tests', () => {
before(() => {
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});

})
it.only('should return 422 if custom email validation fails', async() => {

const wrongEmailReq = { body: {email: '[email protected]'} };

const res = {
statusCode: 500,
status: (code) => {this.statusCode = code; return this},
};

const validationFn = validationModule.validateLogin();
const wrongEmail = await validationFn(wrongEmailReq, res, ()=>{});

expect(wrongEmail.errors[0].msg).to.be.equal('Custom Authorisation Error');

return;
})
And this is my validation.js file:
const Person = require('../models/Person');

// parallel processing
const validate = validations => {
return async (req, res, next) => {
await Promise.all(validations.map(validation => validation.run(req)));

const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}

const error = new Error();
error.message = process.env.NODE_ENV === 'development'? 'Validation Failed':'Error';

error.statusCode = !errors.isEmpty()? 422:500;
error.errors = errors.array({onlyFirstError: true});
next(error);
return error;
};
};

const validateLogin = () => {
const validations = [
body('email')
.isString()
// snip
.custom(async (value, {req}) => {
try{
const person = await Person.findOne({ where: { email: value } });

if(!person) return Promise.reject('Custom Authorisation Error');

} catch(err) {
throw err;
}
})
.trim(),
];

return validate(validations);
}

module.exports = {
validateLogin
};
const Person = require('../models/Person');

// parallel processing
const validate = validations => {
return async (req, res, next) => {
await Promise.all(validations.map(validation => validation.run(req)));

const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}

const error = new Error();
error.message = process.env.NODE_ENV === 'development'? 'Validation Failed':'Error';

error.statusCode = !errors.isEmpty()? 422:500;
error.errors = errors.array({onlyFirstError: true});
next(error);
return error;
};
};

const validateLogin = () => {
const validations = [
body('email')
.isString()
// snip
.custom(async (value, {req}) => {
try{
const person = await Person.findOne({ where: { email: value } });

if(!person) return Promise.reject('Custom Authorisation Error');

} catch(err) {
throw err;
}
})
.trim(),
];

return validate(validations);
}

module.exports = {
validateLogin
};
-------------------------------------------------- Answer So this:
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});
const stubbedFindOne = sinon.stub();
stubbedFindOne.resolves();
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: stubbedFindOne
}
});
Is basically the correct code to stub the nested dependency as far as i can see now (it's working, i'm never touching the code again) My idiocy was here: stubbedFindOne.resolves(); (or rejects()) both failed for me
try{
const person = await Person.findOne({ where: { email: value } });

if(!person) return Promise.reject('Custom Authorisation Error');

} catch(err) {
throw err;
}
try{
const person = await Person.findOne({ where: { email: value } });

if(!person) return Promise.reject('Custom Authorisation Error');

} catch(err) {
throw err;
}
stubbedFindOne.return(null) was the winner. If you look at the above code, I shouldn't be rejecting a promise - the sequelize method doesn't do that, it returns null resolves() was just straight up wrong and I think I was blindly changing code to try and get any different result. rejects() doesn't work because it jumps to the catch block.
Want results from more Discord servers?
Add your server