@aljazmc/testero 0.2.0 → 0.3.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/README.md +2 -12
- package/bin/main.js +62 -4
- package/bin/types/arguments.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# > testero
|
|
4
4
|
|
|
5
|
-
A simple, Jest
|
|
5
|
+
A simple, Jest-like test runner. Easy to understand, easy to customize and easy to extend.
|
|
6
6
|
|
|
7
7
|
## > usage
|
|
8
8
|
|
|
@@ -12,6 +12,7 @@ testero math unit/ # run test files whose path matches a pattern
|
|
|
12
12
|
testero -t "adds numbers" # run tests whose full name matches
|
|
13
13
|
testero --verbose --bail # list every test, stop at the first failing file
|
|
14
14
|
testero --listTests # print the test files instead of running them
|
|
15
|
+
testero --config # write the defaults to testero.config.ts, --config js to testero.config.js
|
|
15
16
|
testero --help
|
|
16
17
|
```
|
|
17
18
|
|
|
@@ -84,14 +85,3 @@ export default {
|
|
|
84
85
|
- `@aljazmc/config` (`shared/config`): loads `testero.config.ts`, finds the files and matches `testMatch`, shared with every package
|
|
85
86
|
|
|
86
87
|
Each test file is bundled on its own, so it gets fresh copies of the files it imports, and spies are restored after it. Test files run one after another in one process, without workers, module mocking, fake timers, snapshots or coverage.
|
|
87
|
-
|
|
88
|
-
## > achieved milestones
|
|
89
|
-
|
|
90
|
-
- setup toolchain (with continuous integration and continuous delivery, using recent tools)
|
|
91
|
-
- Jest like globals, matchers, mocks, hooks, configuration and reports, running this repository's tests
|
|
92
|
-
|
|
93
|
-
## > planned milestones
|
|
94
|
-
|
|
95
|
-
- formidable test coverage
|
|
96
|
-
- module mocking, fake timers and snapshots
|
|
97
|
-
- parallel test files
|
package/bin/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// shared/config/src/config.ts
|
|
4
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
@@ -87,6 +87,62 @@ var Config = class _Config {
|
|
|
87
87
|
}
|
|
88
88
|
return new _Config(defaults, root);
|
|
89
89
|
}
|
|
90
|
+
/** Handles `--config`, writing the defaults to a TypeScript config file, or with `--config js` a JavaScript one. Returns whether it was given. */
|
|
91
|
+
static init(name, defaults, argv = process.argv.slice(2), root = process.cwd()) {
|
|
92
|
+
const index = argv.indexOf("--config");
|
|
93
|
+
if (index === -1) return false;
|
|
94
|
+
const next = argv[index + 1];
|
|
95
|
+
const extension = next === void 0 || next.startsWith("-") ? "ts" : next;
|
|
96
|
+
try {
|
|
97
|
+
console.log(
|
|
98
|
+
`created: ${_Config.export(name, defaults, extension, root)}`
|
|
99
|
+
);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(error instanceof Error ? error.message : error);
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
/** Writes the defaults to `<name>.config.<extension>` in the root, unless a config file is there already. */
|
|
107
|
+
static export(name, defaults, extension = "ts", root = process.cwd()) {
|
|
108
|
+
if (!_Config.extensions.includes(extension))
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Unknown config file type ${extension}, use ts or js.`
|
|
111
|
+
);
|
|
112
|
+
for (const existing of _Config.extensions) {
|
|
113
|
+
const file2 = `${name}.config.${existing}`;
|
|
114
|
+
if (existsSync(join(root, file2)))
|
|
115
|
+
throw new Error(`${file2} already exists.`);
|
|
116
|
+
}
|
|
117
|
+
const file = `${name}.config.${extension}`;
|
|
118
|
+
writeFileSync(
|
|
119
|
+
join(root, file),
|
|
120
|
+
`export default ${_Config.#literal(defaults)};
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
return file;
|
|
124
|
+
}
|
|
125
|
+
/** A value as JavaScript source, objects one property per line, short arrays on one line. */
|
|
126
|
+
static #literal(value, indent = "") {
|
|
127
|
+
const inner = `${indent} `;
|
|
128
|
+
const lines = (items, open, close) => items.length === 0 ? `${open}${close}` : `${open}
|
|
129
|
+
${items.map((item) => `${inner}${item},
|
|
130
|
+
`).join("")}${indent}${close}`;
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
const items = value.map((item) => _Config.#literal(item, inner));
|
|
133
|
+
const line = `[${items.join(", ")}]`;
|
|
134
|
+
return line.length <= 60 && !line.includes("\n") ? line : lines(items, "[", "]");
|
|
135
|
+
}
|
|
136
|
+
if (value?.constructor === Object)
|
|
137
|
+
return lines(
|
|
138
|
+
Object.entries(value).map(
|
|
139
|
+
([key, item]) => `${/^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key)}: ${_Config.#literal(item, inner)}`
|
|
140
|
+
),
|
|
141
|
+
"{",
|
|
142
|
+
"}"
|
|
143
|
+
);
|
|
144
|
+
return JSON.stringify(value);
|
|
145
|
+
}
|
|
90
146
|
/** Deep merges plain objects, anything else in override replaces base. */
|
|
91
147
|
static merge(base, override) {
|
|
92
148
|
const plain = (value) => value?.constructor === Object;
|
|
@@ -148,6 +204,7 @@ Options:
|
|
|
148
204
|
--listTests print the test files instead of running them
|
|
149
205
|
--passWithNoTests succeed when there are no test files
|
|
150
206
|
--testTimeout <ms> milliseconds a test or hook may take
|
|
207
|
+
--config [js] write the default testero.config.ts, or .js
|
|
151
208
|
-h, --help show this help
|
|
152
209
|
`;
|
|
153
210
|
patterns = [];
|
|
@@ -1592,7 +1649,7 @@ import { dirname as dirname2, isAbsolute, relative } from "node:path";
|
|
|
1592
1649
|
import { fileURLToPath } from "node:url";
|
|
1593
1650
|
|
|
1594
1651
|
// packages/testero/src/transformer.ts
|
|
1595
|
-
import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
|
|
1652
|
+
import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1596
1653
|
import { tmpdir } from "node:os";
|
|
1597
1654
|
import { dirname, extname, join as join2, sep } from "node:path";
|
|
1598
1655
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -1618,7 +1675,7 @@ var Transformer = class _Transformer {
|
|
|
1618
1675
|
#globals = join2(this.#directory, "globals.mjs");
|
|
1619
1676
|
#count = 0;
|
|
1620
1677
|
constructor() {
|
|
1621
|
-
|
|
1678
|
+
writeFileSync2(this.#globals, Globals.source());
|
|
1622
1679
|
}
|
|
1623
1680
|
/** Bundles a test file, returns the URL of the module to import. */
|
|
1624
1681
|
async compile(file) {
|
|
@@ -1641,7 +1698,7 @@ var Transformer = class _Transformer {
|
|
|
1641
1698
|
logLevel: "silent",
|
|
1642
1699
|
plugins: [this.#plugin()]
|
|
1643
1700
|
});
|
|
1644
|
-
|
|
1701
|
+
writeFileSync2(outfile, outputFiles[0]?.text ?? "");
|
|
1645
1702
|
return pathToFileURL2(outfile).href;
|
|
1646
1703
|
}
|
|
1647
1704
|
/** Removes the compiled files. */
|
|
@@ -2125,6 +2182,7 @@ var Testero = class {
|
|
|
2125
2182
|
|
|
2126
2183
|
// packages/testero/src/index.ts
|
|
2127
2184
|
try {
|
|
2185
|
+
if (Config.init("testero", config_default)) process.exit();
|
|
2128
2186
|
const args = new Arguments(process.argv.slice(2));
|
|
2129
2187
|
if (args.help) process.stdout.write(Arguments.usage);
|
|
2130
2188
|
else {
|
package/bin/types/arguments.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Rules } from "./rules.js";
|
|
|
2
2
|
import type { Options } from "./testero.js";
|
|
3
3
|
/** Command line arguments, named like Jest's. */
|
|
4
4
|
export default class Arguments {
|
|
5
|
-
static readonly usage = "Usage: testero [patterns...] [options]\n\nRuns the test files whose paths match a pattern, every test file without patterns.\n\nOptions:\n -t, --testNamePattern <regex> run only tests whose name matches\n --bail stop after the first failing test file\n --verbose list every test\n --listTests print the test files instead of running them\n --passWithNoTests succeed when there are no test files\n --testTimeout <ms> milliseconds a test or hook may take\n -h, --help show this help\n";
|
|
5
|
+
static readonly usage = "Usage: testero [patterns...] [options]\n\nRuns the test files whose paths match a pattern, every test file without patterns.\n\nOptions:\n -t, --testNamePattern <regex> run only tests whose name matches\n --bail stop after the first failing test file\n --verbose list every test\n --listTests print the test files instead of running them\n --passWithNoTests succeed when there are no test files\n --testTimeout <ms> milliseconds a test or hook may take\n --config [js] write the default testero.config.ts, or .js\n -h, --help show this help\n";
|
|
6
6
|
readonly patterns: string[];
|
|
7
7
|
readonly rules: Partial<Rules>;
|
|
8
8
|
namePattern: RegExp | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aljazmc/testero",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A simple, Jest like test runner. Easy to understand, easy to customize and easy to extend.",
|
|
5
5
|
"author": "aljazmc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"modular"
|
|
21
21
|
],
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": "^
|
|
23
|
+
"node": "^22.18.0 || ^24 || ^25 || ^26"
|
|
24
24
|
},
|
|
25
25
|
"types": "./bin/types/testero.d.ts",
|
|
26
26
|
"bin": "./bin/main.js",
|