Skip to content

Instantly share code, notes, and snippets.

@johanbrook
Last active March 16, 2022 19:31
Show Gist options
  • Save johanbrook/598d07fa89357f8577d6d0d6e88747a5 to your computer and use it in GitHub Desktop.
Save johanbrook/598d07fa89357f8577d6d0d6e88747a5 to your computer and use it in GitHub Desktop.
Run with `./run-tests.ts`.
// test/_test-helper.ts
type Test = () => void | Promise<void>;
export interface TestCase {
name: string;
test: Test;
path?: string;
}
export const tests: Array<TestCase> = [];
/**
* Usage:
*
* ```ts
* import assert from 'assert';
* import { test } from './_test-helper';
*
* test('Foo', () => {
assert.equals(true, true);
* });
* ```
*/
export const test = (name: string, test: Test) => {
tests.push({ name, test, path: getCallerFile() });
}
/** Returns the path of the caller of the parent function. */
const getCallerFile = (): string | undefined => {
let originalFunc = Error.prepareStackTrace;
let callerfile: string | undefined;;
try {
const err = new Error();
let currentfile: string | undefined;
Error.prepareStackTrace = (_, stack) => stack;
currentfile = (err.stack as unknown as NodeJS.CallSite[]).shift()?.getFileName() ?? undefined;
while ((err.stack as unknown as NodeJS.CallSite[]).length) {
callerfile = (err.stack as unknown as NodeJS.CallSite[]).shift()?.getFileName() ?? undefined;
if (currentfile !== callerfile) break;
}
} catch (e) {}
Error.prepareStackTrace = originalFunc;
return callerfile;
};
// test/example.test.ts
import { test } from "./_test-helper";
import assert from 'assert/strict';
test('it works', () => {
assert.equal(true, true);
});
#!/usr/bin/env node -r esbuild-register
import fs from 'fs/promises';
import { basename } from 'path';
import { tests, TestCase } from './test/_test-helper';
// JOHAN'S RUDIMENTARY TEST RUNNER
//
// Will execute all test() calls in the "test" directory. Skips files prepended
// with an underscore.
//
// Usage:
// node -r esbuild-register test.ts
// or
// ./test.ts
const main = async () => {
const files = await fs.readdir('./test');
for (const file of files) {
if (file.startsWith('_')) continue;
require('./test/' + file);
}
const results = await runTests(tests);
for (const res of results) {
const filename = res.path ? basename(res.path) : 'unknown file';
if (res.fail) {
console.error(Color.FgRed + '✗ ' + Color.Reset + Color.Dim + filename + Color.Reset + ' ' + res.name);
if (res.error) console.error(Color.FgRed + res.error.message);
} else {
console.log(Color.FgGreen + '✓ ' + Color.Reset + Color.Dim + filename + Color.Reset + ' ' + res.name);
}
}
}
enum Color {
FgGreen = "\x1b[32m",
FgRed = "\x1b[31m",
Reset = "\x1b[0m",
Dim = "\x1b[2m",
}
interface TestResult {
name: string;
fail: boolean;
error?: Error;
path?: string;
}
const runTests = async (tests: Array<TestCase>): Promise<Array<TestResult>> =>
Promise.all(tests.map(t =>
Promise.resolve().then(t.test).then((): TestResult => ({
...t,
fail: false,
})).catch((err): TestResult => ({
...t,
fail: true,
error: err,
}))
));
main().catch((err) => {
console.error(err);
process.exit(1);
});
// makes this a module
export {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment