Test nodejs methode with Mocha and chai libraries - node.js

I want to test this methode below with Mocha and chai, but I got an error :
I want to test this methode below with Mocha and chai, but I got an error :
exports.getCaracteristiques = (req,res) => {
db.query('SELECT "titi", "toto"')
.then( ({rows}) => {
var caracteristiqueResult = rows.map((row) => {
return {
'idCaracteristique': row.CARACT_ID
, 'libelleCaracteristique': row.toto
, 'libelleCaracteristique': row.titi
};
})
res.json(caracteristiqueResult);
})
.catch(err => {
// handle the error
console.log("ERROR :", err)
res.status(500).end(err)
})
};
test.js file contains :
var expect = require('chai').expect;
require("../config/config");
var ctr = require('../api/controllers/caracteristiques')
describe('Caracteristiques', () => {
it('returns an array of Carateristiques', () => {
// This will fail if "Caracteristiques result "is
// not array.
return ctr.getCaracteristiques.then(function(data){
expect(data).to.be.a('array');
});// no catch, it'll figure it out since the promise is rejected
});
})
but I got this error :
Caracteristiques
1) returns an array of Carateristiques
0 passing (0ms)
1 failing
1) Caracteristiques
returns an array of Carateristiques:
TypeError: ctr.getCaracteristiques.then is not a function
at Context.it (test\caracteristiques.js:13:40)
How to resolve this problem ?

The error:
TypeError: ctr.getCaracteristiques.then is not a function
Is just plain right. You missed the () when onvoking the getCaracteristiques() method.
This should work:
return ctr.getCaracteristiques().then(function(data){
expect(data).to.be.a('array');
});
Edit after OP comment:
In your code, getCaracteristiques requires a req and a res objects. My guess is that your using express or any other node js http library, which usually fills that for you.
In mocha, we are calling the method by ourselves, without any web server, so we need to craft those objects by ourselves.
The getCaracteristiques method does not use req, but it does needs resto have a json() method. So we can do:
const res = {
json: (a) => a,
};
return ctr.getCaracteristiques({}, res).then(function(data){
expect(data).to.be.a('array');
});
In our test so getCaracteristiques return what we want (just the data, because the fake jsonmethod just yields away its parameter).
Now, the test will fail again, because getCaracteristiques does not return the jsoncall. If we add a return statement, the whole thing should work:
exports.getCaracteristiques = (req,res) => {
return db.query('SELECT "CARACT_ID", "CARACT_LIB", "COULEUR", "IMAGE_ACTIVE",
"IMAGE_PASSIVE", "ACTIF" FROM "DIM_PRC_CARACT"')
.then( ({rows}) => {
var caracteristiqueResult = rows.map((row) => {
return {
'idCaracteristique': row.CARACT_ID
, 'libelleCaracteristique': row.CARACT_CD
, 'libelleCaracteristique': row.CARACT_LIB
, 'couleurCaracteristique': row.COULEUR
, 'pictogrammeActifCaracteristique': row.IMAGE_PASSIVE
, 'pictogrammePassifCaracteristique': row.IMAGE_PASSIVE
};
})
return res.json(caracteristiqueResult);
})
Note that a return was added to db.query and res.json, so the getCaracteristiques method now returns a promise of the caracteristiques.

Related

Testing promise with stub

I'm trying to do some tests with chai using sinon stub. The thing is, I'm stubbing my fetch like this and resolving my promise.
let fetchedStub;
beforeEach(() => {
fetchedStub = sinon.stub(global, 'fetch');
fetchedStub.resolves({ json: () => { body: 'json' } });
});
Then I'm testing if my data is returning correctly
it('should return the JSON data from the promise', () => {
const result = search('test');
result.then((data) => {
expect(data).to.be.eql({ body: 'json' });
});
});
But instead of passing the test, I'm getting
TypeError: Cannot read property 'then' of undefined
Am I doing something wrong with my promise? I think I need some light here.
Edit: this is the search function.
export const search = (query) => {
fetch(`https://api.spotify.com/v1/search?q=${query}&type=artist`)
.then(data => data.json());
};
Your search arrow function does not return anything, hence in your test result is undefined, hence the error message.
You should simply return the result of your fetch:
export const search = (query) => {
// return something
return fetch(`url`).then(data => data.json());
};
You might have been confused by the arrow function shorthand syntax, which automatically returns the result of a single expression, provided that it is not wrapped in curly braces:
export const search = (query) => fetch(`url`).then(data => data.json()); // no curly braces after the arrow

Mocha/Chai test returns error message and I couldnt find a way to test it

Title says it all and it returns a message like this
Error: startDate is a required field
I tried to use equal, instanceof.
describe('filter', () => {
it('needs to return a startDate required message', async () => {
let dto = {
'endDate': '2000-02-02',
};
let result = await service.filter(dto);
expect(result).to.throw();
};
});
The problem here is you are not testing the error.
Think about that: When you are doing expect(result).to.throw(); the error has been thrown.
Also result didn't throws any error.
So you can test the error is thrown when calling the function.
You can do it using chai as promised in this way:
service.filter(dto).should.be.rejected;
Also, I've testd your approach using this code:
describe('Test', () => {
it('Test1', async () => {
//Only this line pass the test
thisFunctionThrowAnError().should.be.rejected;
//This not pass
let result = await thisFunctionThrowAnError();
expect(result).to.throw();
});
});
async function thisFunctionThrowAnError(){
throw new Error("Can mocha get this error?")
}

stub a function with callback, don't return promise

I have a service which is calling a function, I am writing a test for that service and I need to stub the function inside that service, that function has callback instead of returning a promise. when I make the stub for that I and give dummy return but it hangs as service expects the callback,
here is my code for the test
describe('Testing Token Service', () => {
let _stub =null;
beforeEach(async()=>{
_stub = sinon.stub(tModel.prototype, "save")
})
afterEach(async()=>{
if(_stub){
_stub.restore()
}
})
it('testing function saveToken_mongo() ', (done) => {
_stub.returns(Promise.resolve( {'status' : 'true'} ))
token_service.saveToken_mongo({},function(err, data){
console.log(err, data)
done();
})
// done()
}); });
and here is the service function for which I am writing test
Service.prototype.saveToken_mongo = function(token, callback){
var _token = new tModel( token ) ;
_token.save(function(err, data){
if(err){
callback(err, null);
return ;
}
else{
callback(null, {'status':true})
return ;
}
}) }
I need to make dummy callback return from that function using stub.
stub.returns is used for ordinary function not for callback. Since save is callback function, we can use yields.
_stub.yields(null, {'status' : 'true'});
The first argument is for error value, and the second one is for data.
As reference:
https://sinonjs.org/releases/v7.1.1/stubs/#stubyieldsarg1-arg2-
It's a bit tricky, your callback is the saveToken_mongo param,
didn't test it but try:
_stub.returns(function(err, data){callback(null, {'status':true}) });
let me know if you got an error for the callback, you may try using this.callback instead
After the study, I reached the conclusion that there are 2 solutions to this problem.
1) according to deerawan we can use yields to replace callback of function, like this
_stub.yields(null, {'status' : 'true'});
for more detail https://sinonjs.org/releases/v7.1.1/stubs/#stubyieldsarg1-arg2-
2) use bluebird to promisify all methods which will change all methods response from the callback to promise then you can use Promise.returns, here is code
var Model = conn.model( name , ModelSchema);
var Promise = require('bluebird');
Promise.promisifyAll(Model);
Promise.promisifyAll(Model.prototype);
module.exports = Model;
Now you can use test as follows
let _stub = null;
var tModel = require('./../app/models/tokens') ;
beforeEach(async()=>{
_stub = sinon.stub(tModel.prototype, "save")
})
afterEach(async()=>{
if(_stub){
_stub.restore()
}
})
it('returns a Promise' ,async function(){
_stub.returns(Promise.resolve( {'status' : 'true & false'} ));
expect(token_service.saveToken_mongo({})).to.be.a("Promise")
})

TypeError: firestoreService.snapshot_ is not a function

I've been using firebase functions test to do some testing on my functions. I have some code that is supposed to post a thing to firestore, basically in the same way that the examples show to do in the realtime database examples:
exports.addMessage = functions.https.onRequest((req, res) => {
const original = req.query.text;
admin.firestore()
.collection('messages')
.add({ original })
.then(documentReference => res.send(documentReference))
.catch(error => res.send(error));
});
For my test, I've spoofed some basic functionality using sinon, mocha and chai. Here is my current test, which is failing with the error message: TypeError: firestoreService.snapshot_ is not a function
describe('addMessage', () => {
// add message should add a message to the database
let oldDatabase;
before(() => {
// Save the old database method so it can be restored after the test.
oldDatabase = admin.firestore;
});
after(() => {
// Restoring admin.database() to the original method.
admin.firestore = oldDatabase;
});
it('should return the correct data', (done) => {
// create stubs
const refStub = sinon.stub();
// create a fake request object
const req = {
query : {
text: 'fly you fools!'
}
};
const snap = test.firestore.makeDocumentSnapshot({ original: req.query.text }, 'messages/1234');
// create a fake document reference
const fakeDocRef = snap._ref;
// create a fake response object
const res = {
send: returnedDocRef => {
// test the result
assert.equal(returnedDocRef, fakeDocRef);
done();
}
};
// spoof firestore
const adminStub = sinon.stub(admin, 'firestore').get(() => () => {
return {
collection: () => {
return {
add: (data) => {
const secondSnap = test.firestore.makeDocumentSnapshot(data, 'messages/1234');
const anotherFakeDocRef = secondSnap._ref;
return Promise.resolve(anotherFakeDocRef);
}
}
}
}
});
// call the function to execute the test above
myFunctions.addMessage(req, res);
});
});
My question is how the heck do I fix this?
I previously had a test that was just passing the first snap and fakeDocRef, and my test was passing fine, but as soon as I resolve the promise with the new fake document reference, it fails...
Any help would be appreciated! Thanks!
There are three different types of the calls, that are different:
Operating on the Collections.
Operating on the Documents.
Operating on the results of the query.
They have to be used consistently.
Please refer a documentation to see the difference operation on the collection and the document.

How am I suppose to stub a function which is dependent on result of previous function?

I have recently started writing tests and I don't have much experience.If any of the community member could point me in the right direction I would be really thankful. My scenario is simple I am half way through it but unable to solve my exact problem. Below is my code..
return generateServiceToken(req.body.appId, req.body.token, req.auth.userId)
.then(result => {
someService
.createCredentialsForUser(
req.auth.userId,
result.user.uid,
result.user.token
)
.then(result => {
return res.status(201).send(result);
});
})
.catch(error => {
return res.status(500).send({ error: `Credentials not valid - ${error}` });
});
The generateToken function is responsible to call a third party api to generate some credentials for their platform and return us the create credentials.
function generateServiceToken(appId: String, token: String, userId: String) {
return new Promise ((resolve, reject)=>{
const apiURL = `https://someapi.com/api/api.php?op=useradd&token=${token}&addr=${userId}&appid=${appId}`;
request.post(apiURL, (error, response, body) => {
const resp = JSON.parse(body);
if (resp.error) return reject(resp.error);
return resolve(resp);
});
});
}
Whereas, the someService.createCredentialsForUser function is responsible to save those credentials in database and return back the result in simple json format.
I am just stuck in stubbing someService.createCredentialsForUser function while writing the test case for happy-path
My test case is below..
describe.only("controllers/v3/some/", () => {
const c = {};
before(() => {
c.sandbox = sinon.createSandbox();
c.someServiceStub = c.sandbox
.stub(someService, "createCredentialsForUser")
.resolves(VALID_OUTPUT);
});
describe("when the request is valid", () => {
before(() => {
c.agent = setupApp(authenticationMiddleware(USER_ID));
return test(c, VALID_REQUEST_BODY);
});
it("should return 201", () => {
expect(c.response.statusCode).to.equal(201);
});
it("should call createCredentialsForUser", () => {
expect(c.stubs.createCredentialsForUser.called).to.equal(true);
});
});
});
The TestCase function is as follows..
function testCase(context, body = VALID_REQUEST_BODY) {
context.sandbox.resetHistory();
console.log(body.length);
const c = context;
return context.agent
.put(`/v3/some/`)
.send(body)
.then(r => {
c.response = r;
});
//.catch(err=>{c.response=err});
}
My someService.createCredentialsForUser function is responsible to save data into database I want to stub that that in a way that I could expect response return from generateServiceToken
I tried couples of ways which are as follows ..
First, I tried to stub that function in before() but no luck it fails with
error : IllegalArgumentError: init() must be called prior to use.
Second, I tried
c.response = c.sandbox.stub(someService, 'createCredentialsForUser').returns(Promise.resolve(r));
in my test function to stub with the value of resolved promise but no luck in this case it fails with the same error as mentioned above.

Resources