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

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.