Files
Termix/scripts/plugin-dev.test.ts
T

99 lines
3.1 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import {
isSourceChange,
pushPlugin,
resolveDevOptions,
} from "../packages/plugin-sdk/cli/commands/dev.mjs";
const cleanups: Array<() => void> = [];
afterEach(() => {
while (cleanups.length) cleanups.pop()!();
});
function json(status: number, body: unknown) {
return new Response(JSON.stringify(body), { status });
}
function tempFile(): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "termix-plugin-dev-"));
cleanups.push(() => fs.rmSync(dir, { recursive: true, force: true }));
const file = path.join(dir, "demo-1.0.0.tmxplug");
fs.writeFileSync(file, "archive");
return file;
}
describe("termix-plugin dev options", () => {
it("reads flags first, then the environment", () => {
expect(
resolveDevOptions(["--server", "http://a:8080/", "--key", "tmx_1"], {}),
).toEqual({ server: "http://a:8080", key: "tmx_1", once: false });
expect(
resolveDevOptions(["--once"], {
TERMIX_SERVER_URL: "http://b",
TERMIX_API_KEY: "tmx_2",
}),
).toEqual({ server: "http://b", key: "tmx_2", once: true });
expect(resolveDevOptions([], { TERMIX_API_KEY: "tmx_3" }).server).toBe(
"http://localhost:30001",
);
});
it("needs an API key", () => {
expect(() => resolveDevOptions([], {})).toThrow(/API key/);
});
it("watches sources only", () => {
expect(isSourceChange("src/frontend/index.tsx")).toBe(true);
expect(isSourceChange("README.md")).toBe(true);
expect(isSourceChange("dist/frontend.js")).toBe(false);
});
});
describe("pushPlugin", () => {
it("uploads the file then installs it with the capabilities it asks for", async () => {
const fetchImpl = vi
.fn()
.mockResolvedValueOnce(
json(200, { token: "t".repeat(32), capabilities: ["kv:own"] }),
)
.mockResolvedValueOnce(
json(200, { id: "demo", version: "1.0.0", state: "active" }),
);
const { result } = await pushPlugin(
tempFile(),
{ server: "http://s", key: "tmx_k" },
fetchImpl,
);
expect(result.state).toBe("active");
const [uploadUrl, upload] = fetchImpl.mock.calls[0];
expect(uploadUrl).toBe("http://s/plugins/upload");
expect(upload.headers.Authorization).toBe("Bearer tmx_k");
expect(upload.headers["Content-Type"]).toBe("application/octet-stream");
const [installUrl, install] = fetchImpl.mock.calls[1];
expect(installUrl).toBe(
`http://s/plugins/upload/${"t".repeat(32)}/install`,
);
expect(JSON.parse(install.body)).toEqual({ capabilities: ["kv:own"] });
});
it("explains a server with developer mode off", async () => {
const fetchImpl = vi.fn().mockResolvedValue(
json(403, {
error: "Installing from a file needs developer mode",
code: "DEVELOPER_MODE_OFF",
}),
);
await expect(
pushPlugin(tempFile(), { server: "http://s", key: "tmx_k" }, fetchImpl),
).rejects.toThrow(
/403 Installing from a file needs developer mode\n.*developer mode/,
);
});
});