Files
browser/platform_web/pages/AiProvidersPage.test.tsx
2026-07-20 16:42:33 +08:00

103 lines
4.4 KiB
TypeScript

import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { AiProvidersPage } from "./AiProvidersPage";
import aiProvidersPageSource from "./AiProvidersPage.tsx?raw";
import type { AiProviderResponse } from "../api/types";
const provider: AiProviderResponse = {
id: "ai.openai",
name: "OpenAI Relay",
kind: "openai-compatible",
baseUrlConfigured: true,
apiKeyConfigured: true,
models: ["gpt-4.1", "gpt-4.1-mini"],
defaultModel: "gpt-4.1-mini",
relayMode: "relay",
timeoutMs: 30000,
status: "active",
redactionPolicy: "default"
};
describe("AiProvidersPage", () => {
it("renders the loading state before API data arrives", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ listState: "loading" }} />);
expect(html).toContain("AI 提供商管理");
expect(html).toContain("正在加载 AI 提供商");
});
it("renders an empty API state when the platform returns no providers", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ providers: [], listState: "ready", source: "api" }} />);
expect(html).toContain("暂无 AI 提供商");
expect(html).toContain("page-summary-chip");
expect(html).not.toContain("metric-card");
expect(html).toContain("平台还没有返回任何提供商");
expect(html).toContain("新增提供商");
expect(html).not.toContain('value="secret://providers/"');
expect(html).not.toContain("OpenAI Relay");
});
it("renders provider API failure with scoped retry instead of a browser reload", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ listState: "error", listError: "backend unavailable", source: "error" }} />);
expect(html).toContain("AI 提供商加载失败");
expect(html).toContain("backend unavailable");
expect(html).toContain("重试");
expect(aiProvidersPageSource).toContain("refreshProviders");
expect(aiProvidersPageSource).not.toContain("window.location.reload");
});
it("renders local-development fixtures with an explicit status label", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ providers: [provider], listState: "ready", source: "local-development" }} />);
expect(html).toContain("OpenAI Relay");
expect(html).toContain("本地开发");
expect(html).toContain("已配置");
expect(html).not.toContain("secret://providers/openai");
expect(html).toContain("测试");
expect(html).toContain("模型");
expect(html).toContain("编辑");
expect(html).toContain("更多");
});
it("renders guided provider setup for an existing provider", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ providers: [provider], selectedId: provider.id, listState: "ready", source: "api" }} />);
expect(html).toContain("配置流程");
expect(html).toContain("提供商预设");
expect(html).toContain("系统 ID");
expect(html).toContain("自动生成,不需要手填");
expect(html).toContain("高级设置:Base URL、模型、模式、超时");
expect(html).toContain("保存前检查");
expect(html).toContain("测试已保存配置");
expect(html).toContain("发现模型并填入");
expect(html).toContain("secret://providers/...");
expect(html).not.toContain('name="id"');
expect(html).not.toContain("api.example.test");
expect(html).not.toContain("relay.example.test");
});
it("does not render raw key field names", () => {
const html = renderToStaticMarkup(<AiProvidersPage initialState={{ providers: [provider], listState: "ready", source: "api" }} />);
expect(html).not.toContain("apiKey=");
expect(html).not.toContain("rawApiKey");
expect(html).not.toContain('value="sk-');
expect(html).not.toContain(">sk-");
expect(html).not.toContain("api_key=");
expect(html).not.toContain("Bearer ");
});
it("keeps provider state actions confirmed and provider-scoped busy", () => {
expect(aiProvidersPageSource).toContain("confirmStatus");
expect(aiProvidersPageSource).toContain("busyProviderIds.has(provider.id)");
expect(aiProvidersPageSource).toContain("确认提供商状态变更");
expect(aiProvidersPageSource).toContain("只读模式");
expect(aiProvidersPageSource).toContain("operations?.begin");
expect(aiProvidersPageSource).toContain("operations?.succeed");
expect(aiProvidersPageSource).toContain("operations?.fail");
});
});