mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 19:28:28 +00:00
test(infra): dedupe install-source fixtures and cover npm pack parsing
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
} from "./install-source-utils.js";
|
} from "./install-source-utils.js";
|
||||||
|
|
||||||
const runCommandWithTimeoutMock = vi.fn();
|
const runCommandWithTimeoutMock = vi.fn();
|
||||||
|
const TEMP_DIR_PREFIX = "openclaw-install-source-utils-";
|
||||||
|
|
||||||
vi.mock("../process/exec.js", () => ({
|
vi.mock("../process/exec.js", () => ({
|
||||||
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
|
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
|
||||||
@@ -22,6 +23,39 @@ async function createTempDir(prefix: string) {
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createFixtureDir() {
|
||||||
|
return await createTempDir(TEMP_DIR_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createFixtureFile(params: {
|
||||||
|
fileName: string;
|
||||||
|
contents: string;
|
||||||
|
dir?: string;
|
||||||
|
}): Promise<{ dir: string; filePath: string }> {
|
||||||
|
const dir = params.dir ?? (await createFixtureDir());
|
||||||
|
const filePath = path.join(dir, params.fileName);
|
||||||
|
await fs.writeFile(filePath, params.contents, "utf-8");
|
||||||
|
return { dir, filePath };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockPackCommandResult(params: { stdout: string; stderr?: string; code?: number }) {
|
||||||
|
runCommandWithTimeoutMock.mockResolvedValue({
|
||||||
|
stdout: params.stdout,
|
||||||
|
stderr: params.stderr ?? "",
|
||||||
|
code: params.code ?? 0,
|
||||||
|
signal: null,
|
||||||
|
killed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runPack(spec: string, cwd: string, timeoutMs = 1000) {
|
||||||
|
return await packNpmSpecToArchive({
|
||||||
|
spec,
|
||||||
|
timeoutMs,
|
||||||
|
cwd,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
runCommandWithTimeoutMock.mockReset();
|
runCommandWithTimeoutMock.mockReset();
|
||||||
});
|
});
|
||||||
@@ -63,9 +97,10 @@ describe("resolveArchiveSourcePath", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("rejects unsupported archive extensions", async () => {
|
it("rejects unsupported archive extensions", async () => {
|
||||||
const dir = await createTempDir("openclaw-install-source-utils-");
|
const { filePath } = await createFixtureFile({
|
||||||
const filePath = path.join(dir, "plugin.txt");
|
fileName: "plugin.txt",
|
||||||
await fs.writeFile(filePath, "not-an-archive", "utf-8");
|
contents: "not-an-archive",
|
||||||
|
});
|
||||||
|
|
||||||
const result = await resolveArchiveSourcePath(filePath);
|
const result = await resolveArchiveSourcePath(filePath);
|
||||||
expect(result.ok).toBe(false);
|
expect(result.ok).toBe(false);
|
||||||
@@ -75,9 +110,10 @@ describe("resolveArchiveSourcePath", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("accepts supported archive extensions", async () => {
|
it("accepts supported archive extensions", async () => {
|
||||||
const dir = await createTempDir("openclaw-install-source-utils-");
|
const { filePath } = await createFixtureFile({
|
||||||
const filePath = path.join(dir, "plugin.zip");
|
fileName: "plugin.zip",
|
||||||
await fs.writeFile(filePath, "", "utf-8");
|
contents: "",
|
||||||
|
});
|
||||||
|
|
||||||
const result = await resolveArchiveSourcePath(filePath);
|
const result = await resolveArchiveSourcePath(filePath);
|
||||||
expect(result).toEqual({ ok: true, path: filePath });
|
expect(result).toEqual({ ok: true, path: filePath });
|
||||||
@@ -86,8 +122,8 @@ describe("resolveArchiveSourcePath", () => {
|
|||||||
|
|
||||||
describe("packNpmSpecToArchive", () => {
|
describe("packNpmSpecToArchive", () => {
|
||||||
it("packs spec and returns archive path using JSON output metadata", async () => {
|
it("packs spec and returns archive path using JSON output metadata", async () => {
|
||||||
const cwd = await createTempDir("openclaw-install-source-utils-");
|
const cwd = await createFixtureDir();
|
||||||
runCommandWithTimeoutMock.mockResolvedValue({
|
mockPackCommandResult({
|
||||||
stdout: JSON.stringify([
|
stdout: JSON.stringify([
|
||||||
{
|
{
|
||||||
id: "openclaw-plugin@1.2.3",
|
id: "openclaw-plugin@1.2.3",
|
||||||
@@ -98,17 +134,9 @@ describe("packNpmSpecToArchive", () => {
|
|||||||
shasum: "abc123",
|
shasum: "abc123",
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
stderr: "",
|
|
||||||
code: 0,
|
|
||||||
signal: null,
|
|
||||||
killed: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await packNpmSpecToArchive({
|
const result = await runPack("openclaw-plugin@1.2.3", cwd);
|
||||||
spec: "openclaw-plugin@1.2.3",
|
|
||||||
timeoutMs: 1000,
|
|
||||||
cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
ok: true,
|
ok: true,
|
||||||
@@ -131,20 +159,12 @@ describe("packNpmSpecToArchive", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("falls back to parsing final stdout line when npm json output is unavailable", async () => {
|
it("falls back to parsing final stdout line when npm json output is unavailable", async () => {
|
||||||
const cwd = await createTempDir("openclaw-install-source-utils-");
|
const cwd = await createFixtureDir();
|
||||||
runCommandWithTimeoutMock.mockResolvedValue({
|
mockPackCommandResult({
|
||||||
stdout: "npm notice created package\nopenclaw-plugin-1.2.3.tgz\n",
|
stdout: "npm notice created package\nopenclaw-plugin-1.2.3.tgz\n",
|
||||||
stderr: "",
|
|
||||||
code: 0,
|
|
||||||
signal: null,
|
|
||||||
killed: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await packNpmSpecToArchive({
|
const result = await runPack("openclaw-plugin@1.2.3", cwd);
|
||||||
spec: "openclaw-plugin@1.2.3",
|
|
||||||
timeoutMs: 1000,
|
|
||||||
cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
ok: true,
|
ok: true,
|
||||||
@@ -154,20 +174,14 @@ describe("packNpmSpecToArchive", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns npm pack error details when command fails", async () => {
|
it("returns npm pack error details when command fails", async () => {
|
||||||
const cwd = await createTempDir("openclaw-install-source-utils-");
|
const cwd = await createFixtureDir();
|
||||||
runCommandWithTimeoutMock.mockResolvedValue({
|
mockPackCommandResult({
|
||||||
stdout: "fallback stdout",
|
stdout: "fallback stdout",
|
||||||
stderr: "registry timeout",
|
stderr: "registry timeout",
|
||||||
code: 1,
|
code: 1,
|
||||||
signal: null,
|
|
||||||
killed: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await packNpmSpecToArchive({
|
const result = await runPack("bad-spec", cwd, 5000);
|
||||||
spec: "bad-spec",
|
|
||||||
timeoutMs: 5000,
|
|
||||||
cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.ok).toBe(false);
|
expect(result.ok).toBe(false);
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
@@ -177,24 +191,54 @@ describe("packNpmSpecToArchive", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns explicit error when npm pack produces no archive name", async () => {
|
it("returns explicit error when npm pack produces no archive name", async () => {
|
||||||
const cwd = await createTempDir("openclaw-install-source-utils-");
|
const cwd = await createFixtureDir();
|
||||||
runCommandWithTimeoutMock.mockResolvedValue({
|
mockPackCommandResult({
|
||||||
stdout: " \n\n",
|
stdout: " \n\n",
|
||||||
stderr: "",
|
|
||||||
code: 0,
|
|
||||||
signal: null,
|
|
||||||
killed: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await packNpmSpecToArchive({
|
const result = await runPack("openclaw-plugin@1.2.3", cwd, 5000);
|
||||||
spec: "openclaw-plugin@1.2.3",
|
|
||||||
timeoutMs: 5000,
|
|
||||||
cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
ok: false,
|
ok: false,
|
||||||
error: "npm pack produced no archive",
|
error: "npm pack produced no archive",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("parses scoped metadata from id-only json output even with npm notice prefix", async () => {
|
||||||
|
const cwd = await createFixtureDir();
|
||||||
|
mockPackCommandResult({
|
||||||
|
stdout:
|
||||||
|
"npm notice creating package\n" +
|
||||||
|
JSON.stringify([
|
||||||
|
{
|
||||||
|
id: "@openclaw/plugin-demo@2.0.0",
|
||||||
|
filename: "openclaw-plugin-demo-2.0.0.tgz",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await runPack("@openclaw/plugin-demo@2.0.0", cwd);
|
||||||
|
expect(result).toEqual({
|
||||||
|
ok: true,
|
||||||
|
archivePath: path.join(cwd, "openclaw-plugin-demo-2.0.0.tgz"),
|
||||||
|
metadata: {
|
||||||
|
resolvedSpec: "@openclaw/plugin-demo@2.0.0",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses stdout fallback error text when stderr is empty", async () => {
|
||||||
|
const cwd = await createFixtureDir();
|
||||||
|
mockPackCommandResult({
|
||||||
|
stdout: "network timeout",
|
||||||
|
stderr: " ",
|
||||||
|
code: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await runPack("bad-spec", cwd);
|
||||||
|
expect(result).toEqual({
|
||||||
|
ok: false,
|
||||||
|
error: "npm pack failed: network timeout",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user