Created
February 26, 2026 20:22
-
-
Save diachedelic/48017e4fb477ce843cdba5ee9541e3af to your computer and use it in GitHub Desktop.
Minimal Mocha testing framework clone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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