Skip to content

Instantly share code, notes, and snippets.

@diachedelic
Created February 26, 2026 20:22
Show Gist options
  • Select an option

  • Save diachedelic/48017e4fb477ce843cdba5ee9541e3af to your computer and use it in GitHub Desktop.

Select an option

Save diachedelic/48017e4fb477ce843cdba5ee9541e3af to your computer and use it in GitHub Desktop.
Minimal Mocha testing framework clone.
// Lightweight Mocha clone.
// Usage:
// node mocha_lite.js /path/to/test.js
/*jslint global */
import path from "node:path";
import process from "node:process";
function make_runner(log) {
let suites = [];
let current_suite;
function describe(name, fn) {
let suite = {
name,
tests: [],
before_hooks: [],
after_hooks: []
};
if (current_suite !== undefined) {
current_suite.tests.push(suite);
} else {
suites.push(suite);
}
const previous_suite = current_suite;
current_suite = suite;
fn();
current_suite = previous_suite;
}
function it(name, fn) {
if (current_suite === undefined) {
throw new Error("it() must be called inside describe()");
}
current_suite.tests.push({name, fn});
}
function before(fn) {
if (current_suite === undefined) {
throw new Error("before() must be called inside describe()");
}
current_suite.before_hooks.push(fn);
}
function after(fn) {
if (current_suite === undefined) {
throw new Error("after() must be called inside describe()");
}
current_suite.after_hooks.push(fn);
}
function invoke(fn) {
return (
fn.length === 1
? new Promise(function (resolve, reject) {
fn(function done(error) {
return (
error
? reject(error)
: resolve()
);
});
})
: Promise.resolve().then(fn)
);
}
function run_hooks(hooks) {
return hooks.reduce(
function (promise, hook) {
return promise.then(function () {
return invoke(hook);
});
},
Promise.resolve()
);
}
function run_test(test, depth) {
const prefix = " ".repeat(4 * depth);
log(prefix, test.name);
return invoke(test.fn);
}
function run_suite(suite, depth = 0) {
const prefix = " ".repeat(4 * depth);
log(prefix + suite.name);
return run_hooks(
suite.before_hooks
).then(function () {
return suite.tests.reduce(
function (promise, item) {
return promise.then(function () {
return (
item.fn !== undefined
? run_test(item, depth + 1)
: run_suite(item, depth + 1)
);
});
},
Promise.resolve()
);
}).then(function () {
return run_hooks(suite.after_hooks);
});
}
function run() {
return suites.reduce(
function (promise, suite) {
return promise.then(function () {
return run_suite(suite);
});
},
Promise.resolve()
);
}
return {describe, it, before, after, run};
}
const test_file = process.argv[2];
const test_path = path.resolve(process.cwd(), test_file);
const runner = make_runner(globalThis.console.log);
globalThis.describe = runner.describe;
globalThis.it = runner.it;
globalThis.before = runner.before;
globalThis.after = runner.after;
import(test_path).then(runner.run);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment