How to start/stop NodeJS server only once when running test suites - node.js

I'm writing selenium test suites for NodeJS. Here's one sample test file:
var Sails = require('sails');
// create a variable to hold the instantiated sails server
var app;
var client;
// Global before hook
before(function(done) {
// Lift Sails and start the server
Sails.lift({
log: {
level: 'error'
},
environment: 'test',
port: 1338
}, function(err, sails) {
app = sails;
done(err, sails);
});
});
// Global after hook
after(function(done) {
app.lower(done);
});
beforeEach(function(done) {
client = require('webdriverjs').remote({desiredCapabilities:{browserName:'chrome'}});
client.init(done);
});
afterEach(function(done) {
client.end(done);
});
describe("Go to home page", function() {
it('should work', function(done) {
client
.url('http://localhost:1338/')
.pause(5000)
.call(done);
});
});
Currently:
Starting each test file, it boots up the Sails server
Finishing each test file, it shutdowns the Sails server
Starting each test, it boots up the browser
Finishing each test, it closes the browser
Therefore, if I have 10 selenium test files, it will boot/shutdown the Sails server 10 times. Is there any way to boot up the Sails server only once, running all test files, then shut it down?
I'm using Sails + Mocha + webdriverjs stack. Here's my Makefile config
test:
#./node_modules/.bin/mocha -u bdd -R spec --recursive --timeout 15000
.PHONY: test

One possible solution is to switch to using npm test, store your test execution line in your package.json file, and then take advantage of the pretest and posttest script phases. Within these commands you could execute a script which will start up your server (startSailsServer.js), and shutdown your server, respectively. You could then take out the starting and stopping of your server in each test file.
So your package.json would have something like this (you would have to move the start/stop sails server logic to these startSailsServer.js and stopSailsServer.js files):
"scripts": {
"pretest": "node startSailsServer.js",
"test": "./node_modules/.bin/mocha -u bdd -R spec --recursive --timeout 15000",
"posttest": "node stopSailsServer.js"
}
Then to run your tests, you would execute npm test

Thanks for dylants suggestion, I edited the Makefile to utilize the "pre/post-test" script phases:
## Makefile
test:
/bin/bash test/script/startServer.sh
#./node_modules/.bin/mocha -u bdd -R spec --recursive --timeout 15000
/bin/bash test/script/stopServer.sh
## test/script/startServer.sh
# Start Selenium
start-selenium &
echo $! > tmp/selenium.pid
sleep 1
# Start Node server
NODE_ENV=test PORT=1338 node app.js &
echo $! > tmp/test.pid
## test/script/stopServer.sh
kill -SIGINT $(cat tmp/selenium.pid)
kill -SIGINT $(cat tmp/test.pid)

Related

Running Sequelize Migration and Node Server in Same Command Won't Start Server Up

If I try to run my sequelize migrations and then run my Node server in the same command, I run into the issue of my server never starting up. If the migrations have already been run before, the sequelize db:migrate command doesn't go past the "No migrations were executed, database schema was already up to date." message, and my second command is never able to run. If the migration has not run before, everything runs properly in sequence.
This is my npm start command: sequelize db:migrate && node index.js
I assume that internally sequelize db:migrate is not resolving anything in the case where this log message is shown, so is there a way I can "terminate" this command after some time and proceed to my node command?
For anyone else running into this issue, this is how I ended up solving it.
1) Create a new file that you will run in your npm script.
2) I ended up wrapping the process call in a child_process exec, and then terminated the process when I received the above console.log message since the library itself does not resolve anything at this point.
// myRuntimeFile.js --> Make sure this file is in the same directory where your .sequelizerc file lives
(async()=> {
const { exec } = require('child_process');
await new Promise((resolve, reject) => {
const migrate = exec(
'sequelize db:migrate',
{ env: process.env },
(err, stdout, stderr) => {
resolve();
}
);
// Listen for the console.log message and kill the process to proceed to the next step in the npm script
migrate.stdout.on('data', (data) => {
console.log(data);
if (data.indexOf('No migrations were executed, database schema was already up to date.') !== -1) {
migrate.kill();
}
});
});
})();
Obviously the above code is not ideal, but hopefully this is just temporary until the internals of this edge case are resolved properly in a promise.
3) Update your npm script with the following:
"start": "node myRuntimeFile.js && node index.js"
Or if you are running on a Windows machine and cannot use &&, you can use the npm-run-all library.

docker > run two nodejs scripts using gulp and nodemon

I'm trying whole day to find some solution how to run two scripts written in nodejs parallel in docker.
I've two files:
app/index.js - express app using port 8080
app/rabbit.js - script is connection to rabbitmq only as consumer and processing messages
I'm trying to use gulp and nodemon ( I've found solution on the stackoverflow, but id doesn't work )
var gulp = require('gulp')
var gulputil = require('gulp-util');
var child_process = require('child_process');
var nodemon = require('gulp-nodemon');
var processes = {server1: null, server2: null};
gulp.task('start:server', function (cb) {
processes.server1 = nodemon({
script: "app/index.js",
ext: "js"
});
processes.server2 = nodemon({
script: "app/rabbit.js",
ext: "js"
});
cb(); // For parallel execution accept a callback.
// For further info see "Async task support" section here:
// https://github.com/gulpjs/gulp/blob/master/docs/API.md
});
process.on('exit', function () {
// In case the gulp process is closed (e.g. by pressing [CTRL + C]) stop both processes
processes.server1.kill();
processes.server2.kill();
});
gulp.task('run', ['start:server']);
gulp.task('default', ['run']);
This is always runs second script "app/rabbit.js" twice. I'm open to any solution, but I need to run two nodejs script at once in one docker instance.
Any Ideas?
Thanks in advance!
For anyone who will have same problem, I've found solution.
Step 1:
Create two docker files Dockerfile-api, Dockerfile-messages
As command RUN in the dockerfile use
a. CMD ["npm", "run", "start-api"]
b. CMD ["npm", "run", "start-messages"]
Step 2:
In the package.json add lines:
"scripts": {
"start-api": "gulp --gulpfile app/gulpfile-api.js",
"start-messages": "gulp --gulpfile app/gulpfile-messages.js"
}
Step 3:
Obviously create two gulp files, each gulp file will have his own script.
Step 4:
Create two services in docker-compose.yml file each witch different DockerFile
Step 5:
Run docker-compose up

How to run mocha tests and node in a single npm test command ? (CI)

I want to use Circle CI to integrate a git project.
I'm using mocha for my tests .
What i want to do?
When running npm test I want:
my node server to start
my test file to run
How can I run a single npm test command to run both node and my mocha tests which are already wrapped in a single index.js file.
I have tried this in my package.json:
"scripts": {
"test": "node server/app.js & mocha server/tests/index.js",
"start": "node server/app.js",
"postinstall": "bower install"
}
The problems with the above
My server takes some time to start and the tests fail since they run before the server starts
Is there a standard way to run a server and the tests with a single command but I'm missing something?
If it is possible at all in your case I'd suggest using something like supertest to do the testing. This way, you can avoid having to start a server before starting the test.
I understand that there are scenarios where using supertest is not possible. In such case, you could poll your server in a before hook before all tests to wait until it is ready:
before(function (done) {
// Set a reasonable timeout for this hook.
this.timeout(5000);
function check() {
if (serverIsReady()) {
done();
return;
}
// The server is no ready, check again in 1/10th of a second.
setTimeout(check, 100);
}
check(); // Start checking.
});
I'm not sure what serverIsReady should be precisely in your case. It could be an attempt at getting a trivial path from your server like issuing a GET on the path /.
I think the key is to run your node server in your test, rather than trying to initialise it in another process.
Your mocha test should start with a require to your app, then each
of your tests can interact with it.
For example:
var http = require('http');
var server = http.createServer(function(req, res){
res.end('Hello World\n');
})
server.listen(8888);
describe('http', function(){
it('should provide an example', function(done){
http.get({ path: '/', port: 8888 }, function(res){
expect(res).to.have.property('statusCode', 200);
done();
})
})
})
What I do when running a test that needs certain pre-requisites is use mochas beforeEach() functionality.
From the documentation
You may also pick any file and add “root”-level hooks. For example, add beforeEach() outside of all describe() blocks. This will cause the callback to beforeEach() to run before any test case, regardless of the file it lives in (this is because Mocha has an implied describe() block, called the “root suite”).
beforeEach(function() {
console.log('before every test in every file');
});
In the before each code block you can run your command to start the server
using for example the exec library from npm
https://www.npmjs.com/package/exec
This will ensure your server is running before your tests are run allowing you to simply run npm test.

Auto reloading a Sails.js app on code changes?

Currently is seems that for any code change in a sails.js app you have to manually stop the sails server and run sails lift again before you can see the changes.
I was wondering if there is any way when running in development mode to automatically restart the sails server when it detects a code change?
You have to use a watcher like forever, nodemon, or something else...
Example
Install forever by running:
sudo npm install -g forever
Run it:
forever -w start app.js
To avoid infinite restart because Sails writes into .tmp folder, you can create a .foreverignore file into your project directory and put this content inside:
**/.tmp/**
**/views/**
**/assets/**
See the issue on GitHub:
Forever restarting because of /.tmp.
You can use sails-hook-autoreload
Just lift your app as normal, and when you add / change / remove a model or controller file, all controllers and models will be reloaded without having to lower / relift the app.
For example with nodemon to watch api and config directories
.nodemonignore contents
views/*
.tmp/*
.git/*
Run the command after creating .nodemonignore
$> nodemon -w api -w config
Example for supervisor to ignore 3 directories
$> supervisor -i .tmp,.git,views app.js
If you're using Sails 0.11, you can install this hook to automatically reload when you change models or controllers (views do not require reloading):
npm install sails-hook-autoreload
https://www.npmjs.com/package/sails-hook-autoreload
install nodemon globally or locally.
npm install nodemon --save
npm install nodemon -g
install sails locally in you project as follows
npm install sails --save
then change package.json
from
"scripts": {
"debug": "node debug app.js",
"start": "node app.js"
},
to
"scripts": {
"debug": "node debug app.js",
"start": "node app.js",
"dev": "export NODE_ENV=development && nodemon --ignore 'tmp/*' app.js && exit 0"
},
then
npm run dev
I had the same problem and I have solved it using grunt-watch and grunt-forever with sails#beta tasks. The result is 4 grunt commands:
UPDATE: tasks are available in the current sails version (it's no longer beta :>)
start Starts the server
stop Stops the server
restart Restarts the server
startWatch Starts the server and waits for changes to restart it (using grunt-watch). This is probably your solution, but the other commands are also useful.
Here's the code - I'm using sails#beta, which includes a tasks directory, I don't know if this is included in previous versions:
First of all you have to install forever in your sails directory:
npm install grunt-forever --save-dev
tasks/config/forever.js Configure forever task.
module.exports = function(grunt) {
grunt.config.set('forever', {
server: {
options: {
index: 'app.js',
logDir: 'logs'
}
}
});
grunt.loadNpmTasks('grunt-forever');
};
tasks/config/watch.js (edit) Edit watch task in order to add a new rule
// api and assets default rules
,
server: {
// Server files to watch:
files: [
'api/**/*',
'config/**/*'
],
// Restart server
tasks: ['forever:server:restart']
}
tasks/register/watchForever.js Register your custom tasks (this file can be renamed to whatever you want)
module.exports = function(grunt) {
// Starts server
grunt.registerTask('start', [
'compileAssets',
'linkAssetsBuild',
'clean:build',
'copy:build',
'forever:server:start'
]);
// Restarts the server (if necessary) and waits for changes
grunt.registerTask('startWatch', [
'restart',
'watch:server'
]);
// Restarts server
grunt.registerTask('restart', [
'forever:server:restart'
]);
// Stops server
grunt.registerTask('stop', [
'forever:server:stop'
]);
};
With this you should be able to use
grunt startWatch
and make your server wait for changes to be restarted :>
Hope this helped!
Better you use
npm install -g nodemon
i am using this, and it will helps to improve my developing speed. no need to edit any files for this one!.
after installation
nodemon app.js
For anyone coming to this question now, it seems that this is no longer necessary - an application launched with sails lift will have a grunt watch task running, and code changes will be visible without a restart.
I didn't realise this was happening at first because there's nothing to indicate what's happening in the console, but it does seem to work without a restart (I'm using Sails 0.11)

How to test nodejs backend code with Karma (testacular)

How do I setup Karma to run my backend unit tests (written with Mocha)? If I add my backend test script to the files = [], it fails stating that require is undefined.
You don't. Karma is only for testing browser-based code. If you have a project with mocha tests on the backend and karma/mocha on the front end, try editing your package.json under scripts to set test to: mocha -R spec && karma run karma.con
Then, if npm test returns true, you'll know it's safe to commit or deploy.
It seems like it cannot be done (thanks #dankohn). Here is my solution using Grunt:
Karma: update your karma.conf.js file
set autoWatch = false;
set singleRun = true;
set browsers = ['PhantomJS']; (to have inline results)
Grunt:
npm install grunt-contrib-watch grunt-simple-mocha grunt-karma
configure the two grunt tasks (see grunt file below)
Gruntfile.js:
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-simple-mocha');
grunt.loadNpmTasks('grunt-karma');
grunt.initConfig({
simplemocha: {
backend: {
src: 'test/server-tests.js'
}
},
karma: {
unit: {
configFile: 'karma.conf.js'
}
}
});
// Default task.
grunt.registerTask('default', ['simplemocha', 'karma']);
};
Grunt (optional): configure grunt-watch to run after changing spec files or files to be tested.
run all using grunt command.

Resources