Mocha subbing results are different based on the file path - node.js

I am trying to set up stubbing out of middleware using Sinon in my Node App.
When I run a mocha test and point directly to the test file it stubs out correctly. When I point to all my testing folder and run the tests recursively it does not stub out the middleware and fails.
File Structure:
test
functional
checklist
test.spec.js
lib
middleware
auth.js (this is what is being stubbed out)
test.spec.js
const chai = require('chai');
const chaiHttp = require('chai-http');
const sinon = require('sinon');
chai.use(chaiHttp);
const should = chai.should();
// Requirements
const auth = require('../../../lib/middleware/auth')
describe('/checklist/checklistItemLevel',function() {
let checkTokenStub;
beforeEach(function(){
checkTokenStub = sinon.stub(auth,'checkToken').callsFake((req,res,next)=>{
console.log('Stubbed')
next()
});
})
afterEach(function(){
auth.checkToken.restore();
})
context('/ POST',function() {
it('should return hello',function(done){
chai.request(require('../../../server'))
.post('/api/v1/checklist/checklistItemLevel')
.end((err,res)=>{
res.should.have.status(200);
res.text.should.be.eql('Hello');
done(err);
})
})
})
})
router.js
const router = require('express').Router();
const controller = require('./controller')
const auth = require('../../../lib/middleware/auth')
router.post('/',auth.checkToken,(req,res,next)=>{
res.send('Hello');
});
module.exports = router;
Mocha Calls
mocha "**/*.spec.js" // <- Doesnt stub out middleware
mocha "test/functional/checklist/*.spec.js" // <- Stubs out successfully

Found the answer. Mocha is working properly. But the app is being cached by another test case so its running without the stubs

Related

How to test a routing handler calling via mock from express

I'm unit-testing some code of mine in nodejs that works with express.
While it seems obvious, I want to test that my routes are calling the right handler functions.
I'm using jest to create a mock function for the handler function.
While I successfully tried to test that a function is called inside another function, I cannot seem to test that a function (handler) is called from express get of post.
Let's see an examplee:
fruits.js
function orange (req,res,next) {res.status(200)} ;
module.exports = {orange}
app.js
const fruits = require('./fruits')
const express = require('express');
const app = express();
app.get('/fruits', fruits.orange);
module.exports = { app };
When I'm trying to test (with jest) that GET request (with the help of axios module) to /fruits is calling orange(), altough actually orange() works, it won't be saved as a calling with a mock function cover of spy cover.
How can I test that orange() has been called from the GET request ?
Try using supertest with Jest
const app = require('../app') //path to app.js
const request = require('supertest')
test('Upload Info Endpoint', async() => {
await request(app).get('/fruits')
.expect(resp.body.field).toMatch(mocked_field_value)
});

How to startup the server when testing an Express app via Mocha

I would like to write unit tests using Mocha for my Nodejs/Express app that I have written in visual studio. I have scoured everywhere I could looking for a simple tutorial but not found what I am looking for. I have seen many tutorials in creating a test using assert to test that 5=5, etc. but that's not what I want to do.
I am trying to add a JavaScript Mocha Unit Test file through VS and then all I really want it to do is open the home page of my app, check for some content in the body and pass the test. If I want to run the tests from the Test Explorer window the nodejs app can't be running and if it isn't running there would be nothing to receive the request for the homepage.
So I'm not sure if the test itself is somehow supposed to launch the app or what? I feel like I'm in a catch 22 and missing the very basics, just don't see it described anywhere.
What you're looking for is most commonly called an API test - a part of integration testing, not a unit test. If a test touches network, a database or I/O it's, most commonly, an integration test instead.
Now to your question. In order to test your app.js code without starting up the server manually beforehand you can do the following:
module.export your app server.
In your tests, use chai-http to test routes.
require your app in the tests and use that instead of URL's when testing routes.
The key here is the 1st bullet point. You must export your app so you can require it and use it in your tests. This allows you to skip the part where you start a separate server process to run the tests on.
Server code
// app.js
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
app.use(bodyParser.json())
// Routes
app.post('/register', (req, res) => {
const requiredFields = ['name', 'email']
if (requiredFields.every(field => Object.keys(req.body).includes(field))) {
// Run business logic and insert user in DB ...
res.sendStatus(204)
} else {
res.sendStatus(400)
}
})
app.listen(3000)
// export your app so you can include it in your tests.
module.exports = app
Test code
// test/registration.spec.js
const chai = require('chai')
const chaiHttp = require('chai-http')
// `require` your exported `app`.
const app = require('../app.js')
chai.should()
chai.use(chaiHttp)
describe('User registration', () => {
it('responds with HTTP 204 if form fields are valid', () => {
return chai.request(app)
.post('/register')
.send({
name: 'John Doe',
email: 'john#doe.com'
})
.then(res => {
res.should.have.status(204)
})
.catch(err => {
throw err
})
})
it('responds with HTTP 400 if some fields are missing', () => {
return chai.request(app)
.post('/register')
.send({
name: 'John Doe'
})
.catch(err => {
err.should.have.status(400)
})
})
})
Then just run your test from the root directory with:
$ mocha test/registration.spec.js

Mocha, Chai & Sinon: Checking internal working of an API

Let's suppose I have a POST endpoint /user/:id and this endpoint, internally calls a function getUserData(id) and then returns the result to the caller, which in-turn returns the output, after JSON.stringify()ing.
Now, I need to ensure that getUserData(id) is called, for at-least once. How can I stub / spy getUserData(id) function, when I am using chai-http to make a post request to the server? Is it even a correct approach?
I adapted the tutorial from https://scotch.io/tutorials/test-a-node-restful-api-with-mocha-and-chai down to a barebones server and test that you can use to do a basic API test.
As Mr.Phoenix said, you don't need to get too deep into the nitty gritty of your handler, just pass some data to your endpoint and check the result against what you expect to get.
Here are 2 files you can use to do this test:
index.js
const express = require('express')
const app = express()
app.get('/material',(req, res)=>{
res.json([])
//res.json(['stone', 'wood'])
})
function getUserData(id){
return 42
}
const port = 3031
app.listen(port, function(err){
console.log("Listening on port: " + port)
})
module.exports = app
test.js
process.env.NODE_ENV = 'test'
// const Material = require('./materials') // conroller
const chai = require('chai')
const chaiHttp = require('chai-http')
const server = require('./index')
const should = chai.should()
chai.use(chaiHttp)
describe('/GET material', () => {
it('it should get all the materials', (done)=>{
chai.request(server)
.get('/material')
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('array')
res.body.length.should.be.eql(0) // start empty
done()
})
})
})

How to unit test express route with passport authenticate

How can one unit test an express router that is dependent on passport authentication to call the helper methods?
I'm new to express unit testing and I've seen a lot of code that actually hits the server to call the method. But would that not make it an integration test? This ultimately comes down to my lack of understanding on the best practices on express unit testing.
I've tried to just mock out the passport but that didn't work because I need to get to the callbacks. I've also tried using rewire and just try to test the helper methods and that didn't seem to work either, I think, because file is wrapped in module.export.
Any help here would be much appreciated.
File I'm trying to unit test:
module.exports = function (inject) {
var router = require('express').Router();
var app = inject.app;
return router.get('/', app.passport.authenticate('bearer', { session: false }), [editContentCheck, getUser]);
function editContentCheck(req,res,next) {
if(req.authInfo.scope.indexOf('readOwnUser') == -1) {
res.statusCode = 403;
return res.end('Forbidden');
}
return next();
}
function getUser(req, res) {
var authHeader = req.headers.authorization.split(' ');
var token = authHeader[1];
var models = require('../models');
models.AccessToken.getAccessToken(token,function(err,tokenObj) {
models.User.getUser(tokenObj.userId, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
res.send(JSON.stringify(user));
});
});
}
};
Check this repository, it has all You want: https://github.com/num8er/alttab-nodejs-challenge
Also a look at example and implement it as You wish:
1)server.js :
var
http = require('http'),
app = require('./app'); // app.js file
http.createServer(app).listen(8080);
2)app.js :
var
express = require('express'),
app = express();
app.use(require('./routes')); // routes.js file
module.exports = app;
3)routes.js :
var router = require('express').Router();
function editContentCheck(req,res,next) {}
function getUser(req, res) {}
router.get('/posts', app.passport.authenticate('bearer', { session: false }), [editContentCheck, getUser]);
module.exports = router;
4)spec/AppSpec.js :
var
request = require('supertest-as-promised'), // npm i --save-dev supertest-as-promised
app = require('./../app');
var token = "some token here";
describe('App', function() {
describe("Posts", function() {
it('should pass auth check and get posts', function() {
return request(app)
.get('/posts')
.set('Authorization', 'Bearer ' + token)
.expect(200);
});
});
});
p.s. I'm using jasmine as testing framework, but even with mocha it's same style. Because of it's using supertest-as-promised that gets app module and calls the route without creating http object.
p.s.2. it's not unit testing, You're testing the feature, so it's more an integration test to check if all chains of code is properly integrated.

how to use sinon js with Express js unit testing

Hi i want to do unit testing on my express js code i want to mock data so after searching multiple websites and blogs i found this library but i am not clear how can i use this library for mocking or data.
My testing code is
var request = require('supertest');
var server = require('./app');
var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('./app');
var should = chai.should();
chai.use(chaiHttp);
describe('loading express', function () {
it('responds to /', function testSlash(done) {
request(server)
.get('/')
.expect(200, done);
});
it('404 everything else', function testPath(done) {
request(server)
.get('/foo/bar')
.expect(404, done);
});
it('responds to /customers/getCustomerData', function testPath(done) {
request(server)
.get('/customers/getCustomerData?id=0987654321')
.end(function(err, res){
res.should.have.status(200);
res.body.should.be.a('object');
res.body.status.should.equal("success");
res.body.data.customerId.should.equal("0987654321");
done();
});
});
});
Currently this code is fetching data from database but i want Unit testing using mock data. How can i achieve this?
__EDIT__
I want to test the code which is written inside Express js routes file. this routes i am calling inside app.js file like this
var customers = require('./routes/customers');
app.use('/customers', customers);
now the code which customers route file contain is
function getCustomerData(req, res, next) {
var response = {};
var cb = function (response) {
res.send(response);
}
var modelObj = req.models.customer_master;
var data = req.query;
controllers.customers.get(modelObj, data, cb);
};
router.get('/getCustomerData', function (req, res, next) {
getCustomerData(req, res, next);
});
I want to test the response of "get" method using mock data
You want to stub your controller middlewares i guess. As you didn't provide any server side code, i just asume some things:
app.get('/', rootController.get);
Now you want to stub this controller:
it('responds to /', function testSlash(done) {
const rootController = require('./path/to/your/controller');
const rootControllerStub = sinon.stub(rootController, "get",
function(req, res, next){
res.status(200).json({stubbed: 'data'});
});
request(server)
.get('/')
.expect(200)
.expect({stubbed: 'data'})
.end(done);
});
If you wish to mock, you can use sinon express mocks here or if you want to test the actual response data, JSON, use this example
The express route, in the example, takes a parameter and returns a JSON
it('should respond with JSON data', function (done) {
request(server)
.get('/about/jv')
.expect(200)
.end(function (err, response) {
assert.equal(response.header['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(response.body, {
"data":{
"username":"hellojv"}
});
done();
});
but as mentioned above, if you want to use sinon then use the mock library. The example uses Mocha and supertest.
Additionaly, if you write many test files, the stub may not work because of cache. I have to clear cache before initializing the stub and the server. The order is also important.
// have to clear every module which belongs to the require chain
// APP require FOO ROUTE require FOO CONTROLLER require BAR LIB
const caches = [
'../app',
'../routes/foo',
'../controller/foo',
];
caches.forEach(cache => {
delete require.cache[require.resolve(cache)];
});
// mock
const bar = require('../lib/bar');
sinon.stub(bar, 'bar').callsFake(async function() {
return null;
});
app = require('../app');
// ... then the test ...
I found this thread helpful.

Resources