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
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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
Method 2
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
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
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0