85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
import { readdir } from "fs/promises";
|
|
import * as path from "path";
|
|
|
|
class Test {
|
|
readonly name: string;
|
|
readonly promise: Promise<void>;
|
|
|
|
constructor(name: string, promise: Promise<void>) {
|
|
this.name = name;
|
|
this.promise = promise;
|
|
}
|
|
}
|
|
|
|
class Suite {
|
|
tests: Test[];
|
|
|
|
constructor() {
|
|
this.tests = [];
|
|
}
|
|
|
|
public addTest(name: string, f: () => Promise<void>): void {
|
|
const test = new Test(name, f());
|
|
this.tests.push(test);
|
|
}
|
|
|
|
public async run(): Promise<void> {
|
|
let failed = 0;
|
|
for (const test of this.tests) {
|
|
try {
|
|
await test.promise;
|
|
ok(` ✔ ${test.name}`);
|
|
} catch (e) {
|
|
error(` ✖︎ ${test.name}\n ${e.stack}`);
|
|
failed += 1;
|
|
}
|
|
}
|
|
if (failed) {
|
|
const plural = failed > 1 ? "s" : "";
|
|
throw new Error(`${failed} failed test${plural}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class Context {
|
|
public async suite(name: string, f: (ctx: Suite) => void): Promise<void> {
|
|
const ctx = new Suite();
|
|
f(ctx);
|
|
try {
|
|
ok(`⌛︎ ${name}`);
|
|
await ctx.run();
|
|
ok(`✔ ${name}`);
|
|
} catch (e) {
|
|
error(`✖︎ ${name}\n ${e.stack}`);
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function run(): Promise<void> {
|
|
const context = new Context();
|
|
|
|
const testFiles = (await readdir(path.resolve(__dirname))).filter((name) =>
|
|
name.endsWith(".test.js")
|
|
);
|
|
for (const testFile of testFiles) {
|
|
try {
|
|
const testModule = require(path.resolve(__dirname, testFile));
|
|
await testModule.getTests(context);
|
|
} catch (e) {
|
|
error(`${e}`);
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
function ok(message: string): void {
|
|
// eslint-disable-next-line no-console
|
|
console.log(`\x1b[32m${message}\x1b[0m`);
|
|
}
|
|
|
|
function error(message: string): void {
|
|
// eslint-disable-next-line no-console
|
|
console.error(`\x1b[31m${message}\x1b[0m`);
|
|
}
|