mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-26 01:34:51 +08:00
Match the binary name, the Apps page tool id and the i18n keys that already used omp. The app is unreleased, so nothing persisted needs a migration; ohmypi stays accepted as an alias when parsing app ids. Show the app by default like Pi and Kimi Code.
210 lines
6.1 KiB
TypeScript
210 lines
6.1 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import UsageScriptModal from "@/components/UsageScriptModal";
|
|
import type { Provider, UsageScript } from "@/types";
|
|
|
|
vi.mock("@/components/common/FullScreenPanel", () => ({
|
|
FullScreenPanel: ({
|
|
isOpen,
|
|
children,
|
|
footer,
|
|
}: {
|
|
isOpen: boolean;
|
|
children: ReactNode;
|
|
footer?: ReactNode;
|
|
}) =>
|
|
isOpen ? (
|
|
<div>
|
|
<div>{children}</div>
|
|
<div>{footer}</div>
|
|
</div>
|
|
) : null,
|
|
}));
|
|
|
|
vi.mock("@/components/JsonEditor", () => ({
|
|
default: ({ value }: { value: string }) => (
|
|
<textarea data-testid="usage-script-code" value={value} readOnly />
|
|
),
|
|
}));
|
|
|
|
const provider: Provider = {
|
|
id: "sub2api-site",
|
|
name: "Example Sub2API",
|
|
settingsConfig: {
|
|
env: {
|
|
ANTHROPIC_BASE_URL: "https://api.example.com",
|
|
ANTHROPIC_AUTH_TOKEN: "sk-test",
|
|
},
|
|
},
|
|
meta: {
|
|
usage_script: {
|
|
enabled: true,
|
|
language: "javascript",
|
|
code: "({ request: { url: '' }, extractor: function () { return {}; } })",
|
|
},
|
|
},
|
|
};
|
|
|
|
function renderModal(
|
|
onSave: (script: UsageScript) => void,
|
|
usageScript?: UsageScript,
|
|
) {
|
|
const client = new QueryClient({
|
|
defaultOptions: { queries: { retry: false } },
|
|
});
|
|
render(
|
|
<QueryClientProvider client={client}>
|
|
<UsageScriptModal
|
|
provider={
|
|
usageScript
|
|
? { ...provider, meta: { usage_script: usageScript } }
|
|
: provider
|
|
}
|
|
appId="claude"
|
|
isOpen
|
|
onClose={() => {}}
|
|
onSave={onSave}
|
|
/>
|
|
</QueryClientProvider>,
|
|
);
|
|
}
|
|
|
|
describe("UsageScriptModal Sub2API template", () => {
|
|
it("fills the /v1/usage script and saves it as the sub2api template", async () => {
|
|
const onSave = vi.fn();
|
|
renderModal(onSave);
|
|
|
|
await userEvent.click(
|
|
screen.getByRole("button", { name: "usageScript.templateSub2API" }),
|
|
);
|
|
|
|
const code = (
|
|
screen.getByTestId("usage-script-code") as HTMLTextAreaElement
|
|
).value;
|
|
expect(code).toContain('+ "/v1/usage"');
|
|
expect(code).toContain("Bearer {{apiKey}}");
|
|
// 与通用模板一样只用 API Key 和地址,不显示访问令牌、用户 ID
|
|
expect(screen.getByLabelText(/API Key/)).toBeInTheDocument();
|
|
expect(
|
|
screen.queryByLabelText("usageScript.accessToken"),
|
|
).not.toBeInTheDocument();
|
|
|
|
await userEvent.click(
|
|
screen.getByRole("button", { name: "usageScript.saveConfig" }),
|
|
);
|
|
expect(onSave).toHaveBeenCalledWith(
|
|
expect.objectContaining({ templateType: "sub2api", code }),
|
|
);
|
|
});
|
|
|
|
it("reopens a script saved with the sub2api template as that template", async () => {
|
|
const onSave = vi.fn();
|
|
renderModal(onSave, {
|
|
...provider.meta!.usage_script!,
|
|
templateType: "sub2api",
|
|
});
|
|
|
|
await userEvent.click(
|
|
screen.getByRole("button", { name: "usageScript.saveConfig" }),
|
|
);
|
|
expect(onSave).toHaveBeenCalledWith(
|
|
expect.objectContaining({ templateType: "sub2api" }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("UsageScriptModal official subscription hint", () => {
|
|
// agy 的额度靠它自己的 /usage 命令查,不读登录凭据
|
|
it("explains Antigravity's quota check instead of reading OAuth credentials", () => {
|
|
const client = new QueryClient({
|
|
defaultOptions: { queries: { retry: false } },
|
|
});
|
|
render(
|
|
<QueryClientProvider client={client}>
|
|
<UsageScriptModal
|
|
provider={{
|
|
id: "agy-official",
|
|
name: "Google Official",
|
|
category: "official",
|
|
settingsConfig: { env: {}, config: {} },
|
|
meta: {
|
|
usage_script: {
|
|
enabled: true,
|
|
language: "javascript",
|
|
code: "",
|
|
templateType: "official_subscription",
|
|
},
|
|
},
|
|
}}
|
|
appId="agy"
|
|
isOpen
|
|
onClose={() => {}}
|
|
onSave={vi.fn()}
|
|
/>
|
|
</QueryClientProvider>,
|
|
);
|
|
expect(
|
|
screen.getByText("usageScript.officialSubscriptionHintAgy"),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.queryByText("usageScript.officialSubscriptionHint"),
|
|
).not.toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Oh My Pi has its own `AppId` ("omp"), so it never matched the `pi` branch
|
|
* and both built-in tests reported "API key is empty" on an omp card. The
|
|
* provider key and base URL must reach the balance API like they do for Pi.
|
|
*/
|
|
describe("UsageScriptModal Oh My Pi credentials", () => {
|
|
it("passes the omp provider's key and base URL to the balance test", async () => {
|
|
const getBalance = vi.fn().mockResolvedValue({ success: true, data: [] });
|
|
vi.doMock("@/lib/api/subscription", () => ({
|
|
subscriptionApi: { getBalance },
|
|
}));
|
|
const { default: Modal } = await import("@/components/UsageScriptModal");
|
|
const client = new QueryClient({
|
|
defaultOptions: { queries: { retry: false } },
|
|
});
|
|
render(
|
|
<QueryClientProvider client={client}>
|
|
<Modal
|
|
provider={{
|
|
id: "cc-switch-demo",
|
|
name: "Demo",
|
|
// A base URL the balance template recognises, so the test reaches
|
|
// `getBalance` instead of stopping at the template picker.
|
|
settingsConfig: {
|
|
baseUrl: "https://api.deepseek.com/v1",
|
|
apiKey: "sk-omp",
|
|
api: "openai-completions",
|
|
},
|
|
}}
|
|
appId="omp"
|
|
isOpen
|
|
onClose={() => {}}
|
|
onSave={() => {}}
|
|
/>
|
|
</QueryClientProvider>,
|
|
);
|
|
|
|
// The usage query is off by default; enabling it asks for confirmation once.
|
|
await userEvent.click(screen.getByRole("switch"));
|
|
await userEvent.click(
|
|
screen.getByRole("button", { name: "confirm.usage.confirm" }),
|
|
);
|
|
await userEvent.click(
|
|
screen.getByRole("button", { name: "usageScript.testScript" }),
|
|
);
|
|
|
|
expect(getBalance).toHaveBeenCalledWith(
|
|
"https://api.deepseek.com/v1",
|
|
"sk-omp",
|
|
);
|
|
});
|
|
});
|