mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 20:21:11 +00:00
* fix(canvas): bound A2UI git input discovery * build: avoid premature A2UI Git fallback --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
107 lines
3.9 KiB
TypeScript
107 lines
3.9 KiB
TypeScript
// Canvas tests cover bundle a2ui plugin behavior.
|
|
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
compareNormalizedPaths,
|
|
getBundleHashRepoInputPaths,
|
|
getLocalRolldownCliCandidates,
|
|
isBundleHashInputPath,
|
|
} from "./bundle-a2ui.mjs";
|
|
|
|
describe("scripts/bundle-a2ui.mjs", () => {
|
|
it("uses package metadata and plugin-owned A2UI sources as bundle hash inputs", () => {
|
|
const repoRoot = path.resolve("repo-root");
|
|
const inputPaths = getBundleHashRepoInputPaths(repoRoot);
|
|
|
|
expect(inputPaths).toContain(path.join(repoRoot, "package.json"));
|
|
expect(inputPaths).toContain(path.join(repoRoot, "pnpm-lock.yaml"));
|
|
expect(inputPaths).toContain(
|
|
path.join(repoRoot, "extensions", "canvas", "src", "host", "a2ui-app"),
|
|
);
|
|
expect(inputPaths).not.toContain(path.join(repoRoot, "vendor", "a2ui", "renderers", "lit"));
|
|
expect(isBundleHashInputPath(path.join(repoRoot, "package.json"), repoRoot)).toBe(true);
|
|
});
|
|
|
|
it("prefers the installed rolldown CLI over a network dlx fallback", () => {
|
|
const repoRoot = path.resolve("repo-root");
|
|
|
|
expect(getLocalRolldownCliCandidates(repoRoot)[0]).toBe(
|
|
path.join(repoRoot, "node_modules", "rolldown", "bin", "cli.mjs"),
|
|
);
|
|
});
|
|
|
|
it("sorts hash inputs without locale-dependent collation", () => {
|
|
const paths = ["repo/Z.ts", "repo/a.ts", "repo/ä.ts", "repo/A.ts"];
|
|
|
|
expect([...paths].toSorted(compareNormalizedPaths)).toEqual([
|
|
"repo/A.ts",
|
|
"repo/Z.ts",
|
|
"repo/a.ts",
|
|
"repo/ä.ts",
|
|
]);
|
|
});
|
|
|
|
it("keeps unrelated package metadata out of bundle hash inputs", () => {
|
|
const repoRoot = path.resolve("repo-root");
|
|
const inputPaths = getBundleHashRepoInputPaths(repoRoot);
|
|
|
|
expect(inputPaths).not.toContain(path.join(repoRoot, "ui", "package.json"));
|
|
expect(inputPaths).not.toContain(path.join(repoRoot, "packages", "plugin-sdk", "package.json"));
|
|
});
|
|
|
|
it("keeps local node_modules state out of bundle hash inputs", () => {
|
|
const repoRoot = process.cwd();
|
|
const inputPaths = getBundleHashRepoInputPaths(repoRoot);
|
|
|
|
expect(inputPaths).not.toContain(path.join(repoRoot, "node_modules", "lit", "package.json"));
|
|
expect(inputPaths).not.toContain(
|
|
path.join(repoRoot, "ui", "node_modules", "lit", "package.json"),
|
|
);
|
|
});
|
|
|
|
it.skipIf(process.platform === "win32")(
|
|
"falls back when tracked-input discovery stalls",
|
|
async () => {
|
|
await withTempWorkspace(
|
|
{ rootDir: resolvePreferredOpenClawTmpDir(), prefix: "openclaw-a2ui-git-timeout-" },
|
|
async ({ dir }) => {
|
|
const fakeBinDir = path.join(dir, "bin");
|
|
const fakeGitPath = path.join(fakeBinDir, "git");
|
|
const outputFile = path.join(dir, "a2ui.bundle.js");
|
|
const hashFile = path.join(dir, "a2ui.bundle.hash");
|
|
await fs.mkdir(fakeBinDir, { recursive: true });
|
|
await fs.writeFile(
|
|
fakeGitPath,
|
|
`#!${process.execPath}\nsetTimeout(() => {}, 30_000);\n`,
|
|
"utf8",
|
|
);
|
|
await fs.chmod(fakeGitPath, 0o755);
|
|
|
|
execFileSync(
|
|
process.execPath,
|
|
[path.resolve("extensions/canvas/scripts/bundle-a2ui.mjs")],
|
|
{
|
|
cwd: process.cwd(),
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
OPENCLAW_A2UI_BUNDLE_HASH_FILE: hashFile,
|
|
OPENCLAW_A2UI_BUNDLE_OUT: outputFile,
|
|
PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH ?? ""}`,
|
|
},
|
|
killSignal: "SIGKILL",
|
|
timeout: 12_000,
|
|
},
|
|
);
|
|
|
|
await expect(fs.stat(outputFile)).resolves.toBeDefined();
|
|
await expect(fs.stat(hashFile)).resolves.toBeDefined();
|
|
},
|
|
);
|
|
},
|
|
);
|
|
});
|