Reputation: 183
I have a test case need to test a function which has 2 upper layer promise functions. I stub all of these 3 functions, the first 2 works fine, but the last one seems like no working..
classD:
const obj1 = require('./classA');
const obj2 = require('./classB');
const obj3 = require('./classC');
const getTeam = () =>{
return new Promise((resolve, reject) => {
obj1.promiseFunc1().then(res1 => {
if(res1.error){
reject(res1);
}else{
resolve({Teamid: 1, TeamName: 'goodName'});
}
})
}
const getMember = () => {
return new Promise((resolve, reject) => {
obj2.promiseFunc2().then(res2 => {
if(res2.id.length === 0){
obj3.promiseFunc3().then(res3 => {
if(res3.error){
reject(res3);
}else{
getTeam().then(res => {
if(res.error){
reject(res);
}else{
resolve(res);
}
});
}
})
}
})
})
}
Below is the test case:
Test.js
const obj1 = require('./classA');
const obj2 = require('./classB');
const obj3 = require('./classC');
const obj4 = require('./classD');
const sandbox = require('sinon').createSandbox();
test.serial('test getMember', async (t) => {
sandbox.restore();
sandbox.stub(obj2, 'promiseFunc2').resolves({id: [], error: false});
sandbox.stub(obj3, 'promiseFunc3').resolves({status: 200, error: false});
sandbox.stub(obj4, 'getTeam').resolves({data: [], error: false});
const result = await obj4.getMember();
console.log('result :' + JSON.stringify(result));
})
So I need to runa test case for the function obj4.getMember() which will call obj2.promiseFunc2, obj3.promiseFunc3, and obj4.getTeam(), they all return promises. I stub the promiseFunc2 and promiseFunc3 with no problem. But for some reason the obj4.getTeam() seems like not working well. I returned {Teamid: 1, TeamName: 'goodName'} which is the response from last test cases in the same file for getTeam()...
I expected to return {data: [], error: false} which is the outcome I stub for..
Anyone know why the stub is not working? How to make it work?
Thank you very much!
Upvotes: 0
Views: 465
Reputation: 2454
Calling getTeam
as a function from obj4.getMember
could be bypassing Simon's stub.
Try the following:
const obj1 = require('./classA');
const obj2 = require('./classB');
const obj3 = require('./classC');
const obj4 = {};
obj4.getTeam = () =>{
return new Promise((resolve, reject) => {
obj1.promiseFunc1().then(res1 => {
if(res1.error){
reject(res1);
}else{
resolve({Teamid: 1, TeamName: 'goodName'});
}
})
})
}
obj4.getMember = () => {
return new Promise((resolve, reject) => {
obj2.promiseFunc2().then(res2 => {
if(res2.id.length === 0){
obj3.promiseFunc3().then(res3 => {
if(res3.error){
reject(res3);
}else{
obj4.getTeam().then(res => {
if(res.error){
reject(res);
}else{
resolve(res);
}
});
}
})
}
})
})
}
module.exports = obj4;
I don't think you should call modules "classes" as it sets wrong expectations.
As for Promise chaining, it is unfortunate your API does not reject on errors, which forces you to add a lot of error handling logic, but a helper could convert these promises to rejected promises
const rejectOn = predicate => f => (...xs) =>
f(...xs).then(x => predicate(x) ? Promise.reject(x) : x);
const error = x => x.error;
With this in place, the following would be easier to read and functionally identical (assuming objN.promiseFuncN
are not methods with a context). Note that there is no need to wrap a promise-returning function in a new Promise and that returning a Promise replaces the surrounding Promise, removing a lot of boilerplate from your code.
obj4.getTeam = () =>
rejectOn(error)(obj1.promiseFunc1)()
.then(() => ({ Teamid: 1, TeamName: 'goodName' }));
obj4.getMember = () =>
rejectOn(x => x.id.length)(obj2.promiseFunc2)()
.then(rejectOn(error)(obj3.promiseFunc3))
.then(rejectOn(error)(obj4.getTeam));
Maybe you should have a talk with your manager. Clean code does not slow you down. Rotting code slows you down.
Upvotes: 1