Is there a way to unit test Express / Loopback middleware without actually creating a server and listening on a port?
The problem I have is that creating multiple servers in my test code will introduce the problem of port conflicts.
You can use the supertest module.
You may pass an http.Server, or a Function to request() - if the server is not already listening for connections then it is bound to an ephemeral port for you so there is no need to keep track of ports.
Mocha
An example with mocha
var request = require('supertest');
var app = require('path/to/server.js');
describe('GET /user', function() {
it('respond with json', function(done) {
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
Ava
Also, you might be interested in the ava test runner instead of mocha.
Main reason : process isolation between test files
This is usually my test file template with ava
var describe = require('ava-spec').describe;
var app = require('path/to/server.js');
var request = require('supertest');
describe("REST API", function(it){
it.before.cb(function(t){
request(app)
.post('/api/Clients/')
.send({
"username": "foo",
"password": "bar"
})
.expect(200, function(err, res){
t.end(err);
});
});
it.serial.cb('Does something',
function(t){
request(app)
.get(//..)
.expect(404, function(err, res){
if (err) return t.end(err);
t.end();
});
});
it.serial.cb('Does something else afterward',
function(t){
request(app)
.get(//..)
.expect(401, function(err, res){
if (err) return t.end(err);
t.end();
});
});
});
The serial identifier tells ava to run the it clause serially. Otherwise it will run all tests from all files in parallel.
Thanks to process isolation, each test file gets its own, isolated loopback instance (and node environment in general), and all test files can be run in parallel, which speeds up tests as well. Inside each test file however, using serial, tests will run one after another, in the order they are written in the file.
Related
I am using Mocha + Chai + chai-http to test my server application. The thing is, it needs to do some stuff (mostly DB writes) before actually starting the server. And that crashes my tests, because the tasks that are needed to be run before the server startup are not executed yet. Here's the code that I'm using:
// server declaration, it's just a restify server
(async () => {
await cron.scanDB();
await user.updateEventRoles();
console.log('started');
server.listen(config.port, () => {
log.info('Up and running, %s listening on %s', server.name, server.url);
});
})();
...
module.exports = server;
And in tests:
chai.request(server)
.get('/single/' + eventRes.body.data._id + '/organizers')
.set('X-Auth-Token', 'foobar')
.end((err, res) => {
// some actual tests
What can I do to wait for the server to start before running tests?
The problem is that your server.listen is wrapped in an async function and chai-http does not know to wait for that. One thing you can do is use an event emitter and emit after the server is started.
Then at the top of your test create a before with an async function that returns a new promise that resolves when it receives the server started event.
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 am using MOCHA to test some express framework code.
I have written a simple MOCHA code to test messages returned in the response header. The code works. It also means that I am connected to the server and I can get the file from the database.
Now, I want to use "SuperTest" to do the same thing. But, I get "Error: connect ECONMREFUSED"
Here is my code:
var express = require('express');
var request = require('supertest');
var app = express();
describe('GET /core/dbq/534e930204dd311822ec1c9d', function() {
this.timeout(15000);
it ('Check header message', function(done) {
request(app)
.get('http://localhost:3001/ecrud/v1/core/dbq/534e930204dd311822ec1c9d')
.expect('warning', '100 Max Record Limit Exceeded')
.expect('Content-Type', /json/)
.expect(200, done);
} )
} )
and the error showing on the console is:
1) GET /core/dbq/534e930204dd311822ec1c9d Check header message:
Error: connect ECONNREFUSED
at errnoException (net.js:901:11)
at Object.afterConnect [as oncomplete] (net.js:892:19)
I am learning to use "SuperTest". Please help. Thank you.
Supertest starts the application on a random port and fills the host+port part of the URL for you. Your code should supply the path (and query) part only.
request(app)
.get('/ecrud/v1/core/dbq/534e930204dd311822ec1c9d')
// etc.
.expect(200, done);
Alternatively, you can start the application yourself before running the test.
describe('GET /core/dbq/534e930204dd311822ec1c9d', function() {
this.timeout(15000);
before(function(done) {
app.listen(3001, function() { done(); });
});
it ('Check header message', function(done) {
request(app)
.get('http://localhost:3001/ecrud/v1/core/dbq/534e930204dd311822ec1c9d')
// etc.
});
});
I would highly recommend going with the first approach, otherwise your tests may clash with other applications listening on port 3001.
I'm having some issues testing routes using ExpressJS + BusterJS + SuperTest.
var app = require("../../app/app.js"),
buster = require("buster"),
expect = buster.referee.expect,
http = require('http'),
request = require('supertest');
buster.spec.expose();
describe("V2 API - group/get", function () {
var server;
beforeEach(function() {
server = http.createServer(app).listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
});
it("is accessable", function() {
request(server)
.get('/')
.expect(200)
.end(function(err, res){
server.close();
expect(err).toBe(null);
});
});
});
When I run this test, I get:
Failure: V2 API - group/get is accessible
No assertions!
1 test, 0 assertions, 1 runtime ... 1 failure
Express server listening on port 3000
Which seems wrong, because I actually do have an assertion. The problem is that it doesn't get called unless there is an error.
Another issue is that if I have multiple 'if' blocks, the server doesn't restart between them. I might be using the node + express + buster + supertest stack wrong, so any help with how to test these routes would be greatly appreciated.
I have some code that doesn't have your problem; it does almost the same thing as yours but with asynchronous tests, e.g.
it("is accessable", function(done) {
request(server)
.get('/')
.expect(200)
.end(function(err, res){
server.close();
expect(err).toBe(null);
done();
});
});
I don't know enough about Buster to know if this is the "right way" to fix this issue, but hope it helps!
I am new to Mocha and Chai testing Framework ,i am referring the tutorial here i Understand it and its very Good for beginners but What this tutorial is it get the requests via url and in my condition i want to post and pick those data in my node server i cannot found anything unitl now so help me what are the needs and what are files to install in npm. And please send me the useful Links for Beginners Tutorials. And if may a sample application with node and mocha post requests..
We can also use the chai-http for post requests in Mocha
below is My Solution
var chai = require('chai'), chaiHttp = require('chai-http');
chai.use(chaiHttp);
var app = 'localhost:3000';
describe("Sample Unit Testing", function() {
describe("Get User Data", function() {
it("get The User Employee ID", function(done) {
// Send some Form Data
chai.request(app)
.post('/getUserData')
.send({
password: '3333',
empId: '1111'
})
.end(function (err, res) {
expect(res.EmpId).to.equal("1111");
done();
});
});
});
});
This is the Code I am Looking For and I found out myself
//you must install these two in your node js using npm
var expect = require("chai").expect;
var request = require('superagent');
describe("Name For The Test Suite", function() {
it("Testing Post Request using Mocha", function(done) {
request.post('localhost:8081/yourRequestCatcherName')
.set('Content-Type', 'application/json')
.send('{"fieldName":"data"}')
.end(function(err,res){
//your code to Test
done();
})
});
});
it Works Perfectly in the way What I want.