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!
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 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.
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.
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 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.