Skip to content

Commit 1586085

Browse files
committed
test: share node eval helpers
1 parent 11745de commit 1586085

9 files changed

Lines changed: 81 additions & 69 deletions

packages/sdk/src/package.e2e.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
33
import os from "node:os";
44
import path from "node:path";
55
import { afterEach, describe, expect, it } from "vitest";
6+
import { createNodeEvalArgs } from "../../../src/test-utils/node-process.js";
67

78
type CommandResult = {
89
stdout: string;
@@ -104,7 +105,7 @@ describe("OpenClaw SDK package e2e", () => {
104105
});
105106
if (event.type !== "run.started") throw new Error("unexpected event normalization");
106107
`;
107-
await runCommand(process.execPath, ["--input-type=module", "-e", importScript], {
108+
await runCommand(process.execPath, createNodeEvalArgs(importScript, { evalFlag: "-e" }), {
108109
cwd: tempDir,
109110
});
110111
});

src/infra/net/proxy/external-proxy.e2e.test.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { Duplex } from "node:stream";
88
import { afterEach, describe, expect, it } from "vitest";
99
import { WebSocketServer } from "ws";
1010
import { withTempDir } from "../../../test-helpers/temp-dir.js";
11+
import { createNodeEvalArgs } from "../../../test-utils/node-process.js";
1112
import { resolveSystemBin } from "../../resolve-system-bin.js";
1213
import { resolvePreferredOpenClawTmpDir } from "../../tmp-openclaw-dir.js";
1314

@@ -248,15 +249,11 @@ async function runNodeModule(
248249
stdout: string;
249250
stderr: string;
250251
}> {
251-
const child = spawn(
252-
process.execPath,
253-
["--import", "tsx", "--input-type=module", "--eval", source],
254-
{
255-
cwd: process.cwd(),
256-
env,
257-
stdio: ["ignore", "pipe", "pipe"],
258-
},
259-
);
252+
const child = spawn(process.execPath, createNodeEvalArgs(source, { imports: ["tsx"] }), {
253+
cwd: process.cwd(),
254+
env,
255+
stdio: ["ignore", "pipe", "pipe"],
256+
});
260257

261258
let stdout = "";
262259
let stderr = "";

src/infra/net/undici-global-dispatcher.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { execFileSync } from "node:child_process";
21
import path from "node:path";
32
import { pathToFileURL } from "node:url";
43
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
4+
import { execNodeEvalSync } from "../../test-utils/node-process.js";
55

66
const {
77
Agent,
@@ -196,11 +196,7 @@ describe("ensureGlobalUndiciStreamTimeouts", () => {
196196
delete env[key];
197197
}
198198

199-
const output = execFileSync(
200-
process.execPath,
201-
["--import", "tsx", "--input-type=module", "--eval", source],
202-
{ cwd: process.cwd(), encoding: "utf8", env },
203-
);
199+
const output = execNodeEvalSync(source, { env, imports: ["tsx"] });
204200

205201
expect(output.trim()).toBe("ok");
206202
});

src/plugin-sdk/fetch-runtime.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { execFileSync } from "node:child_process";
21
import path from "node:path";
32
import { pathToFileURL } from "node:url";
43
import { describe, expect, it } from "vitest";
4+
import { execNodeEvalSync } from "../test-utils/node-process.js";
55

66
describe("plugin SDK fetch runtime", () => {
77
it("does not initialize the undici global dispatcher on import", () => {
@@ -27,11 +27,7 @@ describe("plugin SDK fetch runtime", () => {
2727
delete env[key];
2828
}
2929

30-
const output = execFileSync(
31-
process.execPath,
32-
["--import", "tsx", "--input-type=module", "--eval", source],
33-
{ cwd: process.cwd(), encoding: "utf8", env },
34-
);
30+
const output = execNodeEvalSync(source, { env, imports: ["tsx"] });
3531

3632
expect(output.trim()).toBe("ok");
3733
});

src/plugins/loader.git-path-regression.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { execFileSync } from "node:child_process";
21
import fs from "node:fs";
32
import path from "node:path";
43
import { afterEach, describe, expect, it } from "vitest";
4+
import { execNodeEvalSync } from "../test-utils/node-process.js";
55
import {
66
cleanupTrackedTempDirs,
77
makeTrackedTempDir,
@@ -85,9 +85,8 @@ export const copiedRuntimeMarker = {
8585
dep: mod.copiedRuntimeMarker?.resolveOutboundSendDep?.(),
8686
}));
8787
`;
88-
const raw = execFileSync(process.execPath, ["--input-type=module", "--eval", script], {
88+
const raw = execNodeEvalSync(script, {
8989
cwd: process.cwd(),
90-
encoding: "utf-8",
9190
});
9291
const result = JSON.parse(raw) as {
9392
withoutAliasThrew: boolean;

src/test-utils/fs-scan-assertions.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { spawnSync } from "node:child_process";
21
import fs from "node:fs";
32
import { expect, vi } from "vitest";
3+
import { spawnNodeEvalSync } from "./node-process.js";
44

55
type FsScanCounter = "existsSync" | "readdirSync" | "statSync";
66

@@ -63,12 +63,8 @@ export function expectNoNodeFsScans<T>(
6363
},
6464
): T {
6565
const counters = options?.counters ?? ["existsSync", "readdirSync"];
66-
const result = spawnSync(
67-
process.execPath,
68-
[
69-
"--input-type=module",
70-
"--eval",
71-
`
66+
const result = spawnNodeEvalSync(
67+
`
7268
import fs from "node:fs";
7369
import { syncBuiltinESMExports } from "node:module";
7470
const counts = ${JSON.stringify(Object.fromEntries(counters.map((name) => [name, 0])))};
@@ -88,10 +84,8 @@ export function expectNoNodeFsScans<T>(
8884
})();
8985
console.log(JSON.stringify({ counts, result }));
9086
`,
91-
],
9287
{
9388
cwd: process.cwd(),
94-
encoding: "utf8",
9589
stdio: ["ignore", "pipe", "pipe"],
9690
},
9791
);

src/test-utils/node-process.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { execFileSync, spawnSync, type SpawnSyncReturns } from "node:child_process";
2+
3+
type NodeEvalArgsOptions = {
4+
evalFlag?: "--eval" | "-e";
5+
imports?: readonly string[];
6+
};
7+
8+
type ExecNodeEvalOptions = Omit<NonNullable<Parameters<typeof execFileSync>[2]>, "encoding"> &
9+
NodeEvalArgsOptions & {
10+
encoding?: BufferEncoding;
11+
};
12+
13+
type SpawnNodeEvalOptions = Omit<NonNullable<Parameters<typeof spawnSync>[2]>, "encoding"> &
14+
NodeEvalArgsOptions & {
15+
encoding?: BufferEncoding;
16+
};
17+
18+
export function createNodeEvalArgs(source: string, options: NodeEvalArgsOptions = {}): string[] {
19+
const args = (options.imports ?? []).flatMap((specifier) => ["--import", specifier]);
20+
args.push("--input-type=module", options.evalFlag ?? "--eval", source);
21+
return args;
22+
}
23+
24+
export function execNodeEvalSync(source: string, options: ExecNodeEvalOptions = {}): string {
25+
const { evalFlag, imports, ...execOptions } = options;
26+
return execFileSync(process.execPath, createNodeEvalArgs(source, { evalFlag, imports }), {
27+
cwd: process.cwd(),
28+
encoding: "utf8",
29+
...execOptions,
30+
});
31+
}
32+
33+
export function spawnNodeEvalSync(
34+
source: string,
35+
options: SpawnNodeEvalOptions = {},
36+
): SpawnSyncReturns<string> {
37+
const { evalFlag, imports, ...spawnOptions } = options;
38+
return spawnSync(process.execPath, createNodeEvalArgs(source, { evalFlag, imports }), {
39+
cwd: process.cwd(),
40+
encoding: "utf8",
41+
...spawnOptions,
42+
});
43+
}

test/scripts/parallels-smoke-model.test.ts

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { execFileSync, spawnSync } from "node:child_process";
21
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
32
import { tmpdir } from "node:os";
43
import { join } from "node:path";
54
import { describe, expect, it } from "vitest";
5+
import { execNodeEvalSync, spawnNodeEvalSync } from "../../src/test-utils/node-process.js";
66

77
const WRAPPERS = {
88
linux: "scripts/e2e/parallels-linux-smoke.sh",
@@ -46,10 +46,7 @@ function countNonEmptyLines(value: string): number {
4646
}
4747

4848
function runTsEval(source: string, env: Record<string, string> = {}) {
49-
return execFileSync("node", ["--import", "tsx", "--input-type=module", "--eval", source], {
50-
encoding: "utf8",
51-
env: { ...process.env, ...env },
52-
});
49+
return execNodeEvalSync(source, { env: { ...process.env, ...env }, imports: ["tsx"] });
5350
}
5451

5552
function resolveProviderAuth(
@@ -313,32 +310,18 @@ console.log(JSON.stringify(result));
313310
});
314311

315312
it("rejects invalid providers and missing keys before touching guests", () => {
316-
const invalidProvider = spawnSync(
317-
"node",
318-
[
319-
"--import",
320-
"tsx",
321-
"--input-type=module",
322-
"--eval",
323-
`import { parseProvider } from "./${TS_PATHS.common}"; parseProvider("bogus");`,
324-
],
325-
{ encoding: "utf8", env: process.env },
313+
const invalidProvider = spawnNodeEvalSync(
314+
`import { parseProvider } from "./${TS_PATHS.common}"; parseProvider("bogus");`,
315+
{ env: process.env, imports: ["tsx"] },
326316
);
327317
expect(invalidProvider.status).toBe(1);
328318
expect(invalidProvider.stderr).toContain("invalid --provider: bogus");
329319

330-
const missingKey = spawnSync(
331-
"node",
332-
[
333-
"--import",
334-
"tsx",
335-
"--input-type=module",
336-
"--eval",
337-
`import { resolveProviderAuth } from "./${TS_PATHS.common}"; resolveProviderAuth({ provider: "openai", apiKeyEnv: "PARALLELS_TEST_MISSING_KEY" });`,
338-
],
320+
const missingKey = spawnNodeEvalSync(
321+
`import { resolveProviderAuth } from "./${TS_PATHS.common}"; resolveProviderAuth({ provider: "openai", apiKeyEnv: "PARALLELS_TEST_MISSING_KEY" });`,
339322
{
340-
encoding: "utf8",
341323
env: { ...process.env, PARALLELS_TEST_MISSING_KEY: "" },
324+
imports: ["tsx"],
342325
},
343326
);
344327
expect(missingKey.status).toBe(1);

test/vitest-unit-fast-config.test.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { spawnSync } from "node:child_process";
21
import { describe, expect, it } from "vitest";
2+
import { spawnNodeEvalSync } from "../src/test-utils/node-process.js";
33
import { createCommandsLightVitestConfig } from "./vitest/vitest.commands-light.config.ts";
44
import { createPluginSdkLightVitestConfig } from "./vitest/vitest.plugin-sdk-light.config.ts";
55
import {
@@ -62,17 +62,20 @@ describe("unit-fast vitest lane", () => {
6262
await import("./test/vitest/vitest.unit-fast.config.ts?io-probe=" + Date.now());
6363
console.log(readdirSyncCalls);
6464
`;
65-
const result = spawnSync(
66-
process.execPath,
67-
["--import", "tsx", "--input-type=module", "-e", script],
68-
{
69-
cwd: process.cwd(),
70-
encoding: "utf8",
71-
},
72-
);
65+
const result = spawnNodeEvalSync(script, {
66+
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
67+
evalFlag: "-e",
68+
imports: ["tsx"],
69+
});
7370

7471
expect(result.status, result.stderr).toBe(0);
75-
expect(Number(result.stdout.trim())).toBeLessThan(20);
72+
const numericOutputLines = result.stdout
73+
.trim()
74+
.split(/\r?\n/u)
75+
.map((line) => Number(line.trim()))
76+
.filter(Number.isFinite);
77+
expect(numericOutputLines.length, result.stdout).toBeGreaterThan(0);
78+
expect(numericOutputLines.at(-1)).toBeLessThan(20);
7679
});
7780

7881
it("runs cache-friendly tests without the reset-heavy runner or runtime setup", () => {

0 commit comments

Comments
 (0)