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.
Related
I built an API for a couchbase database, using express and node.js. My problem is that when I run my tests some of them fail, because the server is not fully running. I found a solution here https://mrvautin.com/ensure-express-app-started-before-tests on how to solve this issue. The article stated that in order to solve this issue, you have to add an event emitter in your server file like this
app.listen(app_port, app_host, function () {
console.log('App has started');
app.emit("appStarted");
});
and then add this, in your test file
before(function (done) {
app.on("appStarted", function(){
done();
});
});
I have tried this, here is my implementation
Server File
app.listen(config['server']['port'], function(){
app.emit("appStarted");
logger.info("Listening")
})
Test File
before(function(done){
app.on("appStarted", function(){
done();
})
});
I keep on getting the following error
1) "before all" hook in "{root}":
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7)
The article is from 2016, so I was thinking that maybe the syntax has been deprecated. I was wondering if someone could please help point me in the right direction?
You can add the below condition, more info see "Accessing the main module".
if (require.main === module) {
// this module was run directly from the command line as in node xxx.js
} else {
// this module was not run directly from the command line and probably loaded by something else
}
E.g.
index.ts:
import express from 'express';
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.sendStatus(200);
});
if (require.main === module) {
app.listen(port, () => {
console.log('App has started');
});
}
export { app, port };
index.test.ts:
import { app, port } from './';
import http from 'http';
import request from 'supertest';
describe('63822664', () => {
let server: http.Server;
before((done) => {
server = app.listen(port, () => {
console.log('App has started');
done();
});
});
after((done) => {
server.close(done);
console.log('App has closed');
});
it('should pass', () => {
return request(server)
.get('/')
.expect(200);
});
});
integration test result:
(node:22869) ExperimentalWarning: The fs.promises API is experimental
63822664
App has started
✓ should pass
App has closed
1 passing (26ms)
!Hi World! My little solution here:
Check this: All depends of your testing markup...
For example, I'm using Mocha and Chai Assertion Library.
const express = require('express');
const request = require("request");
const http = require("http");
const expect = require("chai").expect;
require('dotenv').config();
describe('Server', function() {
const { PORT } = process.env;
const app = express();
before((done) => {
http.Server = app.listen(PORT, () => {
console.log(`Listening Node.js server on port: ${PORT}`);
done();
});
});
it('should return 404 response code status', () => {
const url = `http://localhost:${PORT}/api/v1/yourPath`;
return request(url, (err, response, body) => {
/* Note this result 'cause I don't have any get('/')
controller o function to return another code status
*/
expect(response.statusCode).to.equal(404);
});
})
});
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?
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.
Im just getting started with Mocha, testing against a very basic Express 4.0 rest API.
describe('API CALL UNIT TESTING', function(){
var app = require('../../app');
before(function(){
app.listen(3000);
});
describe('GET', function(){
it('respond with json', function(done){
request(app)
.get('/api/compile')
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json')
.expect(200, done)
.end(function(e, res){
//console.log(res)
done();
})
})
});
after(function() {
app.close();
});
});
Im getting the following error when running the test:
1 passing (48ms) 1 failing
1) API CALL UNIT TESTING "after all" hook:
TypeError: Object function (req, res, next) {
app.handle(req, res, next); } has no method 'close'
Can anyone advise what is causing the "after all" hook error?
Clearly the app object does not have a close() method. You don't actually tell us precisely what app is - but if I recall the express API correctly, you actually call the close() on the object returned from listen(), so perhaps you could try:
var server;
before(function(){
server = app.listen(3000);
});
....
after(function() {
server.close();
});
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!