GitHub Pages code coverage
When building the GitHub Pages App TDD Stats, I wanted to add code coverage with istanbul and it required a little more effort than just wrapping the mocha call with nyc
because jsdom is not yet very code coverage friendly. It has been mentioned before that c8 works better than istanbul with jsdom but not so well with my low-tech javascript frontend files.
And I wanted to explore the advanced features of istanbul: instrumenting source files and generating coverage from __coverage__
object.
Instrument
Instrumenting the source was almost just a matter of running nyc instrument
. I chose to run it during the pretest
phase which makes it very transparent here.
Now that instrumented versions of the source are available, the idea is to give those versions to jsdom. In my case that translates into having the server serving those instrumented assets instead of the original.
Collect coverage information
This one turned out to be way easier that it looked like at first sight. The documentation of istanbul however states it quite clearly and must be taken as is: the coverage information is in window.__coverage__
.
const close = (done) => {
saveCoverage(page.window.__coverage__);
done();
};
const saveCoverage = (coverage) => {
writeFile(`.nyc_output/coverage-${Date.now()}.json`, coverage);
};
The save here happens afterEach
test. Because nyc
is smart enough to aggregate several coverage information for the same file, we add a timestamp to create a new file for each test.
I also had written a test differently, not using jsdom at all but dynamically creating a function from the source file. I do that often when I want to write a test against a file that I can’t require
or import
.
If you are curious and look at the commit history, you will see that I first investigated the details of the actual instrumenting function and tried to call it to get the coverage information. It worked but having a closer look at the instrumenting code, I realized that the coverage information was simply available in global.__coverage
in this case where no window
object was available.
after(() => {
saveCoverage(global.__coverage__);
});
Report
The report part was probably the easiest because a call to nyc report
was almost enough for my need and I just have it in the posttest phase.
🙂
So next time you want coverage info for your App hosted by GitHub Pages, here is a working example.
Leave a Reply