blanket icon indicating copy to clipboard operation
blanket copied to clipboard

How to show 0% for untested files (node + mocha)?

Open danielabar opened this issue 10 years ago • 10 comments

I'm using: node v0.10.21 mocha 1.10.0 blanket 1.1.6

With following configured in package.json

"scripts": {
    "test": "mocha test/server -R spec --recursive",
    "test-cov": "mocha --require blanket test/server -R html-cov --recursive > coverage.html"
  },
"config": {
    "blanket": {
      "pattern": "server"
    }
  }

Then I run npm run-script test-cov It doesn't show coverage for files that are missing tests completely. Is it possible to configure blanket to show 0% for those files? (and factor into the overall coverage?)

Noticed this because the total coverage reported (97%) was higher than expected, but then realized it seems to not report on files that don't have any spec at all.

danielabar avatar Dec 25 '13 14:12 danielabar

I found the same issue.

    var blanketRequired = false;
    if (requireArgPosition &&
        args[requireArgPosition + 1] &&
        args[requireArgPosition + 1].match('blanket')) {
      blanketRequired = true;
    }

This is not a safe way to judge using mocha cli or not. Sometimes args can be: [ 'node', 'C:\Users\miniflycn\AppData\Roaming\npm\node_modules\mocha\bin_mocha', '--require', 'should', '--timeout', '5000', '--require', 'blanket', '-R', 'html-cov' ]

miniflycn avatar Jan 19 '14 13:01 miniflycn

See also #367

miniflycn avatar Jan 19 '14 14:01 miniflycn

Basically, to get coverage for files that are not tested, you need to manually load them somehow so that blanket becomes aware of them.

Without knowing the specifics of your project, it would be something like:

function parseDir(curr){

  if (curr is a file){
      require(curr);
  else if (curr is a directory){
     parseDir(curr.files);
  }
}

you do nothing with the requires, but it will instrument the files so they show up in the blanket report.

alex-seville avatar Jan 28 '14 22:01 alex-seville

I had the same problem; based on these comments I wrote a small function to include all files within one or more directories (largely based on http://stackoverflow.com/questions/7041638/walking-a-directory-with-node-js ). Perhaps it saves someone some time, see below.

I've put this script it in a blanket.js file in the root directory which is automatically loaded by blanket.js before it goes to work.

It feels a bit odd to have to do this manually, you'd expect when setting a 'pattern' it would include all files in the coverage that satisfy that pattern, regardless of inclusion or not. Not sure why that is... I discovered this behaviour only by accident.

(I also had troubles getting the blanket pattern config to load like in the examples; the coverage stayed at 0%. As a work-around I set the blanket configuration below manually)

The function below only works on directories relative to the root directory; not sure what other patterns blanket allows; for me it was sufficient.

'use strict';

/**
 * This file is loaded by blanket.js automatically before it instruments code to generate a code coverage report.
 */

var fs = require('fs');
var log = require('winston');
var packageJson = require('./package.json');

// For some reason the blanket config in package.json does not work automatically, set the settings manually instead
require('blanket')({
    // Only files that match this pattern will be instrumented
    pattern: packageJson.config.blanket.pattern
});

/**
 * Walks through a directory structure recursively and executes a specified action on each file.
 * @param dir {(string|string[])} The directory path or paths.
 * @param action {function} The function that will be executed on any files found.
 *      The function expects two parameters, the first is an error object, the second the file path.
 */
function walkDir(dir, action) {

    // Assert that action is a function
    if (typeof action !== "function") {
        action = function (error, file) {
        };
    }

    if (Array.isArray(dir)) {
        // If dir is an array loop through all elements
        for (var i = 0; i < dir.length; i++) {
            walkDir(dir[i], action);
        }
    } else {
        // Make sure dir is relative to the current directory
        if (dir.charAt(0) !== '.') {
            dir = '.' + dir;
        }

        // Read the directory
        fs.readdir(dir, function (err, list) {

            // Return the error if something went wrong
            if (err) return action(err);

            // For every file in the list, check if it is a directory or file.
            // When it is a directory, recursively loop through that directory as well.
            // When it is a file, perform action on file.
            list.forEach(function (file) {
                var path = dir + "/" + file;
                fs.stat(path, function (err, stat) {
                    if (stat && stat.isDirectory()) {
                        walkDir(path, action);
                    } else {
                        action(null, path);
                    }
                });
            });
        });
    }
};

// Loop through all paths in the blanket pattern
walkDir(packageJson.config.blanket.pattern, function (err, path) {
    if (err) {
        log.error(err);
        return;
    }
    log.error('Including ' + path + ' for blanket.js code coverage');
    require(path);
});

nielskrijger avatar Feb 03 '14 21:02 nielskrijger

This workaround is what I have used in the past. I understand the confusion though. The problem is that Blanket does not load files directly, it just intercepts the loading of files. So, if you wanted Blanket to instrument files not referenced by tests it would require rewriting the way that Blanket instruments. It's possible, but it's a significant change.

alex-seville avatar Feb 08 '14 04:02 alex-seville

I got same issue, please fix it.

guileen avatar Feb 17 '14 03:02 guileen

@guileen this is the fix -> https://github.com/alex-seville/blanket/issues/361#issuecomment-34002054

alex-seville avatar Feb 17 '14 03:02 alex-seville

@alex-seville Thank you for your hard work. Will it be merged in next release?

guileen avatar Feb 17 '14 05:02 guileen

No, the solution lives outside of Blanket for the moment. It doesn't seem like a good idea to automatically provide coverage for all files in a project. Unless this changes, @nielskrijger's code is a good solution to your use case.

alex-seville avatar Feb 17 '14 05:02 alex-seville

In case it's helpful to anyone... here's an example of how to incorporate something like @nielskrijger's comment: https://github.com/hammerlab/cycledash/pull/265

danvk avatar Nov 21 '14 23:11 danvk