test(providers): add tests for Z.AI/Zhipu multi-configuration
Update existing test files to cover all four GLM provider variants: - auth-choice-options.test.ts: Group test for zai, zai-coding, zhipu, zhipu-coding auth choice menu presence (follows MiniMax/Moonshot pattern) - program.smoke.test.ts: Add CLI flag wiring tests for --zai-coding-api-key, --zhipu-api-key, --zhipu-coding-api-key - model-auth.test.ts: Add env var resolution tests for: - zai-coding with fallback to ZAI_API_KEY - zhipu with ZHIPU_API_KEY - zhipu-coding with fallback to ZHIPU_API_KEY - provider-usage.test.ts: Add test for zhipu bigmodel.cn endpoint (will fail until fetchZhipuUsage is implemented) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
parent
61d9798b6b
commit
17a4345004
@ -233,6 +233,132 @@ describe("getApiKeyForModel", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("resolves zai-coding API key with fallback to ZAI_API_KEY", async () => {
|
||||||
|
const previous = {
|
||||||
|
coding: process.env.ZAI_CODING_API_KEY,
|
||||||
|
zai: process.env.ZAI_API_KEY,
|
||||||
|
legacy: process.env.Z_AI_API_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
delete process.env.ZAI_CODING_API_KEY;
|
||||||
|
process.env.ZAI_API_KEY = "zai-fallback-key";
|
||||||
|
delete process.env.Z_AI_API_KEY;
|
||||||
|
|
||||||
|
vi.resetModules();
|
||||||
|
const { resolveApiKeyForProvider } = await import("./model-auth.js");
|
||||||
|
|
||||||
|
const resolved = await resolveApiKeyForProvider({
|
||||||
|
provider: "zai-coding",
|
||||||
|
store: { version: 1, profiles: {} },
|
||||||
|
});
|
||||||
|
expect(resolved.apiKey).toBe("zai-fallback-key");
|
||||||
|
expect(resolved.source).toContain("ZAI_API_KEY");
|
||||||
|
} finally {
|
||||||
|
if (previous.coding === undefined) {
|
||||||
|
delete process.env.ZAI_CODING_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZAI_CODING_API_KEY = previous.coding;
|
||||||
|
}
|
||||||
|
if (previous.zai === undefined) {
|
||||||
|
delete process.env.ZAI_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZAI_API_KEY = previous.zai;
|
||||||
|
}
|
||||||
|
if (previous.legacy === undefined) {
|
||||||
|
delete process.env.Z_AI_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.Z_AI_API_KEY = previous.legacy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws when zhipu API key is missing", async () => {
|
||||||
|
const previous = process.env.ZHIPU_API_KEY;
|
||||||
|
|
||||||
|
try {
|
||||||
|
delete process.env.ZHIPU_API_KEY;
|
||||||
|
|
||||||
|
vi.resetModules();
|
||||||
|
const { resolveApiKeyForProvider } = await import("./model-auth.js");
|
||||||
|
|
||||||
|
let error: unknown = null;
|
||||||
|
try {
|
||||||
|
await resolveApiKeyForProvider({
|
||||||
|
provider: "zhipu",
|
||||||
|
store: { version: 1, profiles: {} },
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(String(error)).toContain('No API key found for provider "zhipu".');
|
||||||
|
} finally {
|
||||||
|
if (previous === undefined) {
|
||||||
|
delete process.env.ZHIPU_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZHIPU_API_KEY = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves zhipu API key from ZHIPU_API_KEY", async () => {
|
||||||
|
const previous = process.env.ZHIPU_API_KEY;
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.env.ZHIPU_API_KEY = "zhipu-test-key";
|
||||||
|
|
||||||
|
vi.resetModules();
|
||||||
|
const { resolveApiKeyForProvider } = await import("./model-auth.js");
|
||||||
|
|
||||||
|
const resolved = await resolveApiKeyForProvider({
|
||||||
|
provider: "zhipu",
|
||||||
|
store: { version: 1, profiles: {} },
|
||||||
|
});
|
||||||
|
expect(resolved.apiKey).toBe("zhipu-test-key");
|
||||||
|
expect(resolved.source).toContain("ZHIPU_API_KEY");
|
||||||
|
} finally {
|
||||||
|
if (previous === undefined) {
|
||||||
|
delete process.env.ZHIPU_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZHIPU_API_KEY = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves zhipu-coding API key with fallback to ZHIPU_API_KEY", async () => {
|
||||||
|
const previous = {
|
||||||
|
coding: process.env.ZHIPU_CODING_API_KEY,
|
||||||
|
zhipu: process.env.ZHIPU_API_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
delete process.env.ZHIPU_CODING_API_KEY;
|
||||||
|
process.env.ZHIPU_API_KEY = "zhipu-fallback-key";
|
||||||
|
|
||||||
|
vi.resetModules();
|
||||||
|
const { resolveApiKeyForProvider } = await import("./model-auth.js");
|
||||||
|
|
||||||
|
const resolved = await resolveApiKeyForProvider({
|
||||||
|
provider: "zhipu-coding",
|
||||||
|
store: { version: 1, profiles: {} },
|
||||||
|
});
|
||||||
|
expect(resolved.apiKey).toBe("zhipu-fallback-key");
|
||||||
|
expect(resolved.source).toContain("ZHIPU_API_KEY");
|
||||||
|
} finally {
|
||||||
|
if (previous.coding === undefined) {
|
||||||
|
delete process.env.ZHIPU_CODING_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZHIPU_CODING_API_KEY = previous.coding;
|
||||||
|
}
|
||||||
|
if (previous.zhipu === undefined) {
|
||||||
|
delete process.env.ZHIPU_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.ZHIPU_API_KEY = previous.zhipu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("resolves Synthetic API key from env", async () => {
|
it("resolves Synthetic API key from env", async () => {
|
||||||
const previousSynthetic = process.env.SYNTHETIC_API_KEY;
|
const previousSynthetic = process.env.SYNTHETIC_API_KEY;
|
||||||
|
|
||||||
|
|||||||
@ -182,6 +182,24 @@ describe("cli program (smoke)", () => {
|
|||||||
key: "sk-zai-test",
|
key: "sk-zai-test",
|
||||||
field: "zaiApiKey",
|
field: "zaiApiKey",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
authChoice: "zai-coding-api-key",
|
||||||
|
flag: "--zai-coding-api-key",
|
||||||
|
key: "sk-zai-coding-test",
|
||||||
|
field: "zaiCodingApiKey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
authChoice: "zhipu-api-key",
|
||||||
|
flag: "--zhipu-api-key",
|
||||||
|
key: "sk-zhipu-test",
|
||||||
|
field: "zhipuApiKey",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
authChoice: "zhipu-coding-api-key",
|
||||||
|
flag: "--zhipu-coding-api-key",
|
||||||
|
key: "sk-zhipu-coding-test",
|
||||||
|
field: "zhipuCodingApiKey",
|
||||||
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
for (const entry of cases) {
|
for (const entry of cases) {
|
||||||
|
|||||||
@ -23,14 +23,19 @@ describe("buildAuthChoiceOptions", () => {
|
|||||||
expect(options.some((opt) => opt.value === "token")).toBe(true);
|
expect(options.some((opt) => opt.value === "token")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes Z.AI (GLM) auth choice", () => {
|
it("includes Z.AI / Zhipu (GLM) auth choices", () => {
|
||||||
const store: AuthProfileStore = { version: 1, profiles: {} };
|
const store: AuthProfileStore = { version: 1, profiles: {} };
|
||||||
const options = buildAuthChoiceOptions({
|
const options = buildAuthChoiceOptions({
|
||||||
store,
|
store,
|
||||||
includeSkip: false,
|
includeSkip: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// International variants (api.z.ai)
|
||||||
expect(options.some((opt) => opt.value === "zai-api-key")).toBe(true);
|
expect(options.some((opt) => opt.value === "zai-api-key")).toBe(true);
|
||||||
|
expect(options.some((opt) => opt.value === "zai-coding-api-key")).toBe(true);
|
||||||
|
// China variants (bigmodel.cn)
|
||||||
|
expect(options.some((opt) => opt.value === "zhipu-api-key")).toBe(true);
|
||||||
|
expect(options.some((opt) => opt.value === "zhipu-coding-api-key")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes MiniMax auth choice", () => {
|
it("includes MiniMax auth choice", () => {
|
||||||
|
|||||||
@ -137,6 +137,49 @@ describe("provider usage loading", () => {
|
|||||||
expect(mockFetch).toHaveBeenCalled();
|
expect(mockFetch).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Implement fetchZhipuUsage in provider-usage.load.ts
|
||||||
|
it("loads zhipu usage from bigmodel.cn endpoint", async () => {
|
||||||
|
const makeResponse = (status: number, body: unknown): Response => {
|
||||||
|
const payload = typeof body === "string" ? body : JSON.stringify(body);
|
||||||
|
const headers = typeof body === "string" ? undefined : { "Content-Type": "application/json" };
|
||||||
|
return new Response(payload, { status, headers });
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockFetch = vi.fn<Parameters<typeof fetch>, ReturnType<typeof fetch>>(async (input) => {
|
||||||
|
const url =
|
||||||
|
typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
||||||
|
if (url.includes("open.bigmodel.cn")) {
|
||||||
|
return makeResponse(200, {
|
||||||
|
success: true,
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
planName: "Basic",
|
||||||
|
limits: [
|
||||||
|
{
|
||||||
|
type: "TOKENS_LIMIT",
|
||||||
|
percentage: 30,
|
||||||
|
unit: 3,
|
||||||
|
number: 6,
|
||||||
|
nextResetTime: "2026-01-07T06:00:00Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return makeResponse(404, "not found");
|
||||||
|
});
|
||||||
|
|
||||||
|
const summary = await loadProviderUsageSummary({
|
||||||
|
now: Date.UTC(2026, 0, 7, 0, 0, 0),
|
||||||
|
auth: [{ provider: "zhipu", token: "token-1" }],
|
||||||
|
fetch: mockFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
const zhipu = summary.providers.find((p) => p.provider === "zhipu");
|
||||||
|
expect(zhipu?.plan).toBe("Basic");
|
||||||
|
expect(zhipu?.windows[0]?.usedPercent).toBe(30);
|
||||||
|
});
|
||||||
|
|
||||||
it("handles nested MiniMax usage payloads", async () => {
|
it("handles nested MiniMax usage payloads", async () => {
|
||||||
const makeResponse = (status: number, body: unknown): Response => {
|
const makeResponse = (status: number, body: unknown): Response => {
|
||||||
const payload = typeof body === "string" ? body : JSON.stringify(body);
|
const payload = typeof body === "string" ? body : JSON.stringify(body);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user