Skip to content

Commit

Permalink
feat(testament): add result format/output, global opts
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Sep 8, 2021
1 parent 98a5c5b commit b624396
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 100 deletions.
2 changes: 1 addition & 1 deletion packages/testament/bin/testament
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ if [ "$(echo $DIR | grep '.nvm')" ]; then
fi

# /usr/bin/env node --experimental-specifier-resolution=node --loader ts-node/esm -e 'import("@thi.ng/testament/cli")' -- $DIR $@
/usr/bin/env node --experimental-specifier-resolution=node --loader ts-node/esm ../../node_modules/@thi.ng/testament/cli.js $DIR $@
/usr/bin/env node --experimental-specifier-resolution=node --loader ts-node/esm ../../node_modules/@thi.ng/testament/cli.js $@
15 changes: 11 additions & 4 deletions packages/testament/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ export type Fn2<A, B, C> = (a: A, b: B) => C;

export type VoidFn = Fn0<void>;

export type Task = Fn0<Promise<any>>;
export type Task = Fn0<Promise<TestResult | TestResult[]>>;

export type Timestamp = number | bigint;

export interface TestOpts {
logger: ILogger;
timeOut: number;
maxTries: number;
maxTrials: number;
}

export interface GroupOpts extends TestOpts {
Expand All @@ -27,8 +27,10 @@ export interface TestCtx {
}

export interface TestResult {
group?: string;
title: string;
time?: number;
time: number;
trials: number;
error?: Error;
}

Expand All @@ -42,4 +44,9 @@ export interface ILogger {
severe(...args: any[]): void;
}

export let TIMEOUT = 1000;
export let GLOBAL_OPTS: Partial<GroupOpts> = {
stop: true,
exit: true,
maxTrials: 1,
timeOut: 1000,
};
111 changes: 96 additions & 15 deletions packages/testament/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import { readdirSync, statSync } from "fs";
import { readdirSync, statSync, writeFileSync } from "fs";
import { resolve } from "path";
import { GLOBAL_OPTS, TestResult } from ".";
import { LOGGER } from "./logger";
import { executeTasks } from "./task";
import { isString } from "./utils";

// interface TestamentArgs {
// csv: boolean;
// }
interface TestamentArgs {
csv: boolean;
json: boolean;
out?: string;
rest: string[];
}

const parseOpts = (args: string[], i = 2) => {
const res = <TestamentArgs>{
csv: false,
json: false,
};
outer: for (; i < args.length; ) {
switch (args[i]) {
case "-a":
case "--all":
GLOBAL_OPTS.stop = false;
i++;
break;
case "--csv":
res.csv = true;
i++;
break;
case "--json":
res.json = true;
i++;
break;
case "-o":
res.out = args[i + 1];
i += 2;
break;
default:
break outer;
}
}
res.rest = args.slice(i);
return res;
};

/**
* Recursively reads given directory and yields sequence of file names matching
Expand Down Expand Up @@ -37,23 +73,68 @@ export function* files(
}
}

(async () => {
const dirs = process.argv.slice(2);
const output = (body: string, path?: string) => {
if (path) {
LOGGER.info("writing results to:", path);
try {
writeFileSync(path, body, "utf-8");
} catch (e) {
LOGGER.warn((<Error>e).message);
}
} else {
console.log(body);
}
};

const formatCSV = (results: TestResult[]) =>
[
"Status,Group,Test,Time,Trials,Error",
...results.map((r) =>
[
r.error ? "fail" : "ok",
r.group || "",
r.title,
r.time,
r.trials,
r.error ? r.error.message : "",
].join(",")
),
].join("\n");

// const cwd = process.argv[1];
const formatJSON = (results: TestResult[]) =>
JSON.stringify(
results.map((r) => ({
status: r.error ? "fail" : "ok",
group: r.group,
title: r.title,
time: r.time,
trials: r.trials,
error: r.error ? r.error.message : undefined,
})),
null,
4
);

(async () => {
const opts = parseOpts(process.argv);
const imports: Promise<any>[] = [];
for (let dir of dirs) {
dir = resolve(dir);
if (statSync(dir).isDirectory()) {
for (let src of files(dir, ".ts")) {
imports.push(import(src));
for (let src of opts.rest) {
src = resolve(src);
if (statSync(src).isDirectory()) {
for (let f of files(src, /\.[jt]s$/)) {
imports.push(import(f));
}
} else {
imports.push(import(dir));
imports.push(import(src));
}
}
LOGGER.info(`importing ${imports.length} tests...`);
LOGGER.info(`importing ${imports.length} sources...`);
await Promise.all(imports);
await executeTasks();
const results = await executeTasks();
if (opts.csv) {
output(formatCSV(results), opts.out);
}
if (opts.json) {
output(formatJSON(results), opts.out);
}
})();
9 changes: 5 additions & 4 deletions packages/testament/src/group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Fn, GroupOpts, TestCtx, TestResult } from "./api";
import { Fn, GLOBAL_OPTS, GroupOpts, TestCtx, TestResult } from "./api";
import { LOGGER } from "./logger";
import { registerTask } from "./task";
import { test } from "./test";
Expand Down Expand Up @@ -40,7 +40,7 @@ export const group = (
) => {
const { logger, stop, beforeEach, afterEach } = {
logger: LOGGER,
stop: true,
...GLOBAL_OPTS,
...opts,
};
registerTask(async () => {
Expand All @@ -51,13 +51,14 @@ export const group = (
logger.info("----------");
for (let k in tests) {
beforeEach && beforeEach();
const res = await test(k, tests[k], opts);
results.push(res);
const res = await test(k, tests[k], opts)();
results.push({ group: title, ...res });
afterEach && afterEach();
if (res.error && stop) {
throw res.error;
}
}
logger.info();
return results;
} catch (e) {
if (opts.exit !== false) {
Expand Down
14 changes: 7 additions & 7 deletions packages/testament/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ class Logger {
}

fine(...args: any[]): void {
this.level <= 0 && this.log("FINE", args);
this.level <= 0 && this.log("FINE ", args);
}

debug(...args: any[]): void {
this.level <= 1 && this.log("DEBUG", args);
this.level <= 1 && this.log("DEBUG ", args);
}

info(...args: any[]): void {
this.level <= 2 && this.log("INFO", args);
this.level <= 2 && this.log("INFO ", args);
}

warn(...args: any[]): void {
this.level <= 3 && this.log("WARN", args);
this.level <= 3 && this.log("WARN ", args);
}

severe(...args: any[]): void {
this.level <= 4 && this.log("SEVERE", args);
}

protected log(_: string, args: any[]) {
// console.log(`[${level}] ${this.id}:`, ...args);
console.log(...args);
protected log(level: string, args: any[]) {
console.log(`[${level}]`, ...args);
// console.log(...args);
}
}

Expand Down
8 changes: 7 additions & 1 deletion packages/testament/src/task.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { TestResult } from ".";
import type { Task } from "./api";
import { now, timeDiff } from "./utils";

export const TASKS: Task[] = [];

Expand All @@ -7,7 +9,11 @@ export const registerTask = (task: Task) => {
};

export const executeTasks = async () => {
let results: TestResult[] = [];
const t0 = now();
while (TASKS.length) {
await TASKS.shift()!();
results = results.concat(await TASKS.shift()!());
}
results.push({ title: "Total", time: timeDiff(t0, now()), trials: 1 });
return results;
};
Loading

0 comments on commit b624396

Please sign in to comment.