@w-lfpup/jackrabbit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build_and_test.yml +18 -0
- package/.prettierignore +3 -0
- package/.prettierrc +5 -0
- package/LICENSE +29 -0
- package/README.md +33 -0
- package/cli/dist/cli.d.ts +3 -0
- package/cli/dist/cli.js +8 -0
- package/cli/dist/cli_types.d.ts +7 -0
- package/cli/dist/cli_types.js +1 -0
- package/cli/dist/config.d.ts +5 -0
- package/cli/dist/config.js +27 -0
- package/cli/dist/importer.d.ts +7 -0
- package/cli/dist/importer.js +16 -0
- package/cli/dist/logger.d.ts +7 -0
- package/cli/dist/logger.js +88 -0
- package/cli/dist/mod.d.ts +6 -0
- package/cli/dist/mod.js +4 -0
- package/cli/package.json +8 -0
- package/cli/src/cli.ts +17 -0
- package/cli/src/cli_types.ts +9 -0
- package/cli/src/config.ts +36 -0
- package/cli/src/importer.ts +25 -0
- package/cli/src/logger.ts +126 -0
- package/cli/src/mod.ts +7 -0
- package/cli/tsconfig.json +7 -0
- package/cli/tsconfig.tsbuildinfo +1 -0
- package/core/dist/jackrabbit_types.d.ts +56 -0
- package/core/dist/jackrabbit_types.js +1 -0
- package/core/dist/mod.d.ts +2 -0
- package/core/dist/mod.js +1 -0
- package/core/dist/run_steps.d.ts +3 -0
- package/core/dist/run_steps.js +95 -0
- package/core/package.json +8 -0
- package/core/src/jackrabbit_types.ts +75 -0
- package/core/src/mod.ts +9 -0
- package/core/src/run_steps.ts +138 -0
- package/core/tsconfig.json +7 -0
- package/core/tsconfig.tsbuildinfo +1 -0
- package/examples/hello_world/goodbye_world.ts +15 -0
- package/examples/hello_world/hello_world.ts +9 -0
- package/examples/hello_world/mod.ts +4 -0
- package/examples/package.json +3 -0
- package/nodejs_cli/dist/mod.d.ts +2 -0
- package/nodejs_cli/dist/mod.js +20 -0
- package/nodejs_cli/package.json +8 -0
- package/nodejs_cli/src/mod.ts +25 -0
- package/nodejs_cli/tsconfig.json +7 -0
- package/nodejs_cli/tsconfig.tsbuildinfo +1 -0
- package/package.json +29 -0
- package/test_guide.md +114 -0
- package/tests/dist/mod.d.ts +9 -0
- package/tests/dist/mod.js +30 -0
- package/tests/dist/test_fail.test.d.ts +9 -0
- package/tests/dist/test_fail.test.js +23 -0
- package/tests/dist/test_logger.d.ts +7 -0
- package/tests/dist/test_logger.js +19 -0
- package/tests/dist/test_pass.test.d.ts +9 -0
- package/tests/dist/test_pass.test.js +23 -0
- package/tests/package.json +8 -0
- package/tests/src/mod.ts +39 -0
- package/tests/src/test_fail.test.ts +28 -0
- package/tests/src/test_logger.ts +28 -0
- package/tests/src/test_pass.test.ts +28 -0
- package/tests/tsconfig.json +7 -0
- package/tests/tsconfig.tsbuildinfo +1 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const TIMEOUT_INTERVAL_MS = 10000;
|
|
2
|
+
function sleep(time) {
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
|
+
setTimeout(() => {
|
|
5
|
+
resolve();
|
|
6
|
+
}, time);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
async function createTimeout(timeoutMs = TIMEOUT_INTERVAL_MS) {
|
|
10
|
+
await sleep(timeoutMs);
|
|
11
|
+
return `timed out at ${performance.now()} after ${timeoutMs} ms.`;
|
|
12
|
+
}
|
|
13
|
+
async function execTest(testModules, logger, moduleId, testId) {
|
|
14
|
+
if (logger.cancelled)
|
|
15
|
+
return;
|
|
16
|
+
logger.log(testModules, {
|
|
17
|
+
type: "start_test",
|
|
18
|
+
moduleId,
|
|
19
|
+
testId,
|
|
20
|
+
});
|
|
21
|
+
const { tests, options } = testModules[moduleId];
|
|
22
|
+
const testFunc = tests[testId];
|
|
23
|
+
const startTime = performance.now();
|
|
24
|
+
const assertions = await Promise.race([
|
|
25
|
+
createTimeout(options.timeoutMs),
|
|
26
|
+
testFunc(),
|
|
27
|
+
]);
|
|
28
|
+
if (logger.cancelled)
|
|
29
|
+
return;
|
|
30
|
+
const endTime = performance.now();
|
|
31
|
+
logger.log(testModules, {
|
|
32
|
+
type: "end_test",
|
|
33
|
+
assertions,
|
|
34
|
+
endTime,
|
|
35
|
+
moduleId,
|
|
36
|
+
startTime,
|
|
37
|
+
testId,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async function execCollection(testModules, logger, moduleId) {
|
|
41
|
+
if (logger.cancelled)
|
|
42
|
+
return;
|
|
43
|
+
const { tests } = testModules[moduleId];
|
|
44
|
+
const wrappedTests = [];
|
|
45
|
+
for (let [testID] of tests.entries()) {
|
|
46
|
+
wrappedTests.push(execTest(testModules, logger, moduleId, testID));
|
|
47
|
+
}
|
|
48
|
+
if (logger.cancelled)
|
|
49
|
+
return;
|
|
50
|
+
await Promise.all(wrappedTests);
|
|
51
|
+
}
|
|
52
|
+
async function execCollectionOrdered(testModules, logger, moduleId) {
|
|
53
|
+
const { tests } = testModules[moduleId];
|
|
54
|
+
for (let [testID] of tests.entries()) {
|
|
55
|
+
if (logger.cancelled)
|
|
56
|
+
return;
|
|
57
|
+
await execTest(testModules, logger, moduleId, testID);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export async function startRun(logger, testModules) {
|
|
61
|
+
logger.log(testModules, {
|
|
62
|
+
type: "start_run",
|
|
63
|
+
time: performance.now(),
|
|
64
|
+
});
|
|
65
|
+
for (let [moduleId, testModule] of testModules.entries()) {
|
|
66
|
+
if (logger.cancelled)
|
|
67
|
+
return;
|
|
68
|
+
logger.log(testModules, {
|
|
69
|
+
type: "start_module",
|
|
70
|
+
moduleId,
|
|
71
|
+
});
|
|
72
|
+
const { options } = testModule;
|
|
73
|
+
options?.runAsynchronously
|
|
74
|
+
? await execCollection(testModules, logger, moduleId)
|
|
75
|
+
: await execCollectionOrdered(testModules, logger, moduleId);
|
|
76
|
+
if (logger.cancelled)
|
|
77
|
+
return;
|
|
78
|
+
logger.log(testModules, {
|
|
79
|
+
type: "end_module",
|
|
80
|
+
moduleId,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
logger.log(testModules, {
|
|
84
|
+
type: "end_run",
|
|
85
|
+
time: performance.now(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
export function cancelRun(logger, testModules) {
|
|
89
|
+
if (logger.cancelled)
|
|
90
|
+
return;
|
|
91
|
+
logger.log(testModules, {
|
|
92
|
+
type: "cancel_run",
|
|
93
|
+
time: performance.now(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface Stringable {
|
|
2
|
+
toString: Object["toString"];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type Assertions = Stringable | Stringable[] | undefined;
|
|
6
|
+
|
|
7
|
+
type SyncTest = () => Assertions;
|
|
8
|
+
type AsyncTest = () => Promise<Assertions>;
|
|
9
|
+
export type Test = SyncTest | AsyncTest;
|
|
10
|
+
|
|
11
|
+
export interface Options {
|
|
12
|
+
title?: string;
|
|
13
|
+
runAsynchronously?: boolean;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TestModule {
|
|
18
|
+
tests: Test[];
|
|
19
|
+
options: Options;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface StartRun {
|
|
23
|
+
type: "start_run";
|
|
24
|
+
time: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface EndRun {
|
|
28
|
+
type: "end_run";
|
|
29
|
+
time: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface CancelRun {
|
|
33
|
+
type: "cancel_run";
|
|
34
|
+
time: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface StartModule {
|
|
38
|
+
type: "start_module";
|
|
39
|
+
moduleId: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface EndModule {
|
|
43
|
+
type: "end_module";
|
|
44
|
+
moduleId: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StartTest {
|
|
48
|
+
type: "start_test";
|
|
49
|
+
testId: number;
|
|
50
|
+
moduleId: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface EndTest {
|
|
54
|
+
type: "end_test";
|
|
55
|
+
testId: number;
|
|
56
|
+
moduleId: number;
|
|
57
|
+
startTime: number;
|
|
58
|
+
endTime: number;
|
|
59
|
+
assertions: Assertions;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type LoggerAction =
|
|
63
|
+
| StartRun
|
|
64
|
+
| EndRun
|
|
65
|
+
| CancelRun
|
|
66
|
+
| StartModule
|
|
67
|
+
| EndModule
|
|
68
|
+
| StartTest
|
|
69
|
+
| EndTest;
|
|
70
|
+
|
|
71
|
+
export interface LoggerInterface {
|
|
72
|
+
readonly failed: boolean;
|
|
73
|
+
readonly cancelled: boolean;
|
|
74
|
+
log(testModules: TestModule[], action: LoggerAction): void;
|
|
75
|
+
}
|
package/core/src/mod.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Assertions,
|
|
3
|
+
LoggerInterface,
|
|
4
|
+
TestModule,
|
|
5
|
+
} from "./jackrabbit_types.ts";
|
|
6
|
+
|
|
7
|
+
const TIMEOUT_INTERVAL_MS = 10000;
|
|
8
|
+
|
|
9
|
+
function sleep(time: number): Promise<void> {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
setTimeout(() => {
|
|
12
|
+
resolve();
|
|
13
|
+
}, time);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function createTimeout(
|
|
18
|
+
timeoutMs: number = TIMEOUT_INTERVAL_MS,
|
|
19
|
+
): Promise<Assertions> {
|
|
20
|
+
await sleep(timeoutMs);
|
|
21
|
+
|
|
22
|
+
return `timed out at ${performance.now()} after ${timeoutMs} ms.`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function execTest(
|
|
26
|
+
testModules: TestModule[],
|
|
27
|
+
logger: LoggerInterface,
|
|
28
|
+
moduleId: number,
|
|
29
|
+
testId: number,
|
|
30
|
+
) {
|
|
31
|
+
if (logger.cancelled) return;
|
|
32
|
+
|
|
33
|
+
logger.log(testModules, {
|
|
34
|
+
type: "start_test",
|
|
35
|
+
moduleId,
|
|
36
|
+
testId,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const { tests, options } = testModules[moduleId];
|
|
40
|
+
|
|
41
|
+
const testFunc = tests[testId];
|
|
42
|
+
const startTime = performance.now();
|
|
43
|
+
const assertions = await Promise.race([
|
|
44
|
+
createTimeout(options.timeoutMs),
|
|
45
|
+
testFunc(),
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
if (logger.cancelled) return;
|
|
49
|
+
|
|
50
|
+
const endTime = performance.now();
|
|
51
|
+
|
|
52
|
+
logger.log(testModules, {
|
|
53
|
+
type: "end_test",
|
|
54
|
+
assertions,
|
|
55
|
+
endTime,
|
|
56
|
+
moduleId,
|
|
57
|
+
startTime,
|
|
58
|
+
testId,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function execCollection(
|
|
63
|
+
testModules: TestModule[],
|
|
64
|
+
logger: LoggerInterface,
|
|
65
|
+
moduleId: number,
|
|
66
|
+
) {
|
|
67
|
+
if (logger.cancelled) return;
|
|
68
|
+
|
|
69
|
+
const { tests } = testModules[moduleId];
|
|
70
|
+
|
|
71
|
+
const wrappedTests = [];
|
|
72
|
+
for (let [testID] of tests.entries()) {
|
|
73
|
+
wrappedTests.push(execTest(testModules, logger, moduleId, testID));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (logger.cancelled) return;
|
|
77
|
+
|
|
78
|
+
await Promise.all(wrappedTests);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function execCollectionOrdered(
|
|
82
|
+
testModules: TestModule[],
|
|
83
|
+
logger: LoggerInterface,
|
|
84
|
+
moduleId: number,
|
|
85
|
+
) {
|
|
86
|
+
const { tests } = testModules[moduleId];
|
|
87
|
+
|
|
88
|
+
for (let [testID] of tests.entries()) {
|
|
89
|
+
if (logger.cancelled) return;
|
|
90
|
+
|
|
91
|
+
await execTest(testModules, logger, moduleId, testID);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function startRun(
|
|
96
|
+
logger: LoggerInterface,
|
|
97
|
+
testModules: TestModule[],
|
|
98
|
+
) {
|
|
99
|
+
logger.log(testModules, {
|
|
100
|
+
type: "start_run",
|
|
101
|
+
time: performance.now(),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
for (let [moduleId, testModule] of testModules.entries()) {
|
|
105
|
+
if (logger.cancelled) return;
|
|
106
|
+
|
|
107
|
+
logger.log(testModules, {
|
|
108
|
+
type: "start_module",
|
|
109
|
+
moduleId,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const { options } = testModule;
|
|
113
|
+
options?.runAsynchronously
|
|
114
|
+
? await execCollection(testModules, logger, moduleId)
|
|
115
|
+
: await execCollectionOrdered(testModules, logger, moduleId);
|
|
116
|
+
|
|
117
|
+
if (logger.cancelled) return;
|
|
118
|
+
|
|
119
|
+
logger.log(testModules, {
|
|
120
|
+
type: "end_module",
|
|
121
|
+
moduleId,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
logger.log(testModules, {
|
|
126
|
+
type: "end_run",
|
|
127
|
+
time: performance.now(),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function cancelRun(logger: LoggerInterface, testModules: TestModule[]) {
|
|
132
|
+
if (logger.cancelled) return;
|
|
133
|
+
|
|
134
|
+
logger.log(testModules, {
|
|
135
|
+
type: "cancel_run",
|
|
136
|
+
time: performance.now(),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/jackrabbit_types.ts","./src/mod.ts","./src/run_steps.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
async function test_that_passes() {
|
|
2
|
+
return [];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
async function test_that_fails() {
|
|
6
|
+
return ["this test will fail"];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const tests = [test_that_passes, test_that_fails];
|
|
10
|
+
|
|
11
|
+
export const options = {
|
|
12
|
+
title: import.meta.url,
|
|
13
|
+
runAsynchronously: true,
|
|
14
|
+
timeoutMs: 2000,
|
|
15
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Config, Importer, Logger, run } from "../../cli/dist/mod.js";
|
|
3
|
+
const config = new Config(process.argv.slice(2));
|
|
4
|
+
const importer = new Importer(process.cwd());
|
|
5
|
+
const logger = new Logger();
|
|
6
|
+
let errored = false;
|
|
7
|
+
try {
|
|
8
|
+
await run(config, importer, logger);
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
errored = true;
|
|
12
|
+
console.log("Error:");
|
|
13
|
+
e instanceof Error
|
|
14
|
+
? console.log(`
|
|
15
|
+
${e.name}
|
|
16
|
+
${e.message}
|
|
17
|
+
${e.stack}`)
|
|
18
|
+
: console.log(e);
|
|
19
|
+
}
|
|
20
|
+
logger.failed || errored ? process.exit(1) : process.exit(0);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Config, Importer, Logger, run } from "../../cli/dist/mod.js";
|
|
4
|
+
|
|
5
|
+
const config = new Config(process.argv.slice(2));
|
|
6
|
+
const importer = new Importer(process.cwd());
|
|
7
|
+
const logger = new Logger();
|
|
8
|
+
|
|
9
|
+
let errored = false;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
await run(config, importer, logger);
|
|
13
|
+
} catch (e: unknown) {
|
|
14
|
+
errored = true;
|
|
15
|
+
console.log("Error:");
|
|
16
|
+
|
|
17
|
+
e instanceof Error
|
|
18
|
+
? console.log(`
|
|
19
|
+
${e.name}
|
|
20
|
+
${e.message}
|
|
21
|
+
${e.stack}`)
|
|
22
|
+
: console.log(e);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
logger.failed || errored ? process.exit(1) : process.exit(0);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/mod.ts"],"version":"5.9.3"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@w-lfpup/jackrabbit",
|
|
3
|
+
"description": "A test runner without dependencies",
|
|
4
|
+
"workspaces": [
|
|
5
|
+
"core",
|
|
6
|
+
"tests",
|
|
7
|
+
"cli",
|
|
8
|
+
"nodejs_cli"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"jackrabbit": "nodejs_cli/dist/mod.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"prepare": "npm run build",
|
|
15
|
+
"build": "npm run --workspaces build",
|
|
16
|
+
"format": "npx prettier --write ./",
|
|
17
|
+
"test": "npx jackrabbit --file ./tests/dist/mod.js"
|
|
18
|
+
},
|
|
19
|
+
"version": "0.1.0",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/w-lfpup/jackarabbit-js.git"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^22.5.5",
|
|
26
|
+
"prettier": "^3.3.1",
|
|
27
|
+
"typescript": "^5.4.5"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/test_guide.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Jackrabbit Tests
|
|
2
|
+
|
|
3
|
+
For a quick visual reference, please refer to the [examples](./examples/).
|
|
4
|
+
|
|
5
|
+
`Jackrabbit` leverages esmodules for a flat, concise testing experience. There are no assertion libraries, there are no wild BDD functions. Developers with javascript experience can immediately start testing with basically zero overhead.
|
|
6
|
+
|
|
7
|
+
## Tests
|
|
8
|
+
|
|
9
|
+
Tests are functions that return assertions.
|
|
10
|
+
|
|
11
|
+
Tests `pass` when they return the `undefined` primitive or an empty array `[]`.
|
|
12
|
+
|
|
13
|
+
```TS
|
|
14
|
+
// my_library.tests.ts
|
|
15
|
+
|
|
16
|
+
function testStuffAndPass() {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function testMoreStuffAndPass() {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Any other value will cause a test to `fail`.
|
|
26
|
+
|
|
27
|
+
So tests that `fail` look like:
|
|
28
|
+
|
|
29
|
+
```TS
|
|
30
|
+
// my_library.tests.ts
|
|
31
|
+
|
|
32
|
+
function testStuffAndFail() {
|
|
33
|
+
return "this test failed!";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function testMoreStuffAndFail() {
|
|
37
|
+
return ["this test also failed!"];
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Test Modules
|
|
42
|
+
|
|
43
|
+
Test Modules are javascript `modules` that contain tests.
|
|
44
|
+
|
|
45
|
+
### Export Tests
|
|
46
|
+
|
|
47
|
+
Test Modules export their tests in an array called `tests`.
|
|
48
|
+
|
|
49
|
+
```TS
|
|
50
|
+
// my_library.tests.ts
|
|
51
|
+
|
|
52
|
+
export const tests = [
|
|
53
|
+
testStuffAndPass,
|
|
54
|
+
testMoreStuffAndPass,
|
|
55
|
+
testStuffAndFail,
|
|
56
|
+
testMoreStuffAndFail,
|
|
57
|
+
];
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Export Options
|
|
61
|
+
|
|
62
|
+
Exporting an `options` pojo is not required.
|
|
63
|
+
|
|
64
|
+
But exporting an `options` pojo with the following properties will affect test behavior:
|
|
65
|
+
|
|
66
|
+
```TS
|
|
67
|
+
export const options = {
|
|
68
|
+
title: import.meta.url,
|
|
69
|
+
runAsyncronously: true,
|
|
70
|
+
timeoutMs: 3000,
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
All properteis are optional.
|
|
75
|
+
|
|
76
|
+
Tests run sequentially unless the `runAsyncronously` property is set to `true`.
|
|
77
|
+
|
|
78
|
+
```TS
|
|
79
|
+
// my_library.tests.ts
|
|
80
|
+
|
|
81
|
+
interface Options {
|
|
82
|
+
title?: string;
|
|
83
|
+
runAsynchronously?: boolean;
|
|
84
|
+
timeoutMs?: number;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Test Collections
|
|
89
|
+
|
|
90
|
+
A `test collection` is a javascript module that exports a list test modules called `testModules`.
|
|
91
|
+
|
|
92
|
+
```TS
|
|
93
|
+
// mod.test.ts
|
|
94
|
+
|
|
95
|
+
import * as MyTests from "./my_library.tests.ts";
|
|
96
|
+
|
|
97
|
+
export const testModules = [
|
|
98
|
+
MyTests
|
|
99
|
+
];
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This gathers all tests into a single explicit location.
|
|
103
|
+
|
|
104
|
+
## Run Test Collections
|
|
105
|
+
|
|
106
|
+
Run the following command and Jackrabbit will log the results of `test collections`.
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
npx jackrabbit --file ./mod.test.ts
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
BSD 3-Clause License
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare function testsFail(): Promise<"fail tests failed to fail" | undefined>;
|
|
2
|
+
declare function testsPass(): Promise<"passing tests failed to pass" | undefined>;
|
|
3
|
+
export declare const testModules: {
|
|
4
|
+
tests: (typeof testsFail | typeof testsPass)[];
|
|
5
|
+
options: {
|
|
6
|
+
title: string;
|
|
7
|
+
};
|
|
8
|
+
}[];
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as FailTests from "./test_fail.test.js";
|
|
2
|
+
import * as PassTests from "./test_pass.test.js";
|
|
3
|
+
import { startRun } from "../../core/dist/mod.js";
|
|
4
|
+
import { TestLogger } from "./test_logger.js";
|
|
5
|
+
// Test pass and fail behavior
|
|
6
|
+
const failTestModules = [FailTests];
|
|
7
|
+
const passTestModules = [PassTests];
|
|
8
|
+
// jackrabbit test run won't pass failing tests
|
|
9
|
+
async function testsFail() {
|
|
10
|
+
let logger = new TestLogger();
|
|
11
|
+
await startRun(logger, failTestModules);
|
|
12
|
+
if (!logger.failed)
|
|
13
|
+
return "fail tests failed to fail";
|
|
14
|
+
}
|
|
15
|
+
// jackrabbit test run won't fail passing tests
|
|
16
|
+
async function testsPass() {
|
|
17
|
+
let logger = new TestLogger();
|
|
18
|
+
await startRun(logger, passTestModules);
|
|
19
|
+
if (logger.failed)
|
|
20
|
+
return "passing tests failed to pass";
|
|
21
|
+
}
|
|
22
|
+
const tests = [testsFail, testsPass];
|
|
23
|
+
const options = {
|
|
24
|
+
title: "Failures and Successes",
|
|
25
|
+
};
|
|
26
|
+
const testModule = {
|
|
27
|
+
tests,
|
|
28
|
+
options,
|
|
29
|
+
};
|
|
30
|
+
export const testModules = [testModule];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare function testStuffAndFail(): string;
|
|
2
|
+
declare function testMoreStuffAndFail(): string[];
|
|
3
|
+
declare function testStuffAndFailAsync(): Promise<string>;
|
|
4
|
+
declare function testMoreStuffAndFailAsync(): Promise<string[]>;
|
|
5
|
+
export declare const tests: (typeof testStuffAndFail | typeof testMoreStuffAndFail | typeof testStuffAndFailAsync | typeof testMoreStuffAndFailAsync)[];
|
|
6
|
+
export declare const options: {
|
|
7
|
+
title: string;
|
|
8
|
+
};
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function testStuffAndFail() {
|
|
2
|
+
return "this test failed!";
|
|
3
|
+
}
|
|
4
|
+
function testMoreStuffAndFail() {
|
|
5
|
+
return ["this test also failed!"];
|
|
6
|
+
}
|
|
7
|
+
async function testStuffAndFailAsync() {
|
|
8
|
+
return "this test failed!";
|
|
9
|
+
}
|
|
10
|
+
async function testMoreStuffAndFailAsync() {
|
|
11
|
+
return ["this test also failed!"];
|
|
12
|
+
}
|
|
13
|
+
// export tests
|
|
14
|
+
export const tests = [
|
|
15
|
+
testStuffAndFail,
|
|
16
|
+
testMoreStuffAndFail,
|
|
17
|
+
testStuffAndFailAsync,
|
|
18
|
+
testMoreStuffAndFailAsync,
|
|
19
|
+
];
|
|
20
|
+
// export optional test details
|
|
21
|
+
export const options = {
|
|
22
|
+
title: import.meta.url,
|
|
23
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LoggerAction, LoggerInterface, TestModule } from "../../core/dist/mod.ts";
|
|
2
|
+
declare class TestLogger implements LoggerInterface {
|
|
3
|
+
cancelled: boolean;
|
|
4
|
+
failed: boolean;
|
|
5
|
+
log(_testModule: TestModule[], action: LoggerAction): void;
|
|
6
|
+
}
|
|
7
|
+
export { TestLogger };
|