mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-22 06:59:03 +00:00
* test(doctor): deslop z0552 tests * test(auth-profiles): deslop z0553 tests * test(auth-profiles): preserve migration table provider type * test(auth-profiles): deslop z0553 tests * test(plugins): deslop z0551 tests * test(plugins): deslop z0551 tests * test(plugins): deslop z0551 tests * test(agents): deslop z0556 tests * test(agents): deslop z0556 tests * test(ui): deslop z0554 tests * test(ui): deslop z0554 tests * test(ui): deslop z0554 tests * test(xai): deslop z0558 tests * test(xai): deslop z0558 tests * test(channels): deslop z0560 tests * test(plugins): deslop z0557 tests * test(plugins): deslop z0557 tests * test(plugins): deslop z0557 tests * test(discord): deslop z0555 tests * test(discord): deslop z0555 tests * test(plugins): deslop z0559 tests * test(plugins): deslop z0559 tests * test(doctor): deslop z0552 tests * test(scripts): deslop z0561 tests * test(scripts): further deslop z0561 tests * test(doctor): deslop z0562 tests * test(doctor): deslop z0562 tests * test(doctor): deslop z0562 tests * test(agents): deslop z0563 tests * test(discord): preserve shared model-picker fixture after replay * test: retain boundary assertions and fix cleanup fixture types * test: repair cleanup fixture types and mock isolation contracts * test(scripts): allow omitted availability in dev-tool cases * test: prune obsolete cleanup mock baseline entries
92 lines
3.9 KiB
TypeScript
92 lines
3.9 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { symlinkSync, writeFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { expect, it, vi } from "vitest";
|
|
import { resolveDevTool } from "../../scripts/lib/dev-tool.mts";
|
|
import { compareFormatResults } from "../../scripts/run-format.mts";
|
|
import { resolveTestNodeExecPath } from "../../src/test-utils/node-process.js";
|
|
import { createScriptTestHarness } from "./test-helpers.js";
|
|
|
|
const { createTempDir } = createScriptTestHarness();
|
|
const pinnedBun = { command: "/pinned/bin/bun" };
|
|
const unavailable = { reason: "unavailable" };
|
|
it.each([
|
|
["format", {}, true],
|
|
["format", { CI: "true" }, false],
|
|
["format", { CI: "false" }, true],
|
|
["format", { OPENCLAW_FORMAT_TOOL: "oxfmt" }, false],
|
|
["format", { OPENCLAW_FORMAT_TOOL: "bun" }, true],
|
|
["format", { CI: "true", OPENCLAW_FORMAT_TOOL: "bun" }, true],
|
|
["lint", {}, false],
|
|
["lint", { CI: "true" }, false],
|
|
["lint", { OPENCLAW_LINT_TOOL: "bun", PATH: "/usr/bin" }, true],
|
|
["format", { OPENCLAW_FORMAT_TOOL: "bun" }, "error", false],
|
|
["format", {}, false, false],
|
|
] as const)("selects %s for %j", (kind, env, bun, availability?: boolean) => {
|
|
const available = availability ?? true;
|
|
const resolvePinnedBun = vi.fn(() => (available ? pinnedBun : unavailable));
|
|
const notice = vi.fn();
|
|
const run = () => resolveDevTool(kind, env, { resolvePinnedBun, notice });
|
|
if (bun === "error") {
|
|
expect(run).toThrow("OPENCLAW_FORMAT_TOOL=bun: unavailable");
|
|
expect(notice).not.toHaveBeenCalled();
|
|
return;
|
|
}
|
|
const tool = run();
|
|
expect(tool.command === "/pinned/bin/bun").toBe(bun);
|
|
expect(resolvePinnedBun).toHaveBeenCalledTimes(bun || !available ? 1 : 0);
|
|
if (available) {
|
|
expect(notice).not.toHaveBeenCalled();
|
|
} else {
|
|
const args = [path.resolve("node_modules/oxfmt/bin/oxfmt")];
|
|
expect(tool).toMatchObject({ command: process.execPath, args });
|
|
expect(notice).toHaveBeenCalledExactlyOnceWith("[openclaw] unavailable; using oxfmt.");
|
|
}
|
|
if (kind === "lint" && bun) {
|
|
expect(tool.args).toEqual(["lint"]);
|
|
expect(tool.env.PATH?.split(/[:;]/u)[0]).toBe("/pinned/bin");
|
|
expect(tool.env.npm_lifecycle_event).toBe("lint");
|
|
}
|
|
});
|
|
|
|
it("rejects an invalid override", () => {
|
|
const invalid = () => resolveDevTool("format", { OPENCLAW_FORMAT_TOOL: "typo" });
|
|
expect(invalid).toThrow("OPENCLAW_FORMAT_TOOL must be bun or oxfmt");
|
|
});
|
|
it.each([
|
|
["bun", "export const value=1;", "process.exit(0);"],
|
|
["oxfmt", "export const value = 1;\n", 'console.log("file.ts"); process.exit(1);'],
|
|
])("CI enforces both tools despite the %s override", (override, source, bunOutput) => {
|
|
const root = createTempDir("format-parity-");
|
|
symlinkSync(path.resolve("node_modules"), path.join(root, "node_modules"), "junction");
|
|
writeFileSync(path.join(root, ".oxfmtrc.jsonc"), "{}");
|
|
writeFileSync(path.join(root, "file.ts"), source);
|
|
// Node stands in for Bun and executes this fixed report as its `fmt` command.
|
|
writeFileSync(path.join(root, "fmt"), bunOutput);
|
|
const node = resolveTestNodeExecPath();
|
|
const result = spawnSync(node, [path.resolve("scripts/run-format.mts"), "--check", "file.ts"], {
|
|
cwd: root,
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
CI: "true",
|
|
OPENCLAW_FORMAT_TOOL: override,
|
|
OPENCLAW_BUN_PATH: node,
|
|
},
|
|
});
|
|
expect(result.status).toBe(1);
|
|
expect(result.stderr).toContain("[format] parity failed");
|
|
});
|
|
|
|
const output = (status: number, stdout = "") => ({ status, stdout });
|
|
const timing = (ms: number) => `Finished in ${ms}ms on 0 files using 4 threads.\n`;
|
|
it.each([
|
|
[output(0, timing(1)), output(0, timing(0)), true],
|
|
[output(0), output(0), true],
|
|
[output(0), output(1, "a.ts\n"), false],
|
|
[output(1, "a.ts"), output(0), false],
|
|
[output(1, "a.ts"), output(1, "b.ts\n"), false],
|
|
[output(1, "b.ts\na.ts"), output(1, "a.ts\nb.ts\n"), true],
|
|
])("compares each tool's changed-file set", (oxfmt, bun, matches) => {
|
|
expect(compareFormatResults(oxfmt, bun)).toBe(matches);
|
|
});
|