node-coverage is a tool that measures code coverage of JavaScript application.
Code coverage is a measure typically used in software testing to describe the degree to which the source code has been tested. This is an indirect measure of quality of your tests.
node-coverage can be used not only to extract measures on how well the application is covered by a test suite, but also to understand how much code is actually needed to load your application.
There are a large variety of coverage criteria. node-coverage measures
- statement coverage. Whether or not each statement has been executed.
- condition coverage. Whether or not each boolean sub-expression evaluated both to
true
andfalse
. - decision coverage. For Javascript this implies from condition coverage.
- function coverage. Whether or not each functions has been called. Full statement coverage doesn't imply full function coverage when empty functions are used. An empty function has full statement coverage even when it's not called.
Why statement coverage is not enough? Consider the following code:
var dangerous = createAnObject();
if (dangerous != null) {
dangerous.doSomething();
}
dangerous.doSomethingElse();
A test suite where dangerous
is always different from null
runs fine and achieve 100% statement coverage, however the program fails when dangerous
is null
.
Such test suite has only 50% of condition coverage because the condition dangerous != null
is never evaluated false
.
Note that for languages where boolean operators are not short-circuited, condition coverage does not necessarly imply decision coverage. This is not the case in JavaScript.
if (a && b) {
//...
}
When a
is false
, b
is not evaluated at all.
a = true, b = true
a = false, b = true
has 100% decision coverage because the if
evaluates both to true
and false
but only 75% condition coverage because b
never evaluates false
.
Adding a test where
a = false, b = false
won't increase condition coverage because the second condition (wheter b
is true
or not) is never checked by the language.
node-coverage works instrumenting your JavaScript code and serving those instrumented files to your browser from a web server. Therefore it depends on
- Optimist library to parse command line arguments.
- UglifyJS to parse and instrument your files.
- Express to serve instrumented files.
- Jade a templating engine to display coverage reports.
- mkdirp utility for recursively create directories.
- Connect middleware layer
- node-http-proxy http proxy for node.js
Those dependencies can be installed (from the node-coverage directory) with:
npm install
Unit tests run on Nodeunit.
The administrative interface uses for "Stats & Graph" page
- jQuery
- Highcharts charting library written in JavaScript
node server.js -d "/var/www" -r "/var/log/reports"
This creates a server listenig on port 8080
serving the content of your folder /var/www
and saving coverage reports inside /var/log/reports
Go to
http://localhost:8080
and run your test suite. When complete you must call from your scripts the function
$$_l.submit()
to submit the coverage report. The report is saved inside /var/log/reports
as a JSON file.
To see the report go to the administrative interface on
http://localhost:8787
It's also possible to specify a report name from the submit
function
$$_l.submit("myTestCaseReport")
-h
or--help
list of options-d
or--doc-root
document root of the web server. All JS files in this folder will be instrumented. Default/var/www
-p
or--port
web server port. Default8080
-r
or--report-dir
directory where reports are stored. Default/var/log/node-coverage
-a
or--admin-port
administrative server port. Default8787
--condition
,--no-condition
Enable or disable condition coverage. By default it's enabled.--function
,--no-function
Enable or disable function coverage. By default it's disabled.--static-info
In case files are pre-instrumented, path to the JSON file containing static information about instrumented files.--session
,--no-session
Enable or disable storage of information not strictly needed by the browser. By default it's enabled. Disabling this means that more code is sent to and from the client.-i
or--ignore
Ignore file or folder. This file/folder won't be instrumented. Path is relative to document root.--proxy
Proxy mode. You can use node-coverage to instrument files on a differnt host.--exit-on-submit
The default behavior is to keep the server running in order to collect multiple reports. By enabling this options the server will automatically shut down when a coverage report is received. This is useful for some continuous integration environment. If you want to collect more coverage reports but still be able to shut down the server when tests are done you can submit a request to '/node-coverage-please-exit'.-v
or--verbose
Enable more verbose logging information. Defaultfalse
.
By default function coverage is disabled, to enable it you can run
node server.js --function
or
node server.js --no-condition
to disable condition coverage.
You can exclude some files or folders using
node server.js -i lib/minified -i lib/jquery.js
The server instruments JavaScript files on each request. It's possible to instrument offline your files running
node instrument.js /var/www/myApp /var/www/myInstrumentedApp
You can then run the server with
node server.js -d /var/www/myInstrumentedApp
-h
or--help
list of options-t
ottest
run unit tests--condition
,--no-condition
enable or disable condition coverage. By default it's enabled.--function
,--no-function
enable or disable function coverage. By default it's disabled.--static-info
Path to a JSON output file which will contain static information about instrumented files. Using this option reduces the size of instrumented files.-i
or--ignore
Ignore file or folder. This file/folder is copied in target folder but not instrumented. Path relative to the source folder.-x
or--exclude
Exclude file or folder. This file/folder won't be copied in target folder. Path relative to the source folder.
By default function coverage is disabled, to enable it you can run
node instrument.js --function /var/www/myApp /var/www/myInstrumentedApp
or
node instrument.js --no-condition /var/www/myApp /var/www/myInstrumentedApp
to disable condition coverage.
The code generated offline is equal to the one generated by the server when storage is disabled with --no-session
, unless --static-info
is used.
You can also instrument a single file launching
node instrument.js myScript.js
The output is sent to standard input.
The command
node instrument /var/www/myApp /var/www/myInstrumentedApp -x .git -i lib/minified
copies and instrument all files inside myApp
excluding .git
which is not copied at all and lib/minified
which is copied but won't be instrumented for coverage.
When instrumented offline, files can be served
-
by node-coverage using as document root the instrumented path
-
by any other web server. Reports however should still be sent back to node-coverage either through XHR or form submit.
By default $$_l.submit
sends an XHR POST request to /node-coverage-store
containing the JSON report.
You can set up your server to redirect this request to node coverage or override the private method $$_l.__send
. This method receives the coverage report as string.
node-coverage server accepts two types of POST request:
- XHR with
Content-type: application/json
and coverage report as request body. - Form submit with
Content-type: application/x-www-form-urlencoded
and coverage report as a string inside the fieldcoverage
.
In order to run unit tests after cloning this repository you need to run
node instrument.js -t
Once the server is started you can access the built-in adminitrative interface or use it's JSONP API to get reports as JSON objects and use them in your own tools.
You can target any page in the administrative interface adding a ?callback=myJsonPCallback
GET parameter.
Empty space characters should be converted in %20
.
http://localhost:8787/?callback=myCallback
The returned JSON is an Array of objects containing
id
: report nametime
: creation timestampdate
: creation date
http://localhost:8787/r/[id]?callback=myCallback
Replace [id]
with the actual report's id.
The returned JSON has the following structure
global
statements
total
: total number of lines,covered
: number of exectuded statement,percentage
: percentage of covered statements, float 0<>100,
conditions
total
: total number of conditions,coveredTrue
: number of conditions evaluated to true,coveredFalse
: number of conditions evaluated to false,percentage
: percentage of conditions evaluated both true and false,
functions
total
: total number of functions,covered
: number of functions that have been called (including empty functions),percentage
: percentage of functions called
files
: map of single reports for every file. The key being the file name and the value being the file reportfunctions
: history of all covered functions
By default files reports are sorted alphabetically by file name.
You can change the sorting criteria targeting
http://localhost:8787/r/[id]/sort/[what]/[how]?callback=myCallback
Where
what
is eitherfile
for alphabetical sort orstatement
,condition
orfunction
to sort according to the desired metric.how
is eitherasc
ordesc
http://localhost:8787/stat/[id]?callback=myCallback
Replace [id]
with the actual report's id.
The returned JSON has the following structure
unused
: number of unused statementsbyFile
: object where the key is a file name and the value is the number of unused statementsbyPackage
: group unused statements by "package" or folder.
http://localhost:8787/r/[id]/file/[fileName]?callback=myCallback
Slashes in fileName
must be converted into +
The returned JSON contains
code
: highlighted codesrc
: array (one entry per line of code) where value are object withs
: source linel
: lineid of the instrumented functionc
: list of conditions (array)
fns
: object mapping a function id to the generated line of code
statements
total
: total number of lines,covered
: number of exectuded statement,detail
: coverage detail for every line, how many times that statement was called,percentage
: percentage of covered statements, float 0<>100,
conditions
total
: total number of conditions,coveredTrue
: number of conditions evaluated to true,coveredFalse
: number of conditions evaluated to false,detail
: list of conditions that evaluated 'true' or 'false' and 'all' for bothpercentage
: percentage of conditions evaluated both true and false (100 if no conditions),
functions
total
: total number of functions,covered
: number of functions that have been called (including empty functions),percentage
: percentage of functions called,detail
: coverage detail of functions, how many times the function was called
http://localhost:8787/merge/?report=[id]&report=[id]?callback=myCallback
Where id
is the report name. It's possible to merge more than two reports adding extra &report=[id]
The returned JSON has the same structure of a single report.
It's also possible to merge multiple reports from the command line
node merge.js -o destination_report.json report1.json report2.json [... reportN.json]
node-coverage has a modular system for interpreting and instrumenting JavaScript files. This allows you to create an interpreter for any type of file.
The base interpreter is able to instrument standard JavaScript files, but you can create your own adding a module inside lib/interpreters
with the following structure
exports.filter = {
files : /.*/, // a regular expression matching file names
content : /\/\!/ // a regular expression matching file content
};
exports.interpret = function (file, content, options) {}
Filter object specifies which files are handled by the module.
files
is mandatory, it's a regular expression matching the file name, examples are/.*/
for any file,/\.js$/
for JavaScript filescontent
is optional, it's a regular expression matching the file content. File content are checked against this expression only if their file name matchesfilter.files
.
interpret
is the function that instruments the code. It takes 3 parameters
file
File namecontent
File contentoptions
Coverage optionsfunction
boolean, enable function coveragecondition
boolean, enable condition coveragestaticInfo
boolean, whether to include static information inside the instrumented codesubmit
boolean, whether to include the submit function inside the instrumented code
this function must return an object containing
clientCode
the instrumented code, this is sent to the clientstaticInfo
an object describing static information about the file
node-coverage can also be used as an http proxy to instrument files hosted on a different machine.
node server.js --proxy -p 8000
Start the instrumentation server in proxy mode. You can configure your browser to use an http proxy targeting localhost
on port 8000
You can also enable or disable condition or function coverage using the same options of a standalone server or specify a differnt path where to store coverage reports.
node server.js --proxy --no-condition -r ~/reports
At the moment it only support http, not https.