Start Node server and run test in CICD - node.js

I am currently trying to deploy some tests to Azure pipelines (but this should apply to any CICD framework)
I have an express project, and I am using supertest with mocha to run tests locally and everything is fine.
Now I want to deploy to production, and I want to run the tests in the pipeline before deployment happens.
The thing is that since these tests are running against http, they need a server running.
So, in my pipeline I have
npm install
npm start
npm test
But the thing is that npm test is not running when the server is started, but instead it just hangs in the server running.
Is there a way to start the tests when the server starts? and then stop the server when the tests are finished?
Or is there a better way to achieve all this?

If you're using supertest I would suggest to export the express app for the tests instead of running it as shown in their docs, and then you would only need to run npm install and npm test.
For example:
app.js
const express = require('express');
const app = express();
// Add middlewares
module.exports = app;
test.spec.js
const app = require('../app.js');
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
...

Related

BASH: express command not recognized

I've read other forums on installing express, I have run
npm install express -g on command prompt as admin.
I did this command a few times and restarted my computer multiple times but Express is still not recognized.
Any help is appreciated.
Express isn't a web server; it is a framework for building web servers.
The express package doesn't provide anything directly executable.
The express documentation has a getting started guide.
If you aren't trying to do server-side programming using Node.js and just want an HTTP server, then the http-server package may be more your speed.
Assuming you’ve already installed Node.js, create a directory to hold your application and make that your working directory.
then follow the below command
npm init
follow step press enter and after
npm install express
make index.js file paste below hello work program.
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
Now you can run file using below command
node index.js
Open your broswer and enter URL : http://localhost:3000/
You can display Hello World!
You have successfully installed node js and express js program.

How to collect code coverage with Istanbul when executing HTTP endpoints via Postman or Karate

I have a JS project that provides a set of endpoints leveraging Express with a typical express/router pattern.
const express = require('express');
const router = new express.Router();
router.post('/', async (req, res, next) => { });
router.get('/:abc', async (req, res, next) => { });
module.exports = router;
I can successfully start the server with npm start which calls node ./src/index.js and makes the endpoints available at https://localhost:8080
I can also successfully test these endpoints utilizing a tool like Postman or automation like Karate.
The problem i'm having is that I can't seem to collect code coverage using Istanbul when exercising the product source JS through http://localhost:8080.
I've tried npm start followed by nyc --all src/**/*.js gradlew test. The latter being automation that tests the endpoints. This results in 0% coverage which i'm assuming was due to not running nyc with npm start.
Next I tried nyc --all src/**/*.js npm start and noticed some coverage, but this was just coverage from starting the Express server.
Next I tried nyc --all src/**/*.js npm start followed by gradlew test and noticed the code coverage results were the same as when no endpoint tests were run.
Next I tried putting the prior two commands into a single JS script(myscript.js) running each asynchronously wherein the Express server was started before the gradle tests started running and ran nyc --all src/**/*.js myscript.js. The results from this were the same as my previous trial wherein only npm start received code coverage.
Next I tried nyc --all src/**/*.js npm start followed by nyc --all src/**/*.js -no-clean gradlew test and noticed the code coverage results were the same as when no endpoint tests were run.
Next I tried all of the attempts above by wrapping them into package.json scripts and running npm run <scriptName> getting the same exact behavior.
Finally I tried nyc instrument src instrumented/src --compact=false followed by npm run start:coverage wherein this start:coverage script calls the instrumented index.js at node ./instrumented/src/index.js followed by gradlew test followed by nyc report --reporter=lcov. This attempt also failing to produce any additional code coverage from the gradlew endpoint tests.
Doing some research online I came across this post
How do I setup code coverage on my Express based API?
And thought this looks eerily similar to my problems. Eg Istanbul doesn't know how to cover code when exercising the code through executing endpoints.
I decided to still post this as the above post is quite a bit old and wanted to get opinions and see if there is a better solution than
https://github.com/gotwarlost/istanbul-middleware
EDIT
Adding more specifics about how we start the Express server and run automation without Istanbul today. Just to clarify what we're working with and automation tools we're invested in. (Mainly Karate and Java)
/*
calls --> node -r dotenv/config src/index.js
*/
npm start
/*
calls --> gradlew clean test
this effectively calls a tool called Karate
Karate's base url is pointed to: https://locahost:8080
Karate tests execute endpoints on that base url
This would be akin to using Postman however Karate has quite a bit of configuration options
https://github.com/intuit/karate
*/
npm test
Through many hours of investigation we've managed to solve this. Prior project posted by #balexandre has been updated to illustrate how to do this.
https://github.com/kirksl/karate-istanbul
As said on the comments, you never start your server to run the tests... the tests will point to your server when you require the server file.
in my example, I'm running mocha with chai and the chai-http package helps to call the server
server.js
const app = require("express")();
// everything else ...
exports.server = app;
in your end-to-end tests, you can easily have:
const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
const server = require("./server.js").server;
...
it("should calculate the circumference", done => {
chai
.request(server) // <-- attach your server here
.get('/v1/circumference/10')
.end((err, res) => {
expect(res.status).to.be.eql(200);
expect(res.type).to.be.eql('application/json');
expect(res.body.result).to.eql(62.83185307179586);
done();
});
});
});
I've made a very simple project and pushed to GitHub so you can checkout and run everything, in order to see how all work together
GitHub Project
Added
I've added a route so it can show the coverage report (I used the html report) and created a static route to it ...
when you run the coverage npm run coverage it will generate the report inside ./report folder and a simple express route pointed to that folder, will enable one to see it as an endpoint.
commit info for such change

How to create Node.js Express app serving a Vue.js SPA?

I'm trying to set up a Node.js project that uses Express to provide a few backend APIs and serve a SPA built with Vue.js.
When I use the Vue cli to initialize a project, I get e.g. src/main.ts main file and commands npm run serve to run a dev server and watch for changes and npm run build to build a production release.
When I use the Express application generator to create a project, I get ./app.js main file and npm start to start the server and watch for changes.
How can I combine these into a single project, both served by the same Express server? Preferably so that a single command would watch + update changes to both server and client? I want to use Vue single file components and TypeScript, which (probably?) require a build step.
(I don't need dynamic server-side rendering of Vue templates, just the static SPA app provided. I prefer TypeScript, but JavaScript answers are fine as well.)
These will be different for your dev and prod environments...
For development look into concurrently - it basically allows you to create a single script in your package.json to start both the client and server concurrently and will watch for changes etc...
For production, you would need something like this in your app.js:
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
(The code above assumes that your directory structure has a client folder with a build folder after having run npm run build I'm more familiar with React than Vue... but the logic should be the same...)

Automate Functional Testing in node.js

I checked some NPM libraries to test a webpages or web-services. But all of them expect that the server is already running. Since I want to automate functional testing, how can I setup NPM package in such a way that
It can start the server
Test the application
Stop the server
So that I can test it locally, as well as on online CI tools like travis-ci or circleci.
Case 1: Webservice
I wrote a NPM package which starts nodejs HTTP(s) server. It can be started from command line $stubmatic. Currently, I use 2 approaches to test it,
manual : I manually start it from command line. Then run the tests.
Automatic: I use exec module to run a unix command which can start the application and run pkill command to kill the application. But for this automation, my application need to be installed on testing machine.
Case 2: Website
I have create a NPM package: fast-xml-parser and created a demo page within the repo so that I can be tested in the browser. To test the demo page, I currently start a local server using http-server npm package manually. Test the application.
What can be the better way to write automate functional tests for node js applications?
Note:
I never used task runners like gulp or grunt. So I'm not sure if they can help in this case.
In case 1, my application starts node js native HTTP server. I'm not using any 3rd party application like express currently.
This question mentions a new Docker container system for Travis that could be duplicated locally. It might be a way: How to run travis-ci locally
Did you look at supertest (SuperAgent driven library for testing HTTP servers) and expect (Assertions library)(documented here) with mocha (Test Framework)?
I use them and I never had any kind of problems for all the tests I do until now.
The documention in the links contains all the informations you need to build up your test.
Case 1: Webservice
Problem 1
As nodejs server.close() was not working. I copied paste this snippet in every test file which is starting my webservice.
try{
server.setup(options);
server.start();
}catch(err){
console.log(err);
}
Once all the tests are completed, server stops.
**Problem 2
I was using chai-http incorrectly. Here is the complete working solution.
//Need to be placed before importing chai and chai-http
if (!global.Promise) {
global.Promise = require('q');
}
var server = require('.././lib/server');
var chai = require('chai')
, chaiHttp = require('chai-http');
chai.use(chaiHttp);
try{
server.setup(someoptions);
server.start();
}catch(err){
console.log(err);
}
describe('FT', function () {
describe('scenario::', function () {
it('responds to POST', function (done) {
chai.request("http://localhost:9999")
.post('/someurl')
.then(res => {
expect(res.status).toBe(200);
//console.log(res.text);
done();
}).catch( err => {
console.log(err);
done();
});
});
});
Case 2: Website This was quite simple.
I used http-server to start the server so my html files can be accessed.
I used zombie js for browser testing. (There are many other options available for browser testing)
Here is the code
process.env.NODE_ENV = 'test';
const Browser = require('zombie');
const httpServer = require('http-server');
describe("DemoApp", function() {
var browser = new Browser({site: 'http://localhost:8080'});
var server = httpServer.createServer();
server.listen(8080);
beforeEach(function(done){
browser.visit('/', done);
});
describe("Parse XML", function() {
it("should parse xml to json", function(done) {
browser.pressButton('#submit');
browser.assert.text('#result', 'some result text');
done();
});
});
afterEach(function(){
server.close();
})
});

Grunt and express.js server

Currenty I'm using grunt with karma and jasmine to run my tests etc. for my Angular app.
I want to connect this app to a mongo database and was wondering what the best way to do this is. Should I keep using grunt and just connect to a database and use it all the way, or should I use an Express server as my main server connected to the database and run the tests with grunt?
Initially I want to publish this project to heroku, and I know you can do this by just adding a static server.js (wich I do not currently have) like this.
var express = require('express');
var port = process.env.PORT || 3000;
var app = express();
app.use(express.static(__dirname + ‘/public’));
app.listen(port);
and modify the gruntfile.js with this:
tasks
grunt.registerTask('heroku',
['compass:dist', 'autoprefixer', 'imagemin']);
What is the best way to do this?
I see, I feel you have slight misconception of what grunt is. Grunt is a task runner. It will run other commands when for each task. Say for example if you can compile css or minifiy js or combine images before starting server you can do it with grunt. But that does not mean grunt can do all those by itself. It will be using other libraries for those.
If you are using grunt to do testing you internally using jasmine or karma js or something else. Same when you say grunt serve you use express internally start server. So grunt does not connect to mongodb. It is express which connects to mongodb. You can write grunt tasks which will start mongodb and start express server but grunt can not do either by its own.
Should you use grunt? Yes of course.

Resources