I'm trying to setup tests for a REST API made with Express and MongoDB. I want to use mocha, chai and chai-http but I'm getting a strange behavior, it seems that the beforeEach function it's exceeding the timeout like it's never being resolved. How could i fix this?
//During the test the env variable is set to test
process.env.NODE_ENV = 'test';
let mongoose = require("mongoose");
let User = require('../models/User');
//Require the dev-dependencies
let chai = require('chai');
let chaiHttp = require('chai-http');
let app = require('../app');
let should = chai.should();
chai.use(chaiHttp);
//Our parent block
describe('Users', function () {
beforeEach(function (done) { //Before each test we empty the database
User.remove({}, function (err) {
done();
});
});
/*
* Test the /GET route
*/
describe('/GET users', function () {
it('it should GET all the users', function (done) {
chai.request(app)
.get('/users')
.end(function (err, res) {
res.should.have.status(200);
res.body.should.be.a('array');
res.body.length.should.be.eql(0);
done();
});
});
});
});
Assuming your connection is working correctly and its only a timeout issue you need to extend the timeout to something beyond the default (2000ms) with the this.timeout() function. For example, adding this.timeout(10000) inside the beforeEach function would set the timeout to 10 seconds which should give your User.remove call more time to complete.
Here is an example in this SO answer: How to set timeout on before hook in mocha?
Related
I read a lot of answers to similar questions already but can't figure out what is wrong in my code.
this is my server.js file
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
app.use(require('koa-bodyparser')())
const login = (ctx, next) => {
ctx.body = ctx.request.body
}
const router = new Router({ prefix: '/api' })
router.get('/test', (ctx, next) => {
ctx.body = { resp: 'GET REQUEST /test WORKING' }
})
router.post('/login', login)
app.use(router.routes())
module.exports = app
this is my index.js file
const server = require('./server')
server.listen(3000, () => {
console.log('App is running on http://localhost:3000')
})
and this is my mocha test file
const axios = require('axios').default
const expect = require('chai').expect
const app = require('./server')
describe('7-module-3-task', () => {
describe('test', function () {
let server
before(done => {
server = app.listen(3000, done)
})
after(async () => {
server.close()
})
it('should return response from server', async () => {
const response = await axios.get('http://localhost:3000/api/test')
expect(response.data, 'should return object with key "resp').to.have.property('resp')
})
})
})
It's working okay when I make a request in Postman. I tried multiple options already but I still get 404 response, as I understand test is performed before server started running...? How can I make it working ?
First, I would move the startup (app.listen) directly into the server.js (not critical, but maybe more simpler because the require in your test would then already start your server:
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
app.use(require('koa-bodyparser')())
const router = new Router({ prefix: '/api' })
router.get('/test', (ctx, next) => {
ctx.body = { resp: 'GET REQUEST /test WORKING' }
})
app.use(router.routes())
app.listen(3000); // can be a parameter but for simplicity hardcoded here
module.exports = app
In your test you then do:
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('./server'); // this will already start up your server
describe('API Tests', () => {
describe('TEST endpoint', () => {
it('It should GET response from test endpoint', (done) => {
chai.request('http://localhost:3000')
.get('/api/test/') // be sure to have a trailing '/' !!
.end((err, res) => {
res.body.should.have.property('resp');
done();
});
})
});
});
One more hint: maybe in your original code you just have to make sure, that you have a trailing / when calling your route in the test.
Code snippets not testet but I hope you get the idea.
I shared the same code with 2 of my friends and they managed to run tests successfully.
I tested it on my other laptop after this and tests worked as well.
The problem was in the port. 3000 port was used as a default one in the debugger in Webstorm, not sure why but still.
Launching the server on port 3000 in a regular way, not in mocha tests, worked very well but in tests, it did not work, not sure why.
So for those who ever face something similar, check the default port of the debugger or any other built-in server.
I am testing an nodejs-app with a server and a client component on nodejs 8.9 with mocha.
For mocha to end properly, I have to make sure that all socketio and http-servers are closed after the tests have been run. This works fine with normal tests, but as soon as I register a middleware to the socketio-server, the mocha-process won't close and stay open forever.
Testcode (comment in the second test to see the problem, run via mocha test.spec.js):
// test.spec.js
'use strict'
const Express = require('express')
const Http = require('http')
const ioserver = require('socket.io')
const ioclient = require('socket.io-client')
const NODE_PORT = process.env.NODE_PORT || 3000
describe('Client', function () {
beforeEach(() => {
const express = new Express()
this._http = Http.Server(express)
this._ioserver = ioserver(this._http)
this._http.listen(NODE_PORT)
})
// this test works perfectly, even when I copy it and run it
// multiple times in this suite
it('should connect to a socketio-server', (done) => {
this._ioserver.on('connection', () => {
client.close()
done()
})
const client = ioclient.connect(`http://localhost:${NODE_PORT}`)
})
// this test also finished, but the suite hangs afterwards - as if
// a socket-client or socket-server was not closed properly.
it('should finish the test suite even with a middleware', (done) => {
this._ioserver.use((socket, next) => {
return next()
})
this._ioserver.on('connection', () => {
client.close()
done()
})
const client = ioclient.connect(`http://localhost:${NODE_PORT}`)
})
afterEach(() => {
this._ioserver.close()
this._http.close()
})
})
Any ideas why that happens?
So, the problem was, that the server closed the client connection on a successful connection event. The client did not get any information on that, but instead saw a failed connection and tried to reconnect. This opened a socket to the server again and because the server was already closed, the connection error kept coming.
This behavior stopped node from properly destroying all objects, which in turn explaines the hanging. The solution is to call done() only after the client has declared a connection open, not after the server has declared a connection open like so:
'use strict'
const Express = require('express')
const Http = require('http')
const ioserver = require('socket.io')
const ioclient = require('socket.io-client')
const NODE_PORT = process.env.NODE_PORT || 3000
describe('Client', function () {
beforeEach(() => {
const express = new Express()
this._http = Http.Server(express)
this._ioserver = ioserver(this._http)
this._http.listen(NODE_PORT)
this._client = null
})
it('should connect to a socketio-server', (done) => {
this._ioserver.on('connection', () => {
done()
})
this._client = ioclient.connect(`http://localhost:${NODE_PORT}`)
})
it('should finish the test suite even with a middleware', (done) => {
this._ioserver.use((socket, next) => {
return next()
})
this._client = ioclient.connect(`http://localhost:${NODE_PORT}`)
// if we wait for the server and kill the server socket,
// the client will try to reconnect and won't be killed
// by mocha.
this._client.on('connect', () => {
done()
})
})
afterEach(() => {
// this last call forces the client to stop connecting
// even if tests failed
this._client.close()
this._ioserver.close()
this._http.close()
})
})
I am testing some get and post apis of my node js application using mocha and chai. So far, I have been running it in my localserver and the sample code for each of post and get api is given below :
process.env.NODE_ENV = 'test';
var mongoose = require("mongoose");
var db_model = require('../models/myproject.model');
var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('../app');
var should = chai.should();
var expect = chai.expect;
chai.use(chaiHttp);
describe('First POST', ()=> {
it('This is the first post', (done) => {
chai.request(server)
//chai.request('http://localhost:8000') //this also works
.post('/data/myproject')
.send(db_model)
.end((err, res) => {
//expect(true).to.be.true;
expect(res.statusCode).to.equal(200);
done();
});
});
});
describe('First GET', () => {
it('This is the first get', (done)=> {
chai.request(server)
.get('/data/myproject')
.end((err, res) => {
//expect(true).to.be.true;
expect(res.statusCode).to.equal(200);
done();
});
});
});
Now, I need to run the above code from the actual server i.e http://myproject.webportal.com
My POST request will be passed following parameters :
1. id = "any_numeric_id"
2. name = "some_name"
3. authentication (username, password) is required.
4. content = {"k1":"v1", "k2", "v2"} // basically json data
My GET request for the same will be having only #1, #2 and #3 of the above list.
Basically when I fire this url manually in the browser it looks like :
http://myproject.webportal.com/data/myproject?id=405&name=smith
How do I need to change my code to fit this requirement, I have gone through several links about this but getting confused and not able to get the result.
Can anybody please help me on this coding to give me a fair idea on how to do it properly?
Thanks.
I'm working on a project where I need to serve both HTTP requests to an API and handle users communicating to each other through sockets (I'm using Socket.io for that purpose). The code of my server.js file is as follows:
let initHttpServer = () => {
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(require('./routes'));
app.get('/config.js', function(req,res) { res.write("var ROOT_URL='"+process.env.ROOT_URL+"'" + '\n'); res.end(); });
http.listen(port, function() {
console.log('express listening on port' + port);
console.log('a user connected');
});
return app;
}
.
.
.
conn.once('open', function() {
initHttpServer();
});
module.exports = initHttpServer;
I also have a io.on('connect'...) function, but for the sake of brevity I'm not posting it here (at least yet).
It works fine when I do tests with Postman, but I'm having trouble testing the HTTP endpoints with mocha and Chai. The code I have for testing now is the following:
chai.use(chaiHttp);
it('should get votes', function(done) { // <= Pass in done callback
chai.request('http://localhost:3000')
.get('/vote')
.then(function(res) {
res.should.have.status(200);
})
.catch(function(err) {
throw err;
});
});
When I run npm test, I get the following error:
Error: Timeout of 10000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
I've tried putting my test function inside a try/catch block as follows:
it('should return all votes on /votes', function(done) {
try{
chai.request('http://127.0.0.1:3000')
.get('/vote')
.end(function(req,res) {
res.should.have.status(787432189700);
done();
});
--> done();
} catch(error) {
done(error);
}
});
If I take the done(); call I indicated with an arrow (-->), I get the aforementioned error, but if I keep it it just returns success without ever testing anything. I'm assuming that it is an asynchronous call, so done() is called before the testing finishes. Therefore, I have no clue on how to proceed. What should I do to test the API endpoints?
Thank you!
First:
Your try/catch block will not work, you are making an async call.
Second
Most probably is that in this line: res.should.have.status(787432189700); there is an error, so the done is not been executed.
Try something like this:
let chai = require('chai')
, chaiHttp = require('chai-http');
const expect = require('chai').expect;
chai.use(chaiHttp);
describe('Some test', () => {
it('Lets see', (done) => {
chai.request('http://localhost:3000')
.get('/vote')
.end(function (err, res) {
expect(err).to.be.null;
expect(res).to.have.status(200);
done();
});
});
});
Please observe the first parameter on the callback function is the error.
I'm trying to integration- and unit test with Mocha, but Mocha doesn't wait for any callback to be done (or in my case, promise to fulfill)...
One moment when I try to test, the promise get's fulfilled BEFORE the first integration test is done, the other moment it crashes...
server.js
const server = require('./app');
server.listen(process.env.PORT, () => {
console.log('Starting server.');
console.log('Displaying server information:');
console.log(`Host: http://localhost:${process.env.PORT}`);
});
app.js
require('babel/register');
/**
* Make some commonly used directories known to the process env
*/
process.env.ROOT_DIR = __dirname;
/**
* Setup Express server and the Express Router
*/
const express = require('express');
const bodyParser = require('body-parser');
const server = express();
// Parses the body for JSON object in the middleware so extra steps for
// parsing aren't required.
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended: true}));
server.use((req, res, next) => {
console.log('url called', req.originalUrl);
next();
});
// This is the call which has the database set up in it
// This has a few generator functions in 'm
require('./init')(server);
/**
* Export
*/
// Define routes on the server.
module.exports = server;
integration test (which is the first one that gets fired)
import should from 'should';
import supertest from 'supertest';
import server from '../../app';
import co from 'co';
let request = supertest(server); // Set request to context of the app.
describe('Index', function () {
describe('GET /', function () {
it('returns 200', co.wrap(function * (done) {
const res = yield request
.get('/');
res.statusCode.should.equal(200);
}));
});
describe('GET /this_is_not_a_valid_route_123456', function () {
it('returns 404', function (done) {
request
.get('/this_is_not_a_valid_route_123456')
.expect(404, done);
});
});
});
command:
NODE_ENV=test ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- ./test/ --recursive --compilers js:babel/register
Does anyone know how I can fix this?
Screenshot of what happens:
(Init done should be BEFORE the 'Index GET /' and directly after 'Init config repo...')
You can tell mocha to wait.
before(function (done) {
if (server.listening) return done();
server.on('listening', function() { done(); });
});
I'm not sure what's inside your init file but if you also want to wait for other events, you can add multiple before functions.