Rename `AppType` to `AppId` across the entire frontend codebase to better reflect its purpose as an application identifier rather than a type category. This aligns frontend naming with backend command parameter conventions. Changes: - Rename type `AppType` to `AppId` in src/lib/api/types.ts - Remove `AppType` export from src/lib/api/index.ts - Update all component props from `appType` to `appId` (43 files) - Update all variable names from `appType` to `appId` - Synchronize documentation (CHANGELOG, refactoring plans) - Update test files and MSW mocks BREAKING CHANGE: `AppType` type is no longer exported. Use `AppId` instead. All component props have been renamed from `appType` to `appId`.
123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { AddProviderDialog } from "@/components/providers/AddProviderDialog";
|
|
import type { ProviderFormValues } from "@/components/providers/forms/ProviderForm";
|
|
|
|
vi.mock("@/components/ui/dialog", () => ({
|
|
Dialog: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
|
DialogContent: ({ children }: { children: React.ReactNode }) => (
|
|
<div>{children}</div>
|
|
),
|
|
DialogHeader: ({ children }: { children: React.ReactNode }) => (
|
|
<div>{children}</div>
|
|
),
|
|
DialogTitle: ({ children }: { children: React.ReactNode }) => (
|
|
<h1>{children}</h1>
|
|
),
|
|
DialogDescription: ({ children }: { children: React.ReactNode }) => (
|
|
<p>{children}</p>
|
|
),
|
|
DialogFooter: ({ children }: { children: React.ReactNode }) => (
|
|
<div>{children}</div>
|
|
),
|
|
}));
|
|
|
|
let mockFormValues: ProviderFormValues;
|
|
|
|
vi.mock("@/components/providers/forms/ProviderForm", () => ({
|
|
ProviderForm: ({ onSubmit }: { onSubmit: (values: ProviderFormValues) => void }) => (
|
|
<form
|
|
id="provider-form"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
onSubmit(mockFormValues);
|
|
}}
|
|
/>
|
|
),
|
|
}));
|
|
|
|
describe("AddProviderDialog", () => {
|
|
beforeEach(() => {
|
|
mockFormValues = {
|
|
name: "Test Provider",
|
|
websiteUrl: "https://provider.example.com",
|
|
settingsConfig: JSON.stringify({ env: {}, config: {} }),
|
|
meta: {
|
|
custom_endpoints: {
|
|
"https://api.new-endpoint.com": {
|
|
url: "https://api.new-endpoint.com",
|
|
addedAt: 1,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
it("使用 ProviderForm 返回的自定义端点", async () => {
|
|
const handleSubmit = vi.fn().mockResolvedValue(undefined);
|
|
const handleOpenChange = vi.fn();
|
|
|
|
render(
|
|
<AddProviderDialog
|
|
open
|
|
onOpenChange={handleOpenChange}
|
|
appId="claude"
|
|
onSubmit={handleSubmit}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(
|
|
screen.getByRole("button", {
|
|
name: "common.add",
|
|
}),
|
|
);
|
|
|
|
await waitFor(() => expect(handleSubmit).toHaveBeenCalledTimes(1));
|
|
|
|
const submitted = handleSubmit.mock.calls[0][0];
|
|
expect(submitted.meta?.custom_endpoints).toEqual(
|
|
mockFormValues.meta?.custom_endpoints,
|
|
);
|
|
expect(handleOpenChange).toHaveBeenCalledWith(false);
|
|
});
|
|
|
|
it("在缺少自定义端点时回退到配置中的 baseUrl", async () => {
|
|
const handleSubmit = vi.fn().mockResolvedValue(undefined);
|
|
|
|
mockFormValues = {
|
|
name: "Base URL Provider",
|
|
websiteUrl: "",
|
|
settingsConfig: JSON.stringify({
|
|
env: { ANTHROPIC_BASE_URL: "https://claude.base" },
|
|
config: {},
|
|
}),
|
|
};
|
|
|
|
render(
|
|
<AddProviderDialog
|
|
open
|
|
onOpenChange={vi.fn()}
|
|
appId="claude"
|
|
onSubmit={handleSubmit}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(
|
|
screen.getByRole("button", {
|
|
name: "common.add",
|
|
}),
|
|
);
|
|
|
|
await waitFor(() => expect(handleSubmit).toHaveBeenCalledTimes(1));
|
|
|
|
const submitted = handleSubmit.mock.calls[0][0];
|
|
expect(submitted.meta?.custom_endpoints).toEqual({
|
|
"https://claude.base": {
|
|
url: "https://claude.base",
|
|
addedAt: expect.any(Number),
|
|
lastUsed: undefined,
|
|
},
|
|
});
|
|
});
|
|
});
|