proby 0.20.0 → 0.22.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/lib/bin.js CHANGED
@@ -31,19 +31,26 @@ if (!is.defined(env.try("PROBY_RELAUNCHED"))) {
31
31
  runtime.exit(0);
32
32
  }
33
33
  import run from "#run";
34
- const [file, group] = runtime.args;
34
+ const verbosity_flags = {
35
+ "-v": 1,
36
+ "--verbose": 1,
37
+ "-vv": 2,
38
+ "--very-verbose": 2,
39
+ };
40
+ const verbose = runtime.args.reduce((max, arg) => Math.max(max, verbosity_flags[arg] ?? 0), 0);
41
+ const [file, group] = runtime.args.filter(arg => !(arg in verbosity_flags));
35
42
  if (monorepo) {
36
43
  for (const repo of await root.join(packages).list({
37
44
  filter: info => info.type === "directory",
38
45
  })) {
39
46
  for (const dir of include) {
40
- await run(repo.join(dir), repo.name, file, group);
47
+ await run(repo.join(dir), repo.name, file, group, verbose);
41
48
  }
42
49
  }
43
50
  }
44
51
  else {
45
52
  for (const dir of include) {
46
- await run(root.join(dir), undefined, file, group);
53
+ await run(root.join(dir), undefined, file, group, verbose);
47
54
  }
48
55
  }
49
56
  //# sourceMappingURL=bin.js.map
package/lib/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { Config } from "#Schema";
2
- declare const _default: (input: Partial<Config>) => Partial<Config>;
3
2
  export default _default;
3
+ declare function _default(input: Partial<Config>): Partial<Config>;
4
4
  //# sourceMappingURL=config.d.ts.map
package/lib/run.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import type { FileRef } from "@rcompat/fs";
2
- declare const _default: (root: FileRef, subrepo?: string, target?: string, group?: string) => Promise<void>;
2
+ export type VerbosityLevel = 0 | 1 | 2;
3
+ export declare function reset_totals(): void;
4
+ export declare function print_summary(): void;
3
5
  export default _default;
6
+ declare function _default(root: FileRef, subrepo?: string, target?: string, group?: string, verbose?: VerbosityLevel): Promise<void>;
4
7
  //# sourceMappingURL=run.d.ts.map
package/lib/run.js CHANGED
@@ -3,7 +3,6 @@ import cli from "@rcompat/cli";
3
3
  import fs from "@rcompat/fs";
4
4
  import is from "@rcompat/is";
5
5
  import repository from "@rcompat/test/repository";
6
- import { Worker } from "node:worker_threads";
7
6
  const extensions = [".spec.ts", ".spec.js"];
8
7
  const base_scalars = ["boolean", "number", "string", "symbol"];
9
8
  function stringify_scalar(x) {
@@ -16,8 +15,9 @@ function stringify_scalar(x) {
16
15
  return x.toString();
17
16
  if (is.bigint(x))
18
17
  return x.toString() + "n";
19
- if (is.function(x))
18
+ if (is.function(x)) {
20
19
  return `[Function${is.text(x.name) ? `: ${x.name}` : ""}]`;
20
+ }
21
21
  }
22
22
  function stringify(x) {
23
23
  const scalar = stringify_scalar(x);
@@ -36,101 +36,401 @@ function stringify(x) {
36
36
  }
37
37
  return String(x);
38
38
  }
39
- async function run_in_worker(spec, env) {
40
- const env_module = assert.shape((await import(env.path)).default, {
41
- globals: "function",
42
- setup: "function?",
43
- teardown: "function?",
44
- });
45
- const context = await env_module.setup?.();
46
- return new Promise((resolve, reject) => {
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, {
49
- workerData: {
50
- spec: spec.path,
51
- env: env.path,
52
- context,
53
- },
39
+ function format_duration(ms) {
40
+ return `[${ms.toFixed(2)}ms]`;
41
+ }
42
+ function format_ms(ms) {
43
+ return `${ms.toFixed(2)}ms`;
44
+ }
45
+ function print_captured_output(output, indent = "") {
46
+ for (const entry of output) {
47
+ const label = entry.stream === "stdout" ? "Log" : "Error";
48
+ const lines = entry.text.split("\n").filter(line => line.length > 0);
49
+ if (lines.length > 0)
50
+ cli.print("\n");
51
+ for (const line of lines)
52
+ cli.print(`${indent}${label}: ${line}\n`);
53
+ }
54
+ }
55
+ function print_expected_actual(expected, actual) {
56
+ const expected_beginning = cli.fg.dim("Expected");
57
+ const expected_end = cli.fg.dim(stringify(expected));
58
+ const actual_beginning = cli.fg.red("Actual");
59
+ const actual_end = cli.fg.red(stringify(actual));
60
+ cli.print(`${expected_beginning} ${expected_end}\n`);
61
+ cli.print(`${actual_beginning} ${actual_end}\n`);
62
+ }
63
+ // Patches process.stdout/stderr and console.* to buffer output, runs the
64
+ // async iterator's next step, then restores. This lets us attribute each
65
+ // test's console output to that test rather than letting it leak to the top.
66
+ async function next_test_with_std_output(iter) {
67
+ const output = [];
68
+ const orig_stdout = process.stdout.write.bind(process.stdout);
69
+ const orig_stderr = process.stderr.write.bind(process.stderr);
70
+ const orig_log = console.log;
71
+ const orig_info = console.info;
72
+ const orig_warn = console.warn;
73
+ const orig_error = console.error;
74
+ const push = (stream, args) => {
75
+ output.push({ stream, text: args.map(String).join(" ") });
76
+ };
77
+ process.stdout.write = (chunk) => {
78
+ push("stdout", [chunk]);
79
+ return true;
80
+ };
81
+ process.stderr.write = (chunk) => {
82
+ push("stderr", [chunk]);
83
+ return true;
84
+ };
85
+ console.log = (...args) => push("stdout", args);
86
+ console.info = (...args) => push("stdout", args);
87
+ console.warn = (...args) => push("stderr", args);
88
+ console.error = (...args) => push("stderr", args);
89
+ let result;
90
+ try {
91
+ result = await iter.next();
92
+ }
93
+ finally {
94
+ process.stdout.write = orig_stdout;
95
+ process.stderr.write = orig_stderr;
96
+ console.log = orig_log;
97
+ console.info = orig_info;
98
+ console.warn = orig_warn;
99
+ console.error = orig_error;
100
+ }
101
+ return { done: result.done ?? false, value: result.value, output };
102
+ }
103
+ const INDENT = " "; // two spaces per nesting level
104
+ function indent_at(depth) {
105
+ return INDENT.repeat(depth);
106
+ }
107
+ const grand_totals = {
108
+ passed: 0,
109
+ failed: 0,
110
+ duration: 0,
111
+ };
112
+ let summary_printed = false;
113
+ export function reset_totals() {
114
+ grand_totals.passed = 0;
115
+ grand_totals.failed = 0;
116
+ grand_totals.duration = 0;
117
+ summary_printed = false;
118
+ }
119
+ function print_totals_line(passed, failed, duration) {
120
+ const passed_color = failed > 0 ? cli.fg.dim : cli.fg.green;
121
+ const failed_color = failed > 0 ? cli.fg.red : cli.fg.dim;
122
+ const passed_text = passed_color(passed + " pass");
123
+ const failed_text = failed_color(failed + " fail");
124
+ const dim = cli.fg.dim;
125
+ const duration_text = dim(format_ms(duration));
126
+ const dim_comma = dim(",");
127
+ const passed_with_comma = `${passed_text}${dim_comma}`;
128
+ const failed_with_comma = `${failed_text}${dim_comma}`;
129
+ const passed_and_failed = `${passed_with_comma} ${failed_with_comma}`;
130
+ cli.print(`${dim("[")}${passed_and_failed} ${duration_text}${dim("]")}`);
131
+ }
132
+ // Used for the per-file summary line at plain verbose (-v) level, where we
133
+ // only want to show timing, not pass/fail counts (those are already
134
+ // visible in the package/summary totals).
135
+ function print_duration_only(duration) {
136
+ const dim = cli.fg.dim;
137
+ cli.print(`${dim("[")}${dim(format_ms(duration))}${dim("]")}`);
138
+ }
139
+ // only the first call actually prints anything.
140
+ export function print_summary() {
141
+ if (summary_printed)
142
+ return;
143
+ if (grand_totals.passed + grand_totals.failed === 0)
144
+ return;
145
+ summary_printed = true;
146
+ cli.print("\n");
147
+ const passed_color = grand_totals.failed > 0 ? cli.fg.dim : cli.fg.green;
148
+ const failed_color = grand_totals.failed > 0 ? cli.fg.red : cli.fg.dim;
149
+ const total_color = grand_totals.failed > 0 ? cli.bg.red : cli.bg.green;
150
+ const formatted_duration = format_ms(grand_totals.duration);
151
+ const total_text = total_color(" SUMMARY ");
152
+ const passed = passed_color("Passed: " + grand_totals.passed);
153
+ const failed = failed_color("Failed: " + grand_totals.failed);
154
+ const duration = cli.fg.dim("Duration: " + formatted_duration);
155
+ cli.print(`${total_text}\n${passed}\n${failed}\n${duration}\n`);
156
+ cli.print("\n");
157
+ cli.print("\n");
158
+ }
159
+ // Guarantees the grand total is printed exactly once, after every subrepo
160
+ // has been processed, with no dependency on the caller remembering to call
161
+ // print_summary() itself.
162
+ process.on("exit", () => {
163
+ print_summary();
164
+ });
165
+ function group_failed(node) {
166
+ return node.tests.some(t => t.results.some(r => !r.passed))
167
+ || node.children.some(group_failed);
168
+ }
169
+ async function process_file(file, group) {
170
+ const result = {
171
+ file,
172
+ passed: 0,
173
+ failed: 0,
174
+ duration: 0,
175
+ items: [],
176
+ };
177
+ const env_file = await file.sibling(file.name.replace(/\.spec\.(ts|js)$/, ".env.ts")).or(() => null);
178
+ const mock_file = await file.sibling(file.name.replace(/\.spec\.(ts|js)$/, ".mock.$1")).or(() => null);
179
+ let env_module;
180
+ if (!is.null(env_file)) {
181
+ env_module = assert.shape((await import(env_file.path)).default, {
182
+ globals: "function",
183
+ setup: "function?",
184
+ teardown: "function?",
54
185
  });
55
- worker.on("message", ({ results }) => {
56
- const failed = results.filter((r) => !r.passed);
57
- for (const result of results) {
58
- cli.print(result.passed ? cli.fg.green("o") : cli.fg.red("x"));
186
+ }
187
+ repository.suite(file);
188
+ const suite = repository.next().next().value;
189
+ // Captured inside the try (where `context` is inferred from setup),
190
+ // invoked from finally so cleanup runs even when suite iteration throws.
191
+ let cleanup;
192
+ try {
193
+ if (!is.null(mock_file))
194
+ await mock_file.import();
195
+ await file.import();
196
+ const context = await env_module?.setup?.();
197
+ // Apply the env's globals to globalThis for the duration of this suite,
198
+ // then restore the previous values afterwards. This replaces the free
199
+ // process-level isolation the old per-spec worker provided; in-process,
200
+ // all spec files share one globalThis, so without restore the globals
201
+ // would leak into subsequent spec files (order-dependent failures).
202
+ const globals = env_module?.globals(context);
203
+ const applied_globals = is.defined(globals)
204
+ ? Object.keys(globals).map(k => [k, globalThis[k]])
205
+ : undefined;
206
+ if (is.defined(globals)) {
207
+ Object.assign(globalThis, globals);
208
+ }
209
+ cleanup = async () => {
210
+ if (is.defined(applied_globals)) {
211
+ for (const [k, v] of applied_globals) {
212
+ if (v === undefined) {
213
+ delete globalThis[k];
214
+ }
215
+ else {
216
+ globalThis[k] = v;
217
+ }
218
+ }
59
219
  }
60
- if (failed.length > 0) {
61
- cli.print("\n");
62
- for (const result of failed) {
63
- cli.print(`${spec.debase(spec.directory)} ${cli.fg.red(result.name)}\n`);
64
- cli.print(` expected ${stringify(result.expected)}\n`);
65
- cli.print(` actual ${stringify(result.actual)}\n`);
220
+ await env_module?.teardown?.(context);
221
+ };
222
+ // Each entry tracks a group name, its own tests, and any child groups
223
+ // that were flushed into it from the stack below.
224
+ const stack = [];
225
+ function flush_top() {
226
+ const node = stack.pop();
227
+ if (stack.length > 0) {
228
+ // Attach this node as a child of the new top.
229
+ stack.at(-1).children.push(node);
230
+ }
231
+ else {
232
+ // Root group — record it in arrival order.
233
+ result.items.push({ kind: "group", node });
234
+ }
235
+ }
236
+ const iter = suite.run()[Symbol.asyncIterator]();
237
+ let doneIterating = false;
238
+ while (is.falsy(doneIterating)) {
239
+ const { done, value, output } = await next_test_with_std_output(iter);
240
+ doneIterating = is.truthy(done) || !is.defined(value);
241
+ if (doneIterating)
242
+ break;
243
+ const { test, duration } = value;
244
+ if (is.defined(group) && test.group !== group)
245
+ continue;
246
+ const testEntry = {
247
+ name: test.name,
248
+ group: test.group,
249
+ duration,
250
+ output,
251
+ results: test.results,
252
+ };
253
+ // Counted per test.case, not per assert — a test.case with several
254
+ // asserts still contributes exactly one pass or one fail.
255
+ const test_failed = testEntry.results.some(r => !r.passed);
256
+ if (test_failed) {
257
+ result.failed++;
258
+ }
259
+ else {
260
+ result.passed++;
261
+ }
262
+ result.duration += duration;
263
+ if (is.defined(test.group)) {
264
+ if (stack.length === 0 || stack.at(-1).name !== test.group) {
265
+ stack.push({ name: test.group, tests: [], children: [] });
66
266
  }
267
+ stack.at(-1).tests.push(testEntry);
268
+ continue;
67
269
  }
68
- });
69
- worker.on("error", reject);
70
- worker.on("exit", async () => {
71
- await env_module.teardown?.(context);
72
- resolve();
73
- });
74
- });
270
+ // Ungrouped test — flush everything on the stack first, to preserve
271
+ // arrival order relative to any group that came before it.
272
+ while (stack.length > 0) {
273
+ flush_top();
274
+ }
275
+ result.items.push({ kind: "test", test: testEntry });
276
+ }
277
+ // Flush any remaining groups at end of file.
278
+ while (stack.length > 0) {
279
+ flush_top();
280
+ }
281
+ }
282
+ finally {
283
+ // Restore any globals we applied, then tear down the env context.
284
+ // Runs even when suite iteration throws, so globals never leak across
285
+ // spec files and teardown always pairs with setup. `repository.reset()`
286
+ // is nested so a throwing teardown can't skip it.
287
+ try {
288
+ await cleanup?.();
289
+ }
290
+ finally {
291
+ repository.reset();
292
+ }
293
+ }
294
+ return result;
295
+ }
296
+ function print_group(node, depth, show_all) {
297
+ const failed = group_failed(node);
298
+ const isPassingEntireGroup = !show_all && !failed;
299
+ if (isPassingEntireGroup)
300
+ return;
301
+ const group_indent = indent_at(depth + 1);
302
+ const test_indent = indent_at(depth + 2);
303
+ const icon = failed ? cli.fg.red("✗") : cli.fg.green("✓");
304
+ const total_duration = node.tests.reduce((n, t) => n + t.duration, 0) +
305
+ node.children.reduce((n, c) => n + c.tests.reduce((m, t) => m + t.duration, 0), 0);
306
+ const group_label = cli.fg.dim(node.name);
307
+ const group_time = cli.fg.dim(format_duration(total_duration));
308
+ const group_label_after_check = failed
309
+ ? `${group_label} ${group_time}`
310
+ : `${cli.fg.dim(group_label)} ${group_time}`;
311
+ cli.print(`${group_indent}${icon} ${group_label_after_check}\n`);
312
+ // Print tests that belong to this group come first (before any child
313
+ // group), then child groups are printed at depth+1. Each test.case is
314
+ // printed as a single line, regardless of how many asserts it contains.
315
+ for (const test of node.tests) {
316
+ const time = format_duration(test.duration);
317
+ const test_failed = test.results.some(r => !r.passed);
318
+ if (test_failed) {
319
+ const beginning = `${test_indent}${cli.fg.red("✗")}`;
320
+ cli.print(`${beginning} ${test.name} ${cli.fg.dim(time)}\n`);
321
+ print_captured_output(test.output);
322
+ cli.print("\n");
323
+ for (const r of test.results) {
324
+ if (!r.passed) {
325
+ print_expected_actual(r.expected, r.actual);
326
+ cli.print("\n");
327
+ }
328
+ }
329
+ }
330
+ else {
331
+ if (!show_all)
332
+ continue; // hide passing lines unless very verbose
333
+ const beginning = `${test_indent}${cli.fg.green("✓")}`;
334
+ cli.print(`${beginning} ${cli.fg.dim(`${test.name} ${time}\n`)}`);
335
+ }
336
+ }
337
+ for (const child of node.children) {
338
+ if (!show_all && !group_failed(child))
339
+ continue;
340
+ print_group(child, depth + 1, show_all);
341
+ }
342
+ }
343
+ function print_ungrouped_test(test, show_all) {
344
+ const time = format_duration(test.duration);
345
+ const test_failed = test.results.some(r => !r.passed);
346
+ if (!show_all && !test_failed)
347
+ return;
348
+ if (test_failed) {
349
+ cli.print(` ${cli.fg.red("✗")} ${test.name} ${time}\n`);
350
+ print_captured_output(test.output, INDENT);
351
+ cli.print("\n");
352
+ for (const r of test.results) {
353
+ if (!r.passed) {
354
+ print_expected_actual(r.expected, r.actual);
355
+ cli.print("\n");
356
+ }
357
+ }
358
+ }
359
+ else {
360
+ const test_name_and_time = cli.fg.dim(test.name + " " + time);
361
+ cli.print(` ${cli.fg.green("✓")} ${test_name_and_time}\n`);
362
+ }
75
363
  }
76
- export default async (root, subrepo, target, group) => {
364
+ function render_file_items(items, show_all) {
365
+ for (const item of items) {
366
+ if (item.kind === "group")
367
+ print_group(item.node, 0, show_all);
368
+ else
369
+ print_ungrouped_test(item.test, show_all);
370
+ }
371
+ }
372
+ export default async (root, subrepo, target, group, verbose = 0) => {
373
+ const show_all = verbose >= 2;
77
374
  const resolved = is.defined(target) ? fs.resolve(target).path : undefined;
78
375
  const files = await root.list({
79
376
  recursive: true,
80
377
  filter: info => {
81
378
  const path = info.path;
82
- if (is.undefined(resolved))
379
+ if (is.undefined(resolved)) {
83
380
  return extensions.some(e => path.endsWith(e));
84
- if (extensions.some(e => resolved.endsWith(e)))
381
+ }
382
+ if (extensions.some(e => resolved.endsWith(e))) {
85
383
  return path.endsWith(resolved);
86
- return info.path.startsWith(resolved) && extensions.some(e => path.endsWith(e));
384
+ }
385
+ return info.path.startsWith(resolved) &&
386
+ extensions.some(e => path.endsWith(e));
87
387
  },
88
388
  });
89
389
  if (files.length === 0)
90
390
  return;
91
- if (is.defined(subrepo))
92
- cli.print(`${cli.fg.blue(subrepo)}\n`);
391
+ // Phase 1: run every file's tests and collect results — nothing is
392
+ // printed yet, so we can know each file's (and the subrepo's) totals
393
+ // before printing anything for it.
394
+ const file_results = [];
93
395
  for (const file of files) {
94
- const env_file = await file.sibling(file.name.replace(/\.spec\.(ts|js)$/, ".env.ts")).or(() => null);
95
- if (env_file !== null) {
96
- await run_in_worker(file, env_file);
97
- continue;
396
+ file_results.push(await process_file(file, group));
397
+ }
398
+ const subrepo_passed = file_results.reduce((n, f) => n + f.passed, 0);
399
+ const subrepo_failed = file_results.reduce((n, f) => n + f.failed, 0);
400
+ const subrepo_duration = file_results.reduce((n, f) => n + f.duration, 0);
401
+ grand_totals.passed += subrepo_passed;
402
+ grand_totals.failed += subrepo_failed;
403
+ grand_totals.duration += subrepo_duration;
404
+ // Phase 2: render. Subrepo header + totals only apply when this call is
405
+ // actually part of a monorepo (i.e. `subrepo` was passed in) — otherwise
406
+ // it would just repeat the grand total.
407
+ const show_subrepo = is.defined(subrepo) &&
408
+ (verbose >= 1 || subrepo_failed > 0);
409
+ if (show_subrepo) {
410
+ cli.print("\n");
411
+ cli.print(`${cli.bg.blue(" PACKAGE ")} ${subrepo} `);
412
+ if (verbose >= 1) {
413
+ print_totals_line(subrepo_passed, subrepo_failed, subrepo_duration);
98
414
  }
99
- const mock_file = await file.sibling(file.name.replace(/\.spec\.(ts|js)$/, ".mock.$1")).or(() => null);
100
- repository.suite(file);
101
- const suite = repository.next().next().value;
102
- try {
103
- if (mock_file !== null)
104
- await mock_file.import();
105
- await file.import();
106
- const failed = [];
107
- for await (const test of suite.run()) {
108
- if (is.defined(group) && test.group !== group)
109
- continue;
110
- for (const result of test.results) {
111
- if (result.passed) {
112
- cli.print(cli.fg.green("o"));
113
- }
114
- else {
115
- failed.push([test, result]);
116
- cli.print(cli.fg.red("x"));
117
- }
118
- }
119
- }
120
- await suite.end();
121
- if (failed.length > 0) {
122
- cli.print("\n");
123
- for (const [test, result] of failed) {
124
- cli.print(`${suite.file.debase(root)} ${cli.fg.red(test.name)} \n`);
125
- cli.print(` expected ${stringify(result.expected)}\n`);
126
- cli.print(` actual ${stringify(result.actual)}\n`);
127
- }
128
- }
415
+ cli.print("\n\n");
416
+ }
417
+ for (const result of file_results) {
418
+ const show_file = verbose >= 1 || result.failed > 0;
419
+ if (!show_file)
420
+ continue;
421
+ cli.print(cli.fg.gray(`${result.file.debase(root)} `));
422
+ // At plain verbose (-v) we only show timing on the file line — pass/
423
+ // fail counts are already visible in the package/summary totals. At
424
+ // very verbose (-vv) we show the full breakdown, since individual
425
+ // test.case results are printed underneath.
426
+ if (show_all) {
427
+ print_totals_line(result.passed, result.failed, result.duration);
129
428
  }
130
- finally {
131
- repository.reset();
429
+ else if (verbose >= 1) {
430
+ print_duration_only(result.duration);
132
431
  }
432
+ cli.print("\n");
433
+ render_file_items(result.items, show_all);
133
434
  }
134
- cli.print("\n");
135
435
  };
136
436
  //# sourceMappingURL=run.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proby",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Standard library test runner",
5
5
  "bugs": "https://github.com/rcompat/rcompat/issues",
6
6
  "license": "MIT",
@@ -16,18 +16,18 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@rcompat/assert": "^0.14.0",
19
- "@rcompat/cli": "^0.25.0",
20
- "@rcompat/fs": "^0.35.0",
21
19
  "@rcompat/env": "^0.23.0",
22
- "@rcompat/is": "^0.12.0",
20
+ "@rcompat/fs": "^0.35.1",
21
+ "@rcompat/cli": "^0.25.0",
22
+ "@rcompat/io": "^0.11.0",
23
23
  "@rcompat/runtime": "^0.17.0",
24
- "@rcompat/io": "^0.11.0"
24
+ "@rcompat/is": "^0.12.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@rcompat/type": "^0.18.0"
28
28
  },
29
29
  "peerDependencies": {
30
- "@rcompat/test": "^0.18.0"
30
+ "@rcompat/test": "^0.20.0"
31
31
  },
32
32
  "peerDependenciesMeta": {
33
33
  "@rcompat/test": {
package/lib/worker.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=worker.d.ts.map
package/lib/worker.js DELETED
@@ -1,29 +0,0 @@
1
- import assert from "@rcompat/assert";
2
- import fs from "@rcompat/fs";
3
- import repository from "@rcompat/test/repository";
4
- import { parentPort, workerData } from "node:worker_threads";
5
- const { spec, env, context } = workerData;
6
- const env_module = assert.shape((await import(env)).default, {
7
- globals: "function",
8
- setup: "function?",
9
- teardown: "function?",
10
- });
11
- Object.assign(globalThis, env_module.globals(context));
12
- repository.suite(fs.ref(spec));
13
- await import(spec);
14
- const results = [];
15
- for (const suite of repository.next()) {
16
- for await (const test of suite.run()) {
17
- for (const result of test.results) {
18
- results.push({
19
- name: test.name,
20
- passed: result.passed,
21
- expected: result.expected,
22
- actual: result.actual,
23
- });
24
- }
25
- }
26
- await suite.end();
27
- }
28
- parentPort.postMessage({ results });
29
- //# sourceMappingURL=worker.js.map