I have the below NodeJS script, which polls an address for web automation tasks and executes upon receipt. Polling and parsing response is fine, but I'm unsure how to synchronously fire the mocha test runner within the res.on() method:
var express = require('express');
//...
app.set('port', process.env.PORT || 3000);
//...
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
var getTestTaskFromQueue = {
host: 'remotehost',
port: 3000,
path: '/met/my/test',
method: 'GET'
};
setInterval(function() {
var reqGet = http.request(getTestTaskFromQueue, function (res) {
var content;
res.on('data', function (chunk){
content += chunk;
});
res.on('end', function () {
content = JSON.parse(content.substring(9, content.length));
console.info("\nReceived Task:\n");
//run one test via mocha here
});
});
reqGet.end();
reqGet.on('error', function (e) {
console.error(e);
});
}, 10000);
And the test runner currently runs fine from CLI as such:
mocha test/folders/test_script.js --browser "firefox" --param1 foo
I'm evisioning stopping the setInterval loop at mocha execution start time and restarting it from a callback, but how should I execute the actual mocha test - from within the same script or talk to the CLI via subprocess?
You can call mocha.run() to start your test once your environment is ready.
Though, what you search is probably stub and mock objects to prevent your test from interacting with external sources.
Related
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.
I'm pretty new to node. I built a sample express app and wrote some BDD tests for it using cucumber.js. I would like to automate the tests using gulp so that when I run my tests it will first start the express app and, once the server is up, run through the tests. However, currently the tests run before the server is up and therefore all fail. Is there a way to wait (using gulp) for the server to start and only then run the tests?
I'm using gulp-cucumber and gulp-express here (somewhat hidden by gulp-load-plugins).
My gulpfile (partial):
var gulp = require('gulp'),
plugins = require('gulp-load-plugins')();
gulp.task('server', function () {
plugins.express.run(['bin/www']);
});
gulp.task('cucumber', ['server'], function() {
return gulp.src('features/*').pipe(plugins.cucumber({
'steps': 'features/steps/*.steps.js',
'support': 'features/support/*.js'
}));
});
gulp.task('test', ['server', 'cucumber']);
I have to use this solution - https://www.npmjs.com/package/run-sequence
var gulp = require('gulp'),
plugins = require('gulp-load-plugins')(),
runSequence = require('run-sequence');
gulp.task('server', function () {
plugins.express.run(['bin/www']);
});
gulp.task('cucumber', function() {
return gulp.src('features/*').pipe(plugins.cucumber({
'steps': 'features/steps/*.steps.js',
'support': 'features/support/*.js'
}));
});
gulp.task('test', function(){
runSequence('server', 'cucumber');
});
I have a server.js module that exports a start() function to start my server.
I require this module and start the server from index.js.
I'm trying to unit test the server.js module in isolation (with Mocha) by starting the server in a child_process.fork call but I don't see how to call the exported start function.
It's currently working by passing 'index.js' to the fork call but then I don't see how to pass options through to the server.js module (sending a port number for example).
Here's my server.js and the unit test that uses index.js (which only requires and calls server.start()).
I'd like to test server.js directly so I can pass environment variables to it.
====EDIT====
I'm not sure what I thought I would gain by starting the server in a separate process.
I've changed the test to just start the server in the before block.
Suggestions welcome.
var assert = require("assert");
var request = require("request");
describe("Server", function(){
var server;
var port = 4008;
before(function(done){
server = require("../server");
server.start(port);
done();
});
it('listens on specified port (' + port + ')', function(done){
request('http://localhost:' + port, function(err, res, body){
assert(res.statusCode == 200);
done();
});
});
});
You may want to use the cluster module for this, which makes handling processes a little simpler. The following may be along the lines of what you need.
var cluster = require('cluster');
// Runs only on the master process.
if (cluster.isMaster) {
var environmentVariables = { PORT: 2020 };
var worker = cluster.fork(environmentVariables);
// Catch a message from the worker, and then destroy it.
worker.on('message', function(message) {
if (message.hasOwnProperty('testResult')) {
// Kill the worker.
worker.destroy();
// Then do something with the result.
}
});
}
// Runs only on a worker process.
if (cluster.isWorker) {
var server = require('./server');
server.start();
// Do some stuff for tests.
// Send the test result.
process.send({ testResults: 'pass', failReason: null });
}
I haven't tested this, but hopefully the gist is clear. You can pass in custom environment variables when the worker process is spawned, and then have the worker process message the master with the result. You probably need to handle exit events and a time out for when the worker crashes or hangs up.
As an aside, you should probably be wrapping the process.env.PORT in a parseInt.
I'm trying to create a standalone test suite using mocha, that in a perfect world would start up my express.js application, use zombie to render a page, check a bunch of stuff and then teardown/kill the express.js application.
Is there an easy/best way to do this?
NB. I could just have the express application server running prior to running the tests, but what good are Yaks if you're not going to shave them.
First, you need to move your actual app setting up into a module, and import that into the file that actually starts your app. Now that this is seperate, you can have the app in its complete state before actually listening.
You should move the actual setting up of your app into a separate file, let's call it app.js, can call listen from the file you run node off of, let's call it index.js.
So, app.js would look like:
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
and index.js would look like:
var app = require('./app');
app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
This seperates loading of your app from actually having it listen, allowing you to load that app into your unit tests.
In your unit tests, you would do something in a setup method and teardown method to bring up and bring down the server.
In the file test/app_tests.js:
describe('app', function(){
var app = require('../app');
beforeEach(function(){
app.listen(3000);
});
// tests here
afterEach(function(){
app.close();
})
});
In addition to Oved D answer.
Describe your app in express-app.js or some other file:
module.exports = function (o) {
o = o || {};
var app = express();
// app.configure
// configure routes
if (o.someOption) {
// some additional test code
}
return app;
}
describe tests in test/01-some.js:
var expressApp = require('../express-app');
describe('some', function () {
// just describe needed vars
var app, server, port;
// describe setup
before(function (next) {
// create app when
app = expressApp({routes: /api\/some\/.*/ /* put here some test options ...*/});
// creating listener with random port
server = app.listen(function () {
// store port when it ready
port = server.address().port;
// and go to tests
next();
});
});
// tests
it('should return valid result', function (done) {
// do a simple request to /api/some
http.request({
host: 'localhost',
port: port,
path: '/api/some'
}, function (res) {
if (res.err) throw new Error(res.err);
done();
});
});
// teardown
after(function () {
// stop listening that port
server.close();
});
});
Done. ;-)
Now you can create any count of tests like that. Recommend you to enable only needed urls and services in tests with defining it by passing params to express-app.js module.
Update:
Not sure how it works in mocha but better to move before and after calls to init.js and load it with mocha --require init.js.
File should looks like that:
// use it in your mocha tests
global.setupEnv = function setupEnv (o, before, after) {
// just describe needed vars
var env = Object.create(null);
// setup
before(function (next) {
// create app
env.app = expressApp(o);
// creating listener with random port
env.server = env.app.listen(function () {
// store port when it ready
port = env.server.address().port;
env.app.log('Listening on ', env.port);
// and go to tests
next();
});
});
// teardown
after(function () {
// stop listening that port
env.server.close();
});
return env;
}
And in your tests:
// requiring dependencies
var request = require('request');
describe('api', function () {
// describe setup
var env = global.setupEnv({
routes: 'api/some'
}, before, after);
// tests
it('should pass', function (done) {
request('http://localhost:' + env.port, function (error, response, body) {
done();
});
});
});