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

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

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.

yjktbbs

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

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x