@cosmicdrift/kumiko-testing 0.391.1 → 0.392.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.
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env bun
2
- // biome-ignore-all lint/suspicious/noConsole: CLI script, console is the interface.
3
-
4
2
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
5
4
  import { parseArgs } from "node:util";
6
5
  import { BUNFIG_FILES, mergeBunfig, renderBunfigFiles } from "../src/bunfig";
7
6
  import {
@@ -23,11 +22,23 @@ const USAGE = `kumiko-testing <command>
23
22
  -h, --help print this help (also works after a command)
24
23
  `;
25
24
 
25
+ export type CliIo = {
26
+ stdout: (line: string) => void;
27
+ stderr: (line: string) => void;
28
+ cwd: string;
29
+ };
30
+
31
+ const processIo: CliIo = {
32
+ stdout: (line) => process.stdout.write(`${line}\n`),
33
+ stderr: (line) => process.stderr.write(`${line}\n`),
34
+ cwd: process.cwd(),
35
+ };
36
+
26
37
  function isHelpFlag(arg: string | undefined): boolean {
27
38
  return arg === "--help" || arg === "-h";
28
39
  }
29
40
 
30
- function runBunfig(args: readonly string[]): number {
41
+ function runBunfig(args: readonly string[], io: CliIo): number {
31
42
  const { values } = parseArgs({
32
43
  args: [...args],
33
44
  options: {
@@ -44,12 +55,13 @@ function runBunfig(args: readonly string[]): number {
44
55
  });
45
56
  let blocked = false;
46
57
  for (const [name, content] of Object.entries(files)) {
58
+ const path = join(io.cwd, name);
47
59
  let toWrite = content;
48
- if (existsSync(name)) {
49
- const merged = mergeBunfig(content, readFileSync(name, "utf-8"));
60
+ if (existsSync(path)) {
61
+ const merged = mergeBunfig(content, readFileSync(path, "utf-8"));
50
62
  if (!merged.ok) {
51
63
  const keys = merged.unknownKeys.map((k) => `${k.section}.${k.key}`).join(", ");
52
- console.error(
64
+ io.stderr(
53
65
  `${name} has key(s) kumiko-testing does not manage: ${keys}. Regenerating would drop them silently — remove them from ${name} or move them out of [install]/[test], then rerun.`,
54
66
  );
55
67
  blocked = true;
@@ -57,13 +69,13 @@ function runBunfig(args: readonly string[]): number {
57
69
  }
58
70
  toWrite = merged.content;
59
71
  }
60
- writeFileSync(name, toWrite);
61
- console.log(`wrote ${name}`);
72
+ writeFileSync(path, toWrite);
73
+ io.stdout(`wrote ${name}`);
62
74
  }
63
75
  return blocked ? 1 : 0;
64
76
  }
65
77
 
66
- async function runIntegration(args: readonly string[]): Promise<number> {
78
+ async function runIntegration(args: readonly string[], io: CliIo): Promise<number> {
67
79
  const { values, positionals } = parseArgs({
68
80
  args: [...args],
69
81
  options: {
@@ -74,23 +86,23 @@ async function runIntegration(args: readonly string[]): Promise<number> {
74
86
  allowPositionals: true,
75
87
  strict: true,
76
88
  });
77
- if (!existsSync(BUNFIG_FILES.integration)) {
78
- console.error(`${BUNFIG_FILES.integration} not found - run \`kumiko-testing bunfig\` first`);
89
+ if (!existsSync(join(io.cwd, BUNFIG_FILES.integration))) {
90
+ io.stderr(`${BUNFIG_FILES.integration} not found - run \`kumiko-testing bunfig\` first`);
79
91
  return 1;
80
92
  }
81
93
  let files: string[];
82
94
  if (positionals.length > 0) {
83
95
  try {
84
- files = resolveRequestedIntegrationFiles(process.cwd(), positionals);
96
+ files = resolveRequestedIntegrationFiles(io.cwd, positionals);
85
97
  if (files.length === 0) throw new Error("no *.integration.test.ts files found");
86
98
  } catch (error) {
87
- console.error(error instanceof Error ? error.message : String(error));
99
+ io.stderr(error instanceof Error ? error.message : String(error));
88
100
  return 1;
89
101
  }
90
102
  } else {
91
- files = selectIntegrationFiles(listIntegrationTestFiles(process.cwd()));
103
+ files = selectIntegrationFiles(listIntegrationTestFiles(io.cwd));
92
104
  if (files.length === 0) {
93
- console.error("no *.integration.test.ts files found");
105
+ io.stderr("no *.integration.test.ts files found");
94
106
  return 1;
95
107
  }
96
108
  }
@@ -105,18 +117,23 @@ async function runIntegration(args: readonly string[]): Promise<number> {
105
117
  // template run id set by runWithTestDbTemplates reaches the test process.
106
118
  () =>
107
119
  Bun.spawn(["bun", ...testArgs], {
120
+ cwd: io.cwd,
108
121
  stdio: ["inherit", "inherit", "inherit"],
109
122
  env: process.env,
110
123
  }).exited,
111
124
  );
112
125
  }
113
126
 
114
- const [command, ...rest] = process.argv.slice(2);
115
- if (isHelpFlag(command) || rest.some(isHelpFlag)) {
116
- console.log(USAGE);
117
- process.exit(0);
127
+ export async function main(argv: readonly string[], io: CliIo = processIo): Promise<number> {
128
+ const [command, ...rest] = argv;
129
+ if (isHelpFlag(command) || rest.some(isHelpFlag)) {
130
+ io.stdout(USAGE);
131
+ return 0;
132
+ }
133
+ if (command === "bunfig") return runBunfig(rest, io);
134
+ if (command === "integration") return runIntegration(rest, io);
135
+ io.stderr(USAGE);
136
+ return 2;
118
137
  }
119
- if (command === "bunfig") process.exit(runBunfig(rest));
120
- if (command === "integration") process.exit(await runIntegration(rest));
121
- console.error(USAGE);
122
- process.exit(2);
138
+
139
+ if (import.meta.main) process.exit(await main(process.argv.slice(2)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-testing",
3
- "version": "0.391.1",
3
+ "version": "0.392.0",
4
4
  "description": "Test template for Kumiko apps: per-flow seedTenant, app test stack, canonical test preloads, bunfig generator and integration runner.",
5
5
  "license": "MIT",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -103,9 +103,9 @@
103
103
  "kumiko-testing": "./bin/kumiko-testing.ts"
104
104
  },
105
105
  "dependencies": {
106
- "@cosmicdrift/kumiko-framework": "0.391.1",
107
- "@cosmicdrift/kumiko-guards": "0.391.1",
108
- "@cosmicdrift/kumiko-types": "0.391.1",
106
+ "@cosmicdrift/kumiko-framework": "0.392.0",
107
+ "@cosmicdrift/kumiko-guards": "0.392.0",
108
+ "@cosmicdrift/kumiko-types": "0.392.0",
109
109
  "zod": "^4.6.7"
110
110
  },
111
111
  "peerDependencies": {
@@ -129,8 +129,8 @@
129
129
  }
130
130
  },
131
131
  "devDependencies": {
132
- "@cosmicdrift/kumiko-bundled-features": "0.391.1",
133
- "@cosmicdrift/kumiko-dev-server": "0.391.1",
132
+ "@cosmicdrift/kumiko-bundled-features": "0.392.0",
133
+ "@cosmicdrift/kumiko-dev-server": "0.392.0",
134
134
  "@happy-dom/global-registrator": "^21.0.4",
135
135
  "@playwright/test": "^1.62.1",
136
136
  "@testing-library/dom": "^10.4.1",
package/src/changes.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.392.0",
4
+ "type": "improvement",
5
+ "title": "kumiko-testing exports main(argv, io)",
6
+ "detail": "The kumiko-testing bin exports main(argv, io), which returns the exit code and writes through the given io, so its commands can run in-process. Invocation from the shell is unchanged."
7
+ },
2
8
  {
3
9
  "version": "0.390.0",
4
10
  "type": "breaking",