mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 12:14:46 +00:00
test: share node eval helpers
This commit is contained in:
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { createNodeEvalArgs } from "../../../src/test-utils/node-process.js";
|
||||
|
||||
type CommandResult = {
|
||||
stdout: string;
|
||||
@@ -104,7 +105,7 @@ describe("OpenClaw SDK package e2e", () => {
|
||||
});
|
||||
if (event.type !== "run.started") throw new Error("unexpected event normalization");
|
||||
`;
|
||||
await runCommand(process.execPath, ["--input-type=module", "-e", importScript], {
|
||||
await runCommand(process.execPath, createNodeEvalArgs(importScript, { evalFlag: "-e" }), {
|
||||
cwd: tempDir,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { Duplex } from "node:stream";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { withTempDir } from "../../../test-helpers/temp-dir.js";
|
||||
import { createNodeEvalArgs } from "../../../test-utils/node-process.js";
|
||||
import { resolveSystemBin } from "../../resolve-system-bin.js";
|
||||
import { resolvePreferredOpenClawTmpDir } from "../../tmp-openclaw-dir.js";
|
||||
|
||||
@@ -248,15 +249,11 @@ async function runNodeModule(
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}> {
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
["--import", "tsx", "--input-type=module", "--eval", source],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
env,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
},
|
||||
);
|
||||
const child = spawn(process.execPath, createNodeEvalArgs(source, { imports: ["tsx"] }), {
|
||||
cwd: process.cwd(),
|
||||
env,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { execNodeEvalSync } from "../../test-utils/node-process.js";
|
||||
|
||||
const {
|
||||
Agent,
|
||||
@@ -196,11 +196,7 @@ describe("ensureGlobalUndiciStreamTimeouts", () => {
|
||||
delete env[key];
|
||||
}
|
||||
|
||||
const output = execFileSync(
|
||||
process.execPath,
|
||||
["--import", "tsx", "--input-type=module", "--eval", source],
|
||||
{ cwd: process.cwd(), encoding: "utf8", env },
|
||||
);
|
||||
const output = execNodeEvalSync(source, { env, imports: ["tsx"] });
|
||||
|
||||
expect(output.trim()).toBe("ok");
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { execNodeEvalSync } from "../test-utils/node-process.js";
|
||||
|
||||
describe("plugin SDK fetch runtime", () => {
|
||||
it("does not initialize the undici global dispatcher on import", () => {
|
||||
@@ -27,11 +27,7 @@ describe("plugin SDK fetch runtime", () => {
|
||||
delete env[key];
|
||||
}
|
||||
|
||||
const output = execFileSync(
|
||||
process.execPath,
|
||||
["--import", "tsx", "--input-type=module", "--eval", source],
|
||||
{ cwd: process.cwd(), encoding: "utf8", env },
|
||||
);
|
||||
const output = execNodeEvalSync(source, { env, imports: ["tsx"] });
|
||||
|
||||
expect(output.trim()).toBe("ok");
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { execNodeEvalSync } from "../test-utils/node-process.js";
|
||||
import {
|
||||
cleanupTrackedTempDirs,
|
||||
makeTrackedTempDir,
|
||||
@@ -85,9 +85,8 @@ export const copiedRuntimeMarker = {
|
||||
dep: mod.copiedRuntimeMarker?.resolveOutboundSendDep?.(),
|
||||
}));
|
||||
`;
|
||||
const raw = execFileSync(process.execPath, ["--input-type=module", "--eval", script], {
|
||||
const raw = execNodeEvalSync(script, {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf-8",
|
||||
});
|
||||
const result = JSON.parse(raw) as {
|
||||
withoutAliasThrew: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import { expect, vi } from "vitest";
|
||||
import { spawnNodeEvalSync } from "./node-process.js";
|
||||
|
||||
type FsScanCounter = "existsSync" | "readdirSync" | "statSync";
|
||||
|
||||
@@ -63,12 +63,8 @@ export function expectNoNodeFsScans<T>(
|
||||
},
|
||||
): T {
|
||||
const counters = options?.counters ?? ["existsSync", "readdirSync"];
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
"--input-type=module",
|
||||
"--eval",
|
||||
`
|
||||
const result = spawnNodeEvalSync(
|
||||
`
|
||||
import fs from "node:fs";
|
||||
import { syncBuiltinESMExports } from "node:module";
|
||||
const counts = ${JSON.stringify(Object.fromEntries(counters.map((name) => [name, 0])))};
|
||||
@@ -88,10 +84,8 @@ export function expectNoNodeFsScans<T>(
|
||||
})();
|
||||
console.log(JSON.stringify({ counts, result }));
|
||||
`,
|
||||
],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
},
|
||||
);
|
||||
|
||||
43
src/test-utils/node-process.ts
Normal file
43
src/test-utils/node-process.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { execFileSync, spawnSync, type SpawnSyncReturns } from "node:child_process";
|
||||
|
||||
type NodeEvalArgsOptions = {
|
||||
evalFlag?: "--eval" | "-e";
|
||||
imports?: readonly string[];
|
||||
};
|
||||
|
||||
type ExecNodeEvalOptions = Omit<NonNullable<Parameters<typeof execFileSync>[2]>, "encoding"> &
|
||||
NodeEvalArgsOptions & {
|
||||
encoding?: BufferEncoding;
|
||||
};
|
||||
|
||||
type SpawnNodeEvalOptions = Omit<NonNullable<Parameters<typeof spawnSync>[2]>, "encoding"> &
|
||||
NodeEvalArgsOptions & {
|
||||
encoding?: BufferEncoding;
|
||||
};
|
||||
|
||||
export function createNodeEvalArgs(source: string, options: NodeEvalArgsOptions = {}): string[] {
|
||||
const args = (options.imports ?? []).flatMap((specifier) => ["--import", specifier]);
|
||||
args.push("--input-type=module", options.evalFlag ?? "--eval", source);
|
||||
return args;
|
||||
}
|
||||
|
||||
export function execNodeEvalSync(source: string, options: ExecNodeEvalOptions = {}): string {
|
||||
const { evalFlag, imports, ...execOptions } = options;
|
||||
return execFileSync(process.execPath, createNodeEvalArgs(source, { evalFlag, imports }), {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
...execOptions,
|
||||
});
|
||||
}
|
||||
|
||||
export function spawnNodeEvalSync(
|
||||
source: string,
|
||||
options: SpawnNodeEvalOptions = {},
|
||||
): SpawnSyncReturns<string> {
|
||||
const { evalFlag, imports, ...spawnOptions } = options;
|
||||
return spawnSync(process.execPath, createNodeEvalArgs(source, { evalFlag, imports }), {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
...spawnOptions,
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { execFileSync, spawnSync } from "node:child_process";
|
||||
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { execNodeEvalSync, spawnNodeEvalSync } from "../../src/test-utils/node-process.js";
|
||||
|
||||
const WRAPPERS = {
|
||||
linux: "scripts/e2e/parallels-linux-smoke.sh",
|
||||
@@ -46,10 +46,7 @@ function countNonEmptyLines(value: string): number {
|
||||
}
|
||||
|
||||
function runTsEval(source: string, env: Record<string, string> = {}) {
|
||||
return execFileSync("node", ["--import", "tsx", "--input-type=module", "--eval", source], {
|
||||
encoding: "utf8",
|
||||
env: { ...process.env, ...env },
|
||||
});
|
||||
return execNodeEvalSync(source, { env: { ...process.env, ...env }, imports: ["tsx"] });
|
||||
}
|
||||
|
||||
function resolveProviderAuth(
|
||||
@@ -313,32 +310,18 @@ console.log(JSON.stringify(result));
|
||||
});
|
||||
|
||||
it("rejects invalid providers and missing keys before touching guests", () => {
|
||||
const invalidProvider = spawnSync(
|
||||
"node",
|
||||
[
|
||||
"--import",
|
||||
"tsx",
|
||||
"--input-type=module",
|
||||
"--eval",
|
||||
`import { parseProvider } from "./${TS_PATHS.common}"; parseProvider("bogus");`,
|
||||
],
|
||||
{ encoding: "utf8", env: process.env },
|
||||
const invalidProvider = spawnNodeEvalSync(
|
||||
`import { parseProvider } from "./${TS_PATHS.common}"; parseProvider("bogus");`,
|
||||
{ env: process.env, imports: ["tsx"] },
|
||||
);
|
||||
expect(invalidProvider.status).toBe(1);
|
||||
expect(invalidProvider.stderr).toContain("invalid --provider: bogus");
|
||||
|
||||
const missingKey = spawnSync(
|
||||
"node",
|
||||
[
|
||||
"--import",
|
||||
"tsx",
|
||||
"--input-type=module",
|
||||
"--eval",
|
||||
`import { resolveProviderAuth } from "./${TS_PATHS.common}"; resolveProviderAuth({ provider: "openai", apiKeyEnv: "PARALLELS_TEST_MISSING_KEY" });`,
|
||||
],
|
||||
const missingKey = spawnNodeEvalSync(
|
||||
`import { resolveProviderAuth } from "./${TS_PATHS.common}"; resolveProviderAuth({ provider: "openai", apiKeyEnv: "PARALLELS_TEST_MISSING_KEY" });`,
|
||||
{
|
||||
encoding: "utf8",
|
||||
env: { ...process.env, PARALLELS_TEST_MISSING_KEY: "" },
|
||||
imports: ["tsx"],
|
||||
},
|
||||
);
|
||||
expect(missingKey.status).toBe(1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { spawnNodeEvalSync } from "../src/test-utils/node-process.js";
|
||||
import { createCommandsLightVitestConfig } from "./vitest/vitest.commands-light.config.ts";
|
||||
import { createPluginSdkLightVitestConfig } from "./vitest/vitest.plugin-sdk-light.config.ts";
|
||||
import {
|
||||
@@ -62,17 +62,20 @@ describe("unit-fast vitest lane", () => {
|
||||
await import("./test/vitest/vitest.unit-fast.config.ts?io-probe=" + Date.now());
|
||||
console.log(readdirSyncCalls);
|
||||
`;
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
["--import", "tsx", "--input-type=module", "-e", script],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
},
|
||||
);
|
||||
const result = spawnNodeEvalSync(script, {
|
||||
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
|
||||
evalFlag: "-e",
|
||||
imports: ["tsx"],
|
||||
});
|
||||
|
||||
expect(result.status, result.stderr).toBe(0);
|
||||
expect(Number(result.stdout.trim())).toBeLessThan(20);
|
||||
const numericOutputLines = result.stdout
|
||||
.trim()
|
||||
.split(/\r?\n/u)
|
||||
.map((line) => Number(line.trim()))
|
||||
.filter(Number.isFinite);
|
||||
expect(numericOutputLines.length, result.stdout).toBeGreaterThan(0);
|
||||
expect(numericOutputLines.at(-1)).toBeLessThan(20);
|
||||
});
|
||||
|
||||
it("runs cache-friendly tests without the reset-heavy runner or runtime setup", () => {
|
||||
|
||||
Reference in New Issue
Block a user