Files
2026-07-13 13:36:53 +08:00

274 lines
9.1 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
PROVIDERS,
GATEWAY_PLATFORMS,
GATEWAY_SECTIONS,
SETTINGS_SECTIONS,
LOCAL_PRESETS,
OPENAI_COMPATIBLE_BASE_URLS,
DASHSCOPE_ENDPOINTS,
THEME_OPTIONS,
} from "../src/renderer/src/constants";
// ─── PROVIDERS ──────────────────────────────────────────
describe("PROVIDERS", () => {
it("has auto-detect as first option", () => {
expect(PROVIDERS.options[0]).toEqual({
value: "auto",
label: "constants.autoDetect",
});
});
it("includes all v0.9.0 providers", () => {
const values = PROVIDERS.options.map((o) => o.value);
expect(values).toContain("openrouter");
expect(values).toContain("aimlapi");
expect(values).toContain("anthropic");
expect(values).toContain("openai");
expect(values).toContain("openai-codex");
expect(values).toContain("google");
expect(values).toContain("xai");
expect(values).toContain("xiaomi");
expect(values).toContain("nous");
expect(values).toContain("alibaba");
expect(values).toContain("qwen-oauth");
expect(values).toContain("minimax");
expect(values).toContain("lmstudio");
expect(values).toContain("ollama");
expect(values).toContain("vllm");
expect(values).toContain("llamacpp");
expect(values).toContain("custom");
});
it("has labels for every non-auto provider option", () => {
for (const opt of PROVIDERS.options) {
if (opt.value === "auto") continue;
expect(PROVIDERS.labels[opt.value]).toBeTruthy();
}
});
it("setup entries have required fields", () => {
for (const entry of PROVIDERS.setup) {
expect(entry.id).toBeTruthy();
expect(entry.name).toBeTruthy();
expect(entry.configProvider).toBeTruthy();
expect(typeof entry.needsKey).toBe("boolean");
}
});
it("setup entries that need a key have envKey and url", () => {
for (const entry of PROVIDERS.setup) {
if (entry.needsKey) {
expect(entry.envKey).toBeTruthy();
expect(entry.url).toBeTruthy();
}
}
});
it("no duplicate option values", () => {
const values = PROVIDERS.options.map((o) => o.value);
expect(new Set(values).size).toBe(values.length);
});
it("no duplicate setup IDs", () => {
const ids = PROVIDERS.setup.map((s) => s.id);
expect(new Set(ids).size).toBe(ids.length);
});
it("offers DashScope setup through Alibaba with a mainland default", () => {
const dashscope = PROVIDERS.setup.find((s) => s.id === "alibaba");
expect(dashscope).toBeTruthy();
expect(dashscope?.configProvider).toBe("alibaba");
expect(dashscope?.envKey).toBe("DASHSCOPE_API_KEY");
expect(dashscope?.baseUrl).toBe(DASHSCOPE_ENDPOINTS[0].baseUrl);
});
});
// ─── GATEWAY_PLATFORMS ──────────────────────────────────
describe("GATEWAY_PLATFORMS", () => {
it("has 16 platforms (matching v0.9.0 release)", () => {
expect(GATEWAY_PLATFORMS.length).toBe(16);
});
it("includes all core platforms", () => {
const keys = GATEWAY_PLATFORMS.map((p) => p.key);
expect(keys).toContain("telegram");
expect(keys).toContain("discord");
expect(keys).toContain("slack");
expect(keys).toContain("whatsapp");
expect(keys).toContain("signal");
expect(keys).toContain("matrix");
expect(keys).toContain("email");
expect(keys).toContain("sms");
expect(keys).toContain("bluebubbles"); // iMessage
expect(keys).toContain("dingtalk");
expect(keys).toContain("feishu");
expect(keys).toContain("wecom");
expect(keys).toContain("weixin"); // WeChat
expect(keys).toContain("webhooks");
expect(keys).toContain("home_assistant");
expect(keys).toContain("mattermost");
});
it("no duplicate platform keys", () => {
const keys = GATEWAY_PLATFORMS.map((p) => p.key);
expect(new Set(keys).size).toBe(keys.length);
});
it("every platform has at least one field", () => {
for (const p of GATEWAY_PLATFORMS) {
expect(p.fields.length).toBeGreaterThan(0);
}
});
it("every platform has label and description", () => {
for (const p of GATEWAY_PLATFORMS) {
expect(p.label).toBeTruthy();
expect(p.description).toBeTruthy();
}
});
it("every platform field exists in GATEWAY_SECTIONS", () => {
const allSectionKeys = new Set(
GATEWAY_SECTIONS.flatMap((s) => s.items.map((i) => i.key)),
);
for (const p of GATEWAY_PLATFORMS) {
for (const field of p.fields) {
expect(allSectionKeys.has(field)).toBe(true);
}
}
});
});
// ─── GATEWAY_SECTIONS ───────────────────────────────────
describe("GATEWAY_SECTIONS", () => {
it("has at least one section", () => {
expect(GATEWAY_SECTIONS.length).toBeGreaterThan(0);
});
it("every item has key, label, type, hint", () => {
for (const section of GATEWAY_SECTIONS) {
for (const item of section.items) {
expect(item.key).toBeTruthy();
expect(item.label).toBeTruthy();
expect(item.type).toBeTruthy();
expect(typeof item.hint).toBe("string");
}
}
});
it("no duplicate field keys across sections", () => {
const allKeys = GATEWAY_SECTIONS.flatMap((s) => s.items.map((i) => i.key));
expect(new Set(allKeys).size).toBe(allKeys.length);
});
it("password type fields contain sensitive keywords", () => {
for (const section of GATEWAY_SECTIONS) {
for (const item of section.items) {
if (item.type === "password") {
const lk = item.key.toLowerCase();
expect(
lk.includes("token") ||
lk.includes("key") ||
lk.includes("secret") ||
lk.includes("password"),
).toBe(true);
}
}
}
});
});
// ─── SETTINGS_SECTIONS ──────────────────────────────────
describe("SETTINGS_SECTIONS", () => {
it("includes LLM Providers section", () => {
expect(
SETTINGS_SECTIONS.find(
(s) => s.title === "constants.sectionLlmProviders",
),
).toBeTruthy();
});
it("includes Google AI Studio and xAI keys", () => {
const allKeys = SETTINGS_SECTIONS.flatMap((s) => s.items.map((i) => i.key));
expect(allKeys).toContain("GOOGLE_API_KEY");
expect(allKeys).toContain("XAI_API_KEY");
expect(allKeys).toContain("XIAOMI_API_KEY");
expect(allKeys).toContain("AIMLAPI_API_KEY");
});
it("includes existing keys (backward compat)", () => {
const allKeys = SETTINGS_SECTIONS.flatMap((s) => s.items.map((i) => i.key));
expect(allKeys).toContain("OPENROUTER_API_KEY");
expect(allKeys).toContain("OPENAI_API_KEY");
expect(allKeys).toContain("ANTHROPIC_API_KEY");
expect(allKeys).toContain("HF_TOKEN");
expect(allKeys).toContain("EXA_API_KEY");
expect(allKeys).toContain("FAL_KEY");
expect(allKeys).toContain("BROWSERBASE_API_KEY");
});
it("no duplicate keys across all settings sections", () => {
const allKeys = SETTINGS_SECTIONS.flatMap((s) => s.items.map((i) => i.key));
expect(new Set(allKeys).size).toBe(allKeys.length);
});
});
// ─── Static constants ───────────────────────────────────
describe("LOCAL_PRESETS", () => {
it("has expected presets", () => {
const ids = LOCAL_PRESETS.map((p) => p.id);
expect(ids).toContain("lmstudio");
expect(ids).toContain("aimlapi");
expect(ids).toContain("ollama");
expect(ids).toContain("vllm");
expect(ids).toContain("llamacpp");
});
it("exposes every local preset as a provider dropdown option", () => {
const options = new Set(PROVIDERS.options.map((o) => o.value));
for (const preset of LOCAL_PRESETS.filter((p) => p.group === "local")) {
expect(options.has(preset.id)).toBe(true);
expect(PROVIDERS.labels[preset.id]).toBeTruthy();
}
});
// Every preset chip routes through OPENAI_COMPATIBLE_BASE_URLS in the
// Providers picker; a missing entry collapses the picker and mis-saves the
// provider (regression: AtlasCloud/LM Studio fell through to native routing).
it("maps every preset id to an OpenAI-compatible base URL", () => {
for (const preset of LOCAL_PRESETS) {
expect(OPENAI_COMPATIBLE_BASE_URLS[preset.id]).toBeTruthy();
}
});
});
describe("DASHSCOPE_ENDPOINTS", () => {
it("offers mainland and international DashScope endpoints", () => {
expect(DASHSCOPE_ENDPOINTS).toEqual([
{
id: "cn",
name: "constants.dashscopeChinaEndpoint",
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
},
{
id: "intl",
name: "constants.dashscopeIntlEndpoint",
baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
},
]);
});
});
describe("THEME_OPTIONS", () => {
it("has system, light, dark", () => {
const values = THEME_OPTIONS.map((t) => t.value);
expect(values).toEqual(["system", "light", "dark"]);
});
});