singularity-forge/src/tests/web-subprocess-runner.test.ts
2026-05-05 14:31:16 +02:00

180 lines
4.9 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "vitest";
const { runSubprocess, resolveModulePaths } = await import(
"../web/subprocess-runner.ts"
);
// ---------------------------------------------------------------------------
// resolveModulePaths — centralised TS loader + module path resolution
// ---------------------------------------------------------------------------
test("resolveModulePaths returns tsLoaderPath and validates it exists", () => {
const packageRoot = "/fake/package";
const result = resolveModulePaths(packageRoot, {
modules: [{ envKey: "MOD", relativePath: "src/mod.ts" }],
existsSync: () => true,
});
assert.equal(
result.tsLoaderPath,
"/fake/package/src/resources/extensions/sf/tests/resolve-ts.mjs",
);
});
test("resolveModulePaths throws when TS loader is missing", () => {
const packageRoot = "/fake/package";
assert.throws(
() =>
resolveModulePaths(packageRoot, {
modules: [{ envKey: "MOD", relativePath: "src/mod.ts" }],
existsSync: () => false,
label: "test-service",
}),
(error: Error) => {
assert.match(error.message, /test-service/);
assert.match(error.message, /not found/);
return true;
},
);
});
test("resolveModulePaths throws when any module path is missing", () => {
const packageRoot = "/fake/package";
const existingSets = new Set([
"/fake/package/src/resources/extensions/sf/tests/resolve-ts.mjs",
]);
assert.throws(
() =>
resolveModulePaths(packageRoot, {
modules: [
{ envKey: "MOD_A", relativePath: "src/a.ts" },
{ envKey: "MOD_B", relativePath: "src/b.ts" },
],
existsSync: (p: string) => existingSets.has(p),
label: "multi-mod",
}),
(error: Error) => {
assert.match(error.message, /multi-mod/);
return true;
},
);
});
test("resolveModulePaths returns env entries for each module", () => {
const packageRoot = "/fake/package";
const result = resolveModulePaths(packageRoot, {
modules: [
{ envKey: "SF_MOD_A", relativePath: "src/a.ts" },
{ envKey: "SF_MOD_B", relativePath: "src/b.ts" },
],
existsSync: () => true,
});
assert.deepEqual(result.env, {
SF_MOD_A: "/fake/package/src/a.ts",
SF_MOD_B: "/fake/package/src/b.ts",
});
});
// ---------------------------------------------------------------------------
// runSubprocess — shared execFile + JSON.parse wrapper
// ---------------------------------------------------------------------------
test("runSubprocess returns parsed JSON from a child process", async () => {
const result = await runSubprocess<{ hello: string }>({
packageRoot: process.cwd(),
script: 'process.stdout.write(JSON.stringify({ hello: "world" }));',
env: {},
label: "test",
});
assert.deepEqual(result, { hello: "world" });
});
test("runSubprocess rejects when child process exits with error", async () => {
await assert.rejects(
() =>
runSubprocess({
packageRoot: process.cwd(),
script: "process.exit(1);",
env: {},
label: "exit-test",
}),
(error: Error) => {
assert.match(error.message, /exit-test/);
assert.match(error.message, /subprocess failed/);
return true;
},
);
});
test("runSubprocess rejects on invalid JSON output", async () => {
await assert.rejects(
() =>
runSubprocess({
packageRoot: process.cwd(),
script: 'process.stdout.write("not json");',
env: {},
label: "json-test",
}),
(error: Error) => {
assert.match(error.message, /json-test/);
assert.match(error.message, /invalid JSON/);
return true;
},
);
});
test("runSubprocess applies timeout option", async () => {
await assert.rejects(
() =>
runSubprocess({
packageRoot: process.cwd(),
script: "setTimeout(() => {}, 60000);",
env: {},
label: "timeout-test",
timeoutMs: 500,
}),
(error: Error) => {
assert.match(error.message, /timeout-test/);
return true;
},
);
});
test("runSubprocess accepts custom maxBuffer", async () => {
// Verify it does not throw with a reasonable buffer
const result = await runSubprocess<{ ok: boolean }>({
packageRoot: process.cwd(),
script: "process.stdout.write(JSON.stringify({ ok: true }));",
env: {},
label: "buffer-test",
maxBuffer: 512,
});
assert.equal(result.ok, true);
});
test("runSubprocess passes env vars to child process", async () => {
const result = await runSubprocess<{ val: string }>({
packageRoot: process.cwd(),
script:
"process.stdout.write(JSON.stringify({ val: process.env.TEST_VAR }));",
env: { TEST_VAR: "hello_from_parent" },
label: "env-test",
});
assert.equal(result.val, "hello_from_parent");
});
test("runSubprocess includes stderr in error message on failure", async () => {
await assert.rejects(
() =>
runSubprocess({
packageRoot: process.cwd(),
script: 'process.stderr.write("detailed error info"); process.exit(1);',
env: {},
label: "stderr-test",
}),
(error: Error) => {
assert.match(error.message, /detailed error info/);
return true;
},
);
});