Gulp Mocha is a Gulp plugin that provides a thin wrapper around the Mocha testing framework to enable running Mocha tests as part of Gulp build pipelines. It processes test files through Gulp's stream system and executes them using the Mocha CLI with configurable options.
npm install --save-dev gulp-mochaimport mocha from "gulp-mocha";For CommonJS environments:
const mocha = require("gulp-mocha");import gulp from "gulp";
import mocha from "gulp-mocha";
export default () => (
gulp.src("test.js", { read: false })
// gulp-mocha needs file paths so you cannot have any plugins before it
.pipe(mocha({ reporter: "nyan" }))
);Executes Mocha tests through Gulp's stream processing with configurable options.
/**
* Creates a Gulp plugin stream for running Mocha tests
* @param options - Configuration options (optional)
* @returns Gulp plugin stream that processes test files
*/
function mocha(options?: MochaOptions): NodeJS.ReadWriteStream;
interface MochaOptions {
// Test Interface Options
ui?: "bdd" | "tdd" | "qunit" | "exports";
// Reporter Options
reporter?: string;
reporterOptions?: Record<string, any>;
// Test Execution Options
timeout?: number;
bail?: boolean;
grep?: string;
exit?: boolean;
// Environment Options
globals?: string[];
checkLeaks?: boolean;
colors?: boolean;
// Module Loading Options
require?: string[];
compilers?: string;
// Gulp-Mocha Specific Options
suppress?: boolean;
// Any other Mocha CLI option (passed through to mocha binary)
// Options are automatically converted from camelCase to kebab-case
// Arrays and objects are processed according to gulp-mocha rules
[key: string]: any;
}Usage Examples:
import gulp from "gulp";
import mocha from "gulp-mocha";
// Basic test execution
export const test = () => (
gulp.src("test/*.js", { read: false })
.pipe(mocha())
);
// With custom reporter and options
export const testDetailed = () => (
gulp.src("test/**/*.js", { read: false })
.pipe(mocha({
reporter: "spec",
timeout: 5000,
require: ["test/helper.js"],
ui: "bdd"
}))
);
// With error handling
export const testWithErrorHandling = () => (
gulp.src("test.js", { read: false })
.pipe(mocha())
.once("error", (err) => {
console.error(err);
process.exit(1);
})
.once("end", () => {
process.exit();
})
);
// Suppressed output for programmatic use
export const testQuiet = () => (
gulp.src("test/*.js", { read: false })
.pipe(mocha({ suppress: true }))
);
// Programmatic result access with pEvent (requires p-event package)
import { pEvent } from "p-event";
export const testWithResults = async () => {
const stream = mocha({ suppress: true });
const resultPromise = pEvent(stream, "_result");
stream.end(new Vinyl({ path: "test/my-test.js" }));
const { stdout, exitCode } = await resultPromise;
console.log(`Tests completed with exit code: ${exitCode}`);
console.log(`Output: ${stdout}`);
};
// Multiple require files pattern
export const testWithMultipleRequires = () => (
gulp.src("test/**/*.js", { read: false })
.pipe(mocha({
require: [
"test/setup.js",
"test/helpers.js",
"babel-register"
],
timeout: 5000
}))
);
// Error handling with pEvent
export const testWithAsyncErrorHandling = async () => {
const stream = mocha({ suppress: true });
try {
const resultPromise = pEvent(stream, "_result");
const errorPromise = pEvent(stream, "error");
stream.end(new Vinyl({ path: "test/failing-test.js" }));
// Race between success and error
const result = await Promise.race([
resultPromise.then(r => ({ type: "success", data: r })),
errorPromise.then(e => ({ type: "error", data: e }))
]);
if (result.type === "error") {
console.log("Test failures detected:", result.data.message);
console.log("isPresentable:", result.data.isPresentable);
} else {
console.log("Tests passed:", result.data.stdout);
}
} catch (error) {
console.error("Unexpected error:", error);
}
};The plugin automatically processes options to match Mocha CLI expectations using the following rules:
['glob1', 'glob2'] becomes 'glob1,glob2')require option can be specified multiple times and remains as an arraykey=value comma-separated format (e.g., {foo: 'bar', biz: 'baz'} becomes 'foo=bar,biz=baz')false values are ignored, true values become CLI flagssuppress option is handled internally and not passed to Mocha CLIInternal Processing Logic:
// Special options that can be arrays (not converted to comma-separated)
const MULTIPLE_OPTIONS = new Set(['require']);
// Options excluded from CLI arguments
const EXCLUDED_OPTIONS = ['suppress'];
// Processing rules applied to each option:
// 1. Arrays: Convert to comma-separated unless in MULTIPLE_OPTIONS
// 2. Objects: Convert to key=value comma-separated format
// 3. Exclude specified options from CLI arguments
// 4. Use dargs with ignoreFalse: true for boolean handlingThe plugin emits standard Gulp stream events plus custom events:
interface MochaStream extends NodeJS.ReadWriteStream {
// Custom Events
on(event: "_result", listener: (result: ExecaResult) => void): this;
on(event: "error", listener: (error: MochaTestError) => void): this;
}
interface ExecaResult {
stdout: string;
stderr: string;
exitCode: number;
command: string;
escapedCommand: string;
failed: boolean;
killed: boolean;
signal?: string;
signalDescription?: string;
timedOut: boolean;
}
interface MochaTestError extends Error {
message: "There were test failures";
isPresentable: true;
}"bdd" | "tdd" | "qunit" | "exports""bdd"string"spec"Record<string, any>{ reportFilename: "index.html" }number2000booleanfalsestringbooleanstring[]["YUI"], ["gulp*"], ["*"])booleanfalsebooleanBoolean(supportsColor.stdout) - Automatically detected based on stdout color supportsupports-color librarystring[]string"js:babel-core/register"booleanfalsetrue, the plugin will not pipe Mocha's output to the parent process streams, allowing for programmatic access to results via the _result event. This option is excluded from CLI arguments and handled internally by gulp-mocha.The plugin handles test failures and process errors with specific behavior:
isPresentable: trueError Processing Logic:
try {
const result = await subprocess; // execa mocha execution
stream.emit('_result', result);
} catch (error) {
if (error.exitCode > 0) {
// Test failures - create presentable error
const testError = new Error('There were test failures');
testError.isPresentable = true;
throw testError;
}
// Other process errors - re-throw as-is
throw error;
}Error Handling Examples:
// Basic error handling
gulp.src("test/*.js", { read: false })
.pipe(mocha())
.on("error", (error) => {
if (error.isPresentable) {
console.log("Tests failed:", error.message); // "There were test failures"
} else {
console.log("Process error:", error);
}
});
// Programmatic error detection
import { pEvent } from "p-event";
const stream = mocha({ suppress: true });
try {
const errorPromise = pEvent(stream, "error");
stream.end(new Vinyl({ path: "test/failing-test.js" }));
const error = await errorPromise;
console.log(error.message); // "There were test failures"
console.log(error.isPresentable); // true
} catch (processError) {
// Handle non-test-failure errors
console.error("Process error:", processError);
}execa for reliable subprocess handling with local binary preferenceThe plugin performs the following internal operations:
Binary Resolution:
execa with localDir: __dirname and preferLocal: truemocha binary in local node_modules first, then PATHCommand Construction:
dargs utility with ignoreFalse: truesuppress) from CLI argumentsmocha [...files, ...arguments]Stream Processing:
gulpPlugin with supportsAnyType: trueonFinish)_result event with full execa result objectOutput Management:
suppress optionsuppress: false (default): subprocess.stdout.pipe(process.stdout)suppress: true: No output piping, results accessible via _result event^10.2.0 - The underlying test framework^8.0.1 - Process execution utility^8.1.0 - Command line argument processing^0.3.0 - Gulp plugin utilities^9.4.0 - Terminal color support detection>=18gulp >=4 (optional)