proby 0.12.0 → 0.13.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 CHANGED
@@ -42,6 +42,64 @@ Run proby from your project root:
42
42
  npx proby
43
43
  ```
44
44
 
45
+ Run a single file:
46
+ ```bash
47
+ npx proby math.spec.ts
48
+ ```
49
+
50
+ Run a single group within a file:
51
+ ```bash
52
+ npx proby math.spec.ts addition
53
+ ```
54
+
55
+ ### Grouping tests
56
+
57
+ Use `test.group` in your spec files to cluster related cases. Groups can then
58
+ be targeted individually when running proby:
59
+ ```js
60
+ // src/math.spec.ts
61
+ import test from "@rcompat/test";
62
+
63
+ test.group("addition", () => {
64
+ test.case("integers", assert => {
65
+ assert(1 + 1).equals(2);
66
+ });
67
+ });
68
+
69
+ test.group("multiplication", () => {
70
+ test.case("integers", assert => {
71
+ assert(2 * 3).equals(6);
72
+ });
73
+ });
74
+ ```
75
+ ```bash
76
+ npx proby math.spec.ts addition # runs only the addition group
77
+ ```
78
+
79
+ ### Grouping tests
80
+
81
+ Use `test.group` in your spec files to cluster related cases. Groups can then
82
+ be targeted individually when running proby:
83
+ ```js
84
+ // src/math.spec.ts
85
+ import test from "@rcompat/test";
86
+
87
+ test.group("addition", () => {
88
+ test.case("integers", assert => {
89
+ assert(1 + 1).equals(2);
90
+ });
91
+ });
92
+
93
+ test.group("multiplication", () => {
94
+ test.case("integers", assert => {
95
+ assert(2 * 3).equals(6);
96
+ });
97
+ });
98
+ ```
99
+ ```bash
100
+ npx proby math.spec.ts addition # runs only the addition group
101
+ ```
102
+
45
103
  ### Writing tests
46
104
 
47
105
  Create test files with `.spec.ts` or `.spec.js` extension in your `src`
@@ -128,7 +186,8 @@ npm test
128
186
  - Files must end with `.spec.ts` or `.spec.js`
129
187
  - Files must be in the `src` directory (or `packages/*/src` for monorepos)
130
188
  - Use `@rcompat/test` to write tests
131
-
189
+ - Use `test.group` to organize cases into named groups targetable by proby
190
+
132
191
  ## Examples
133
192
 
134
193
  ### Basic assertions
@@ -0,0 +1,8 @@
1
+ declare const Schema: import("pema").ObjectType<{
2
+ monorepo: import("pema").DefaultType<import("pema").BooleanType, false>;
3
+ packages: import("pema").DefaultType<import("pema").StringType, "packages">;
4
+ include: import("pema").DefaultType<import("pema").ArrayType<import("pema").StringType>, string[]>;
5
+ conditions: import("pema").DefaultType<import("pema").ArrayType<import("pema").StringType>, string[]>;
6
+ }>;
7
+ export default Schema;
8
+ //# sourceMappingURL=Schema.d.ts.map
package/lib/Schema.js ADDED
@@ -0,0 +1,9 @@
1
+ import p from "pema";
2
+ const Schema = p({
3
+ monorepo: p.boolean.default(false),
4
+ packages: p.string.default("packages"),
5
+ include: p.array(p.string).default(["src"]),
6
+ conditions: p.array(p.string).default(["source"]),
7
+ });
8
+ export default Schema;
9
+ //# sourceMappingURL=Schema.js.map
package/lib/bin.js CHANGED
@@ -1,37 +1,45 @@
1
1
  #!/usr/bin/env node
2
- import args from "@rcompat/args";
3
- import color from "@rcompat/cli/color";
4
- import print from "@rcompat/cli/print";
2
+ import Schema from "#Schema";
3
+ import env from "@rcompat/env";
5
4
  import fs from "@rcompat/fs";
6
- import run from "./run.js";
5
+ import io from "@rcompat/io";
6
+ import is from "@rcompat/is";
7
+ import runtime from "@rcompat/runtime";
7
8
  const root = await fs.project.root();
8
- const spec_json = root.join("spec.json");
9
- if (await spec_json.exists()) {
10
- // console.log(`spec.json exists, reading`);
9
+ const ts_config_file = root.join("proby.config.ts");
10
+ const js_config_file = root.join("proby.config.js");
11
+ const user_config = await ts_config_file.exists()
12
+ ? (await ts_config_file.import("default"))
13
+ : await js_config_file.exists()
14
+ ? (await js_config_file.import("default"))
15
+ : {};
16
+ const { include, packages, conditions, monorepo } = Schema.parse(user_config);
17
+ const conditions_flag = conditions.length > 0
18
+ ? ` --conditions=${conditions.join(",")}`
19
+ : "";
20
+ const script = runtime.script;
21
+ const args = runtime.args.join(" ");
22
+ if (!is.defined(env.try("PROBY_RELAUNCHED"))) {
23
+ await io.spawn(`${runtime.bin} ${conditions_flag} ${script} ${args}`, {
24
+ inherit: true,
25
+ env: { ...process.env, PROBY_RELAUNCHED: "1" },
26
+ });
27
+ runtime.exit(0);
11
28
  }
12
- else {
13
- // console.log(`spec.json missing, continuing with defaults`);
14
- }
15
- const [file] = args;
16
- const type = await (async (base) => {
17
- if (await base.join("packages").exists()) {
18
- return "monorepo";
19
- }
20
- if (await base.join("src").exists()) {
21
- return "repo";
22
- }
23
- })(root);
24
- if (type === "monorepo") {
25
- for (const repo of await root.join("packages").list({
29
+ import run from "#run";
30
+ const [file, group] = runtime.args;
31
+ if (monorepo) {
32
+ for (const repo of await root.join(packages).list({
26
33
  filter: info => info.kind === "directory",
27
34
  })) {
28
- await run(repo.join("src"), repo.name, file);
35
+ for (const dir of include) {
36
+ await run(repo.join(dir), repo.name, file, group);
37
+ }
29
38
  }
30
39
  }
31
- else if (type === "repo") {
32
- await run(root.join("src"), undefined, file);
33
- }
34
40
  else {
35
- print(`${color.red("src")} or ${color.red("packages")} not found\n`);
41
+ for (const dir of include) {
42
+ await run(root.join(dir), undefined, file, group);
43
+ }
36
44
  }
37
45
  //# sourceMappingURL=bin.js.map
@@ -0,0 +1,9 @@
1
+ import type Schema from "#Schema";
2
+ declare const _default: (input: typeof Schema.input) => {
3
+ monorepo?: boolean | undefined;
4
+ packages?: string | undefined;
5
+ include?: string[] | undefined;
6
+ conditions?: string[] | undefined;
7
+ } | undefined;
8
+ export default _default;
9
+ //# sourceMappingURL=config.d.ts.map
package/lib/config.js ADDED
@@ -0,0 +1,2 @@
1
+ export default (input) => input;
2
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,2 @@
1
+ export declare function add(a: number, b: number): number;
2
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1,4 @@
1
+ export function add(a, b) {
2
+ return a + b;
3
+ }
4
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=math.mock.d.ts.map
@@ -0,0 +1,5 @@
1
+ import test from "@rcompat/test";
2
+ test.mock("#fixtures/static-mock/math", () => ({
3
+ add: (a, b) => 99,
4
+ }));
5
+ //# sourceMappingURL=math.mock.js.map
package/lib/run.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { FileRef } from "@rcompat/fs";
2
- declare const _default: (root: FileRef, subrepo?: string, target?: string) => Promise<void>;
2
+ declare const _default: (root: FileRef, subrepo?: string, target?: string, group?: string) => Promise<void>;
3
3
  export default _default;
4
4
  //# sourceMappingURL=run.d.ts.map
package/lib/run.js CHANGED
@@ -44,7 +44,8 @@ async function run_in_worker(spec, env) {
44
44
  });
45
45
  const context = await env_module.setup?.();
46
46
  return new Promise((resolve, reject) => {
47
- const worker = new Worker(new URL("./worker.js", import.meta.url), {
47
+ const worker_url = new URL(import.meta.url.endsWith(".ts") ? "./worker.ts" : "./worker.js", import.meta.url);
48
+ const worker = new Worker(worker_url, {
48
49
  workerData: {
49
50
  spec: spec.path,
50
51
  env: env.path,
@@ -72,7 +73,7 @@ async function run_in_worker(spec, env) {
72
73
  });
73
74
  });
74
75
  }
75
- export default async (root, subrepo, target) => {
76
+ export default async (root, subrepo, target, group) => {
76
77
  const files = await root.list({
77
78
  recursive: true,
78
79
  filter: info => extensions.some(extension => info.path.endsWith(extension)),
@@ -89,33 +90,41 @@ export default async (root, subrepo, target) => {
89
90
  await run_in_worker(file, env_file);
90
91
  continue;
91
92
  }
93
+ const mock_file = await file.sibling(file.name.replace(/\.spec\.(ts|js)$/, ".mock.$1")).or(() => null);
92
94
  repository.suite(file);
93
- await file.import();
94
- }
95
- for (const suite of repository.next()) {
96
- const failed = [];
97
- for await (const test of suite.run()) {
98
- for (const result of test.results) {
99
- if (result.passed) {
100
- print(color.green("o"));
95
+ const suite = repository.next().next().value;
96
+ try {
97
+ if (mock_file !== null)
98
+ await mock_file.import();
99
+ await file.import();
100
+ const failed = [];
101
+ for await (const test of suite.run()) {
102
+ if (group !== undefined && test.group !== group)
103
+ continue;
104
+ for (const result of test.results) {
105
+ if (result.passed) {
106
+ print(color.green("o"));
107
+ }
108
+ else {
109
+ failed.push([test, result]);
110
+ print(color.red("x"));
111
+ }
101
112
  }
102
- else {
103
- failed.push([test, result]);
104
- print(color.red("x"));
113
+ }
114
+ await suite.end();
115
+ if (failed.length > 0) {
116
+ print("\n");
117
+ for (const [test, result] of failed) {
118
+ print(`${suite.file.debase(root)} ${color.red(test.name)} \n`);
119
+ print(` expected ${stringify(result.expected)}\n`);
120
+ print(` actual ${stringify(result.actual)}\n`);
105
121
  }
106
122
  }
107
123
  }
108
- await suite.end();
109
- if (failed.length > 0) {
110
- print("\n");
111
- for (const [test, result] of failed) {
112
- print(`${suite.file.debase(root)} ${color.red(test.name)} \n`);
113
- print(` expected ${stringify(result.expected)}\n`);
114
- print(` actual ${stringify(result.actual)}\n`);
115
- }
124
+ finally {
125
+ repository.reset();
116
126
  }
117
127
  }
118
128
  print("\n");
119
- repository.reset();
120
129
  };
121
130
  //# sourceMappingURL=run.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proby",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Standard library test runner",
5
5
  "bugs": "https://github.com/rcompat/rcompat/issues",
6
6
  "license": "MIT",
@@ -16,13 +16,17 @@
16
16
  "directory": "packages/proby"
17
17
  },
18
18
  "dependencies": {
19
- "@rcompat/args": "^0.12.0",
20
- "@rcompat/cli": "^0.17.0",
21
- "@rcompat/fs": "^0.27.1",
22
- "@rcompat/assert": "^0.7.0"
19
+ "pema": "^0.5.0",
20
+ "@rcompat/assert": "^0.8.0",
21
+ "@rcompat/cli": "^0.18.0",
22
+ "@rcompat/env": "^0.17.0",
23
+ "@rcompat/io": "^0.5.0",
24
+ "@rcompat/fs": "^0.28.0",
25
+ "@rcompat/is": "^0.6.0",
26
+ "@rcompat/runtime": "^0.11.0"
23
27
  },
24
28
  "peerDependencies": {
25
- "@rcompat/test": "^0.11.2"
29
+ "@rcompat/test": "^0.12.0"
26
30
  },
27
31
  "peerDependenciesMeta": {
28
32
  "@rcompat/test": {
@@ -32,10 +36,16 @@
32
36
  "type": "module",
33
37
  "imports": {
34
38
  "#*": {
35
- "apekit": "./src/*.ts",
39
+ "source": "./src/*.ts",
36
40
  "default": "./lib/*.js"
37
41
  }
38
42
  },
43
+ "exports": {
44
+ "./config": {
45
+ "source": "./src/config.ts",
46
+ "default": "./lib/config.js"
47
+ }
48
+ },
39
49
  "scripts": {
40
50
  "build": "npm run clean && tsc",
41
51
  "clean": "rm -rf ./lib",