openclaw/test/scripts/format-docs.test.ts
Peter Steinberger f86f96e639
test(agents,ui,gateway): remove low-value tests (batch d330) (#178556)
* test(chat): deslop z0292 tests

* test(chat): deslop z0292 tests

* test(ui): deslop z0295 tests

* test(ui): deslop z0295 tests

* test(plugins): deslop z0296 tests

* test(plugins): deslop z0296 tests

* test(plugins): deslop z0296 tests

* test(subagents): deslop z0294 tests

* test(subagents): deslop z0294 tests

* test(subagents): deslop z0294 tests

* test(agents): deslop z0290 tests

* test(agents): deslop z0290 tests

* test(gateway): deslop z0298 tests

* test(gateway): deslop z0298 tests

* test(gateway): deslop z0298 tests

* test(gateway): deslop z0297 tests

* test(gateway): deslop z0297 tests

* test(gateway): deslop z0297 tests

* test(auto-reply): deslop z0299 tests

* test(auto-reply): deslop z0299 tests

* test(auto-reply): deslop z0299 tests

* test(scripts): deslop z0300 tests

* test(scripts): deslop z0300 tests

* test(scripts): deslop z0300 tests

* test(ui): deslop z0301 tests

* test(ui): deslop z0301 tests

* test(ui): deslop z0301 tests

* test(outbound): deslop z0304 tests

* test(imessage): deslop z0303 tests

* test(imessage): deslop z0303 tests

* test(chat): retain current activity regressions during replay

* test: preserve async fixtures and regression coverage in d330

* test: preserve hoisted fixtures and retired view notifications

* test: document isolated mock boundaries for d330

* test(subagents): return void from timer cleanup

* test: preserve fixture callback and assertion contracts

* test: prune stale mock export baseline entries
2026-10-20 18:23:13 +00:00

116 lines
4.5 KiB
TypeScript

import { spawnSync, type SpawnSyncReturns } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { formatDocs } from "../../scripts/format-docs.mts";
import { createScriptTestHarness } from "./test-helpers.js";
vi.mock("node:child_process", async (importOriginal) => ({
...(await importOriginal<typeof import("node:child_process")>()),
spawnSync: vi.fn(),
}));
const { createTempDir } = createScriptTestHarness();
let root: string;
beforeEach(() => {
root = createTempDir("openclaw-format-docs-");
});
afterEach(() => {
vi.mocked(spawnSync).mockReset();
vi.unstubAllGlobals();
vi.unstubAllEnvs();
});
function commandResult(stdout = "", stderr = "", status = 0): SpawnSyncReturns<string> {
return { pid: 1, output: [null, stdout, stderr], stdout, stderr, status, signal: null };
}
function mockFormatter(files = ["README.md", "docs/guide.mdx"], run = () => commandResult()) {
for (const file of files) {
const target = path.join(root, file);
fs.mkdirSync(path.dirname(target), { recursive: true });
fs.writeFileSync(target, "# Guide\n", "utf8");
}
const calls: Array<{ command: string; args: readonly string[]; options: unknown }> = [];
vi.mocked(spawnSync).mockImplementation((command, args, options) => {
if (command === "git") {
return args?.[0] === "ls-files" ? commandResult(files.join("\n")) : commandResult("", "", 1);
}
calls.push({ command, args: args ?? [], options });
return run();
});
return calls;
}
describe("format-docs", () => {
it("wraps the Windows oxfmt.cmd shim through cmd.exe", () => {
const shim = path.join(root, "node_modules", ".bin", "oxfmt.cmd");
fs.mkdirSync(path.dirname(shim), { recursive: true });
fs.writeFileSync(shim, "@echo off\n");
vi.stubGlobal("process", { ...process, platform: "win32" });
vi.stubEnv("SystemRoot", "C:\\Windows");
const calls = mockFormatter();
formatDocs({ root });
expect(calls).toEqual([
{
command: "C:\\Windows\\System32\\cmd.exe",
args: ["/d", "/s", "/c", expect.stringMatching(/oxfmt\.cmd.*--write.*docs\/guide\.mdx/u)],
options: expect.objectContaining({ shell: false, windowsVerbatimArguments: true }),
},
]);
});
it("batches oxfmt invocations without losing docs that exceed the command line budget", () => {
const files = Array.from({ length: 150 }, (_, index) => `docs/${index}-${"a".repeat(180)}.md`);
const calls = mockFormatter(files);
formatDocs({ root });
expect(calls.length).toBeGreaterThan(1);
expect(calls.every((call) => call.command === process.execPath)).toBe(true);
expect(calls.flatMap((call) => call.args.slice(5))).toEqual(files);
});
it("reports git and oxfmt spawn diagnostics", () => {
vi.mocked(spawnSync).mockReturnValue(commandResult("", "fatal: not a git repository", 128));
expect(() => formatDocs({ root })).toThrow(
/git ls-files failed:[\s\S]*exit status: 128[\s\S]*fatal: not a git repository/u,
);
mockFormatter(["README.md"], () => commandResult("formatter stdout", "formatter stderr", 1));
expect(() => formatDocs({ root })).toThrow(
/oxfmt failed:[\s\S]*command:[\s\S]*exit status: 1[\s\S]*formatter stderr[\s\S]*formatter stdout/u,
);
});
it("keeps real formatter failure tails UTF-8 safe", async () => {
const { spawnSync: realSpawnSync } =
await vi.importActual<typeof import("node:child_process")>("node:child_process");
mockFormatter(["README.md"], () =>
realSpawnSync(
process.execPath,
["-e", 'process.stderr.write("你好" + "x".repeat(16_380)); process.exitCode = 1'],
{ encoding: "utf8", maxBuffer: 1024 * 1024, shell: false, timeout: 5_000 },
),
);
expect(() => formatDocs({ root })).toThrow(
/oxfmt failed:[\s\S]*exit status: 1[\s\S]*stderr tail:\n好x/u,
);
});
it("uses repository paths in write mode and temporary paths in check mode", () => {
const calls = mockFormatter();
expect(formatDocs({ root })).toEqual({ changed: [], fileCount: 2 });
expect(formatDocs({ root, check: true })).toEqual({ changed: [], fileCount: 2 });
expect(calls[0]?.args.slice(-2)).toEqual(["README.md", "docs/guide.mdx"]);
const temporaryFiles = calls[1]?.args.slice(-2);
expect(temporaryFiles?.every((file) => path.isAbsolute(file))).toBe(true);
expect(temporaryFiles?.every((file) => file.startsWith(root))).toBe(false);
});
});