istanbul-middleware

Connect middleware for getting code coverage numbers in functional tests for nodejs apps using istanbul.
Run the sample app at test/app
to get a feel for how this works.
All of this is experimental and is known to work for narrow use-cases such as an express3 app. YMMV.
Server-side code coverage
This involves:
- hooking
require()
in the server process - exposing coverage information on special endpoints (e.g.
/coverage
) - allowing reset of coverage numbers to ensure clean slate
- allowing users to download coverage reports after tests have run
var im = require('istanbul-middleware'),
isCoverageEnabled = (process.env.COVERAGE == "true");
if (isCoverageEnabled) {
console.log('Hook loader for coverage - ensure this is not production!');
im.hookLoader(__dirname);
}
var stuff = require('./lib'),
express = require('express'),
app = express();
if (isCoverageEnabled) {
app.use('/coverage', im.createHandler());
}
app.listen(80);
The above snippet adds the following endpoints to your app under /coverage
URL | Description |
---|
GET / |
Dynamic code coverage HTML report showing live coverage.
Clickable with drill-downs just like the static version
|
POST /reset | Reset coverage to baseline numbers |
GET /download | Download a zip file with coverage JSON, HTML and lcov reports |
POST /client |
Allows you to post a coverage object for client-side code coverage from the browser.
Must be a JSON object with a Content-type: application/json header.
This object is aggregated with the stats already present on the server
|
Client-side coverage
This involves:
- Delivering instrumented code instead of the original Javascript to the browser
- Having your tests post the coverage information to the server (see
POST /client
endpoint above)
using the window.__coverage__
object. You need to figure out how to do this using your favorite test runner. - Aggregating the client and server coverage numbers. This is automatically done for you by the server-side middleware.
The API for this is highly experimental given the number of moving parts. But, it roughly looks like this:
var path = require('path'),
im = require('istanbul-middleware');
app.use(im.createClientHandler(__dirname));
You can write your own custom middleware and completely ignore this library's client handler. As in:
app.use(function (req, res, next) {
if (isJSRequiringCoverage(req)) {
var file = getFilePath(req),
code = readTheCodeFromFile(file),
instrumenter = im.getInstrumenter();
res.send(instrumenter.instrumentSync(code, file));
} else {
next();
}
});
API
istanbulMiddleware.hookLoader(rootOrMatcher, instrumenterOpts)
hooks require
for coverage using istanbul.
rootOrMatcher
can be:
- a string in which case it is assumed to be the root under which you want to cover all files except those under
node_modules
- a function in which case it is assumed to be a match function with signature
fn(filePath)
that should return true
when the supplied filePath
should be covered and false
otherwise
instrumenterOpts
is an optional object with additional options to be passed to the istanbul instrumenter. See the
API docs in istanbul for more information. In addition, options can also contain the postLoadHook
key that is
passed to istanbul.hook.hookRequire()
istanbulMiddleware.createHandler(opts)
returns connect middleware that exposes additional endpoints for coverage. Endpoints exposed are documented in the summary.
opts
is optional and currently only supports one flag.
resetOnGet
- boolean to allow resets of coverage to baseline numbers using GET
in addition to POST
istanbulMiddleware.createClientHandler(root, opts)
returns connect middleware similar to the static
middleware to return instrumented JS to the client.
The default behavior of the middleware is to intercept all GET
requests to Javascript files and return the
instrumented version by deriving the path of the file from the URL, instrumenting the code and sending the
instrumented version in the response.
opts
is an optional object with the following supported keys:
matcher
- a function of the form fn(request)
that returns true if instrumentation
is required and false otherwise.pathTransformer
- a function of the form fn(request)
that inspects the request URL
and returns the physical path to the JS file on the filesystem.
An example of a matcher function could be:
function ignoreFrameworks(req) {
var parsed = require('url').parse(req.url);
return parsed.pathname && parsed.pathname.match(/\.js$/) && !parsed.pathname.match(/jquery/);
}
For all other cases where the client handler provided by this library is not good enough, just write your own
middleware as documented in the summary.
istanbulMiddleware.getInstrumenter()
returns the instrumenter object that is created as a side-effect of the hookLoader
call. Useful for custom
client-side instrumentation to ensure that the instrumentation is done with the same options for all code.
Third-party libraries
The following third-party libraries are used by this module: