repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/web/__tests__/settings.test.ts
Rawimport { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { createTestSession, type TestSession } from "../../../test/harness";
import {
minimaxApiHost,
zaiContentSize,
zaiFreshness,
zaiLocation,
zaiMcpUrl,
} from "../settings.ts";
import { zaiSearch } from "../zai.ts";
const extensionPath = path.resolve(import.meta.dirname, "../index.ts");
type Case = {
user?: unknown;
project?: unknown;
env?: Record<string, string>;
untrusted?: boolean;
};
describe("web settings resolution", () => {
let t: TestSession | undefined;
let root: string | undefined;
afterEach(() => {
t?.dispose();
t = undefined;
if (root) rmSync(root, { recursive: true, force: true });
root = undefined;
});
async function start(input: Case) {
const dir = mkdtempSync(path.join(tmpdir(), "pi-ext-web-settings-"));
root = dir;
const write = (at: string, web: unknown) => {
mkdirSync(at, { recursive: true });
writeFileSync(path.join(at, "settings.json"), JSON.stringify({ web }));
};
if ("user" in input)
write(path.join(dir, ".test-home/.pi/agent"), input.user);
if ("project" in input) write(path.join(dir, ".pi"), input.project);
const session = await createTestSession({
cwd: dir,
extensions: [extensionPath],
env: {
ZAI_API_KEY: "test-key",
ZAI_SEARCH_FRESHNESS: undefined,
ZAI_SEARCH_MCP_URL: undefined,
ZAI_SEARCH_BASE_URL: undefined,
ZAI_SEARCH_CONTENT_SIZE: undefined,
ZAI_SEARCH_LOCATION: undefined,
MINIMAX_API_HOST: undefined,
...input.env,
},
});
t = session;
if (input.untrusted)
session.session.settingsManager.setProjectTrusted(false);
// The harness already started once, before trust was applied.
const before = session.events.uiCallsFor("notify").length;
await session.session.extensionRunner.emit({
type: "session_start",
reason: "startup",
});
const warnings = session.events
.uiCallsFor("notify")
.slice(before)
.filter((call) => String(call.args[0]).startsWith("web: Invalid"))
.map((call) => call.args[0]);
const ctx = { cwd: dir, isProjectTrusted: () => !input.untrusted };
return { ctx, warnings };
}
it("uses defaults without settings", async () => {
const { ctx, warnings } = await start({});
expect(warnings).toEqual([]);
expect(zaiFreshness(ctx)).toBeNull();
expect(zaiMcpUrl(ctx)).toBe(
"https://api.z.ai/api/mcp/web_search_prime/mcp",
);
expect(zaiContentSize(ctx)).toBe("medium");
expect(zaiLocation(ctx)).toBe("us");
expect(minimaxApiHost(ctx)).toBe("https://api.minimax.io");
});
it("merges trusted project over user settings", async () => {
const { ctx, warnings } = await start({
user: {
zai: { freshness: "week", location: "eu" },
minimax: { apiHost: "https://user.test" },
},
project: { zai: { freshness: "day" } },
});
expect(warnings).toEqual([]);
expect(zaiFreshness(ctx)).toBe("day");
expect(zaiLocation(ctx)).toBe("eu");
expect(minimaxApiHost(ctx)).toBe("https://user.test");
});
it("prefers env over project and user settings", async () => {
const { ctx } = await start({
user: { zai: { contentSize: "high" } },
project: { zai: { contentSize: "low", mcpUrl: "https://project.test" } },
env: {
ZAI_SEARCH_CONTENT_SIZE: "medium",
MINIMAX_API_HOST: "https://env.test",
},
});
expect(zaiContentSize(ctx)).toBe("medium");
expect(zaiMcpUrl(ctx)).toBe("https://project.test");
expect(minimaxApiHost(ctx)).toBe("https://env.test");
});
it("orders ZAI_SEARCH_MCP_URL over ZAI_SEARCH_BASE_URL over settings", async () => {
const both = await start({
project: { zai: { mcpUrl: "https://project.test" } },
env: {
ZAI_SEARCH_MCP_URL: "https://mcp.test",
ZAI_SEARCH_BASE_URL: "https://base.test",
},
});
expect(zaiMcpUrl(both.ctx)).toBe("https://mcp.test");
t?.dispose();
t = undefined;
const base = await start({
project: { zai: { mcpUrl: "https://project.test" } },
env: { ZAI_SEARCH_BASE_URL: "https://base.test" },
});
expect(zaiMcpUrl(base.ctx)).toBe("https://base.test");
});
it("ignores untrusted project settings", async () => {
const { ctx, warnings } = await start({
user: { zai: { freshness: "week" } },
project: { zai: { freshness: 42 } },
untrusted: true,
});
expect(warnings).toEqual([]);
expect(zaiFreshness(ctx)).toBe("week");
});
it.each([
[
"project freshness",
{
user: { zai: { freshness: "week" } },
project: { zai: { freshness: "hour" } },
},
"web: Invalid web.zai.freshness from project settings: expected day, week, month, year, or none",
],
[
"env location",
{ user: { zai: { location: "eu" } }, env: { ZAI_SEARCH_LOCATION: " " } },
"web: Invalid web.zai.location from environment variable ZAI_SEARCH_LOCATION: expected a non-empty string",
],
[
"user api host",
{ user: { minimax: { apiHost: 1 } } },
"web: Invalid web.minimax.apiHost from user settings: expected a non-empty string",
],
] satisfies [string, Case, string][])(
"warns on invalid %s without falling through",
async (_name, input, warning) => {
const { warnings } = await start(input);
expect(warnings).toEqual([warning]);
},
);
it("fails Z.AI search on an invalid setting", async () => {
await start({ user: { zai: { contentSize: "" } } });
await expect(zaiSearch("q", undefined)).rejects.toThrow(
"Invalid web.zai.contentSize from user settings: expected a non-empty string",
);
});
});