grunt-contrib-nodeunit is a Grunt plugin that provides integration with the nodeunit-x testing framework for running server-side JavaScript unit tests. It offers enhanced error formatting, custom reporting options, and proper handling of edge cases like incomplete tests.
npm install grunt-contrib-nodeunit --save-dev// Load the plugin in your Gruntfile
grunt.loadNpmTasks('grunt-contrib-nodeunit');The plugin automatically registers the nodeunit task when loaded.
// Basic Gruntfile.js configuration
module.exports = function(grunt) {
grunt.initConfig({
nodeunit: {
all: ['test/*_test.js']
}
});
grunt.loadNpmTasks('grunt-contrib-nodeunit');
grunt.registerTask('test', ['nodeunit']);
};Run tests with:
grunt nodeunit
# or
grunt nodeunit:allgrunt-contrib-nodeunit is built as a standard Grunt plugin with the following key components:
grunt instance for task registrationgrunt reporter in nodeunit.reporters.gruntbetterErrors and cleanStack functionsnodeunit.json filesprocess.stdout.write for output capture when using reporterOutput/**
* Main plugin export function
* @param grunt - The Grunt instance
*/
module.exports = function(grunt: any): void;The main task provided by this plugin for running nodeunit tests with enhanced reporting.
// Task configuration
nodeunit: {
// Target name (e.g., 'all', 'unit', 'integration')
[targetName]: [
// Array of file patterns
'test/*_test.js',
'test/**/*_test.js'
],
options: {
// Optional task options
reporter: string, // Default: 'grunt'
reporterOutput: string, // Default: false
reporterOptions: object // Default: {}
}
}All options are configured within the options object of the task configuration.
interface NodeunitTaskOptions {
/**
* Reporter to use for test output
* Built-in options: 'grunt' (default), 'default', 'verbose', 'tap', 'junit'
* Default: 'grunt'
*/
reporter?: string;
/**
* File path where reporter output should be saved
* When false, output goes to console only
* Default: false
*/
reporterOutput?: string | false;
/**
* Options passed to the selected reporter
* Varies by reporter type
* Default: {}
*/
reporterOptions?: {
/** Output directory for junit reporter */
output?: string;
[key: string]: any;
};
}The task accepts standard Grunt file pattern formats:
// Single files
nodeunit: {
single: ['test/specific_test.js']
}
// Wildcards (all files ending in _test.js in test directory)
nodeunit: {
wildcard: ['test/*_test.js']
}
// Recursive (all _test.js files in test directory and subdirectories)
nodeunit: {
recursive: ['test/**/*_test.js']
}
// Multiple patterns
nodeunit: {
multiple: [
'test/unit/*_test.js',
'test/integration/*_test.js'
]
}The plugin supports any reporter available in the nodeunit-x package. If an invalid reporter is specified, the task will fail with an error. The most commonly used reporters include:
Custom reporter that integrates with Grunt's logging system, providing enhanced error formatting with colored output, better stack traces, and proper integration with Grunt's verbose mode.
The Grunt reporter provides several enhancements over standard nodeunit reporters:
util.inspect with color support and 10-level depth for better object visualization--stack flag is usedtest.done() and provides helpful error messagesnodeunit: {
all: ['test/*_test.js'],
options: {
reporter: 'grunt' // This is the default
}
}Test Anything Protocol output format, useful for CI/CD integration.
nodeunit: {
all: ['test/*_test.js'],
options: {
reporter: 'tap',
reporterOutput: 'test-results.tap'
}
}XML output compatible with JUnit, ideal for CI systems that parse JUnit reports.
nodeunit: {
all: ['test/*_test.js'],
options: {
reporter: 'junit',
reporterOptions: {
output: 'test-results' // Directory for XML files
}
}
}Standard nodeunit reporters for basic console output.
nodeunit: {
all: ['test/*_test.js'],
options: {
reporter: 'default' // or 'verbose'
}
}Simple setup for running all test files:
grunt.initConfig({
nodeunit: {
all: ['test/*_test.js']
}
});Separate configurations for different test types:
grunt.initConfig({
nodeunit: {
unit: ['test/unit/*_test.js'],
integration: ['test/integration/*_test.js'],
options: {
reporter: 'grunt'
}
}
});Configuration optimized for continuous integration:
grunt.initConfig({
nodeunit: {
ci: ['test/**/*_test.js'],
options: {
reporter: 'junit',
reporterOptions: {
output: 'test-results'
}
}
}
});Save test results to a file:
grunt.initConfig({
nodeunit: {
all: ['test/*_test.js'],
options: {
reporter: 'tap',
reporterOutput: 'build/test-results.tap'
}
}
});The plugin respects Grunt CLI options that affect output behavior:
grunt nodeunit --verbose # Shows detailed test progress and enhanced error reporting
grunt nodeunit --stack # Displays full stack traces including nodeunit internal calls--verbose: Shows detailed test progress, enhanced error reporting, and full error logging--stack: Displays complete stack traces including nodeunit internal calls (normally filtered out)The plugin automatically loads default configuration from nodeunit.json files:
nodeunit-x/bin/nodeunit.json in node_modules directoriesreporterOptionsThe plugin provides enhanced error handling compared to standard nodeunit:
test.done() callsutil.inspectreporterOptions.outputreporterOutputThe plugin follows Grunt's error handling conventions:
// Error scenarios and their handling
interface ErrorHandling {
/** Task fails when reporter doesn't exist */
invalidReporter: Error;
/** Grunt exits with code 90-99 based on number of incomplete tests */
incompleteTests: {
exitCode: number; // Math.min(99, 90 + numberOfIncompleteTests)
message: string; // Lists all incomplete test names
};
/** Warnings for test failures (doesn't stop Grunt) */
testFailures: {
type: 'warning';
message: string; // "X/Y assertions failed (Zms)"
};
/** Warnings for zero assertions */
noAssertions: {
type: 'warning';
message: string; // "0/0 assertions ran (Zms)"
};
}Missing test.done()
Incomplete tests/setups/teardowns:
testName
A test was missing test.done(), so nodeunit exploded. Sorry!This occurs when a test function doesn't call test.done(). Ensure all async tests call test.done():
exports.asyncTest = function(test) {
setTimeout(function() {
test.ok(true);
test.done(); // Required for async tests
}, 100);
};npm install grunt-contrib-nodeunit --save-devgrunt nodeunitThe plugin integrates seamlessly with Grunt's task system and provides detailed feedback during test execution.
For completeness, the plugin includes several internal utility functions that enhance the testing experience:
// Internal utility functions (not directly configurable but part of the implementation)
interface InternalUtilities {
/** Hooks into stdout for output capture */
hook_stdout(callback: (string: string, encoding: string, fd: any) => void): () => void;
/** Enhances error display with better formatting */
betterErrors(assertion: any): any;
/** Cleans stack traces for better readability */
cleanStack(error: Error): Error;
/** Custom Grunt reporter implementation */
'nodeunit.reporters.grunt': {
info: string;
run: (files: string[], options: any, callback: () => void) => void;
};
}These utilities work together to provide the enhanced error reporting and output management that makes grunt-contrib-nodeunit more user-friendly than standard nodeunit command-line usage.