mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-26 01:34:51 +08:00
Unify the visual and interaction rules on top of the v7 redesign. - Theme color #F97315 for --action-* and --ring; dark mode uses #EA580C with white text, toned-down mode colors and translucent soft fills - Buttons mapped to three sizes (28 / 32 / 36); inputs, selects and search fields share fieldClass; self-drawn checkbox and radio - HoverTip replaces title on about 100 icon buttons; it stays closed when a closing menu returns focus to its trigger - Install tailwindcss-animate so menu, popover, dialog and tooltip enter/exit animations take effect; sliding segment thumb and tab underline - Remove the command palette and the header prompt entry; provider card primary actions become icon buttons - Virtualize the session list and the Skills discovery list; optimistic toggles for MCP and Skills with a 300ms delayed disabled state - Toasts drawn unstyled with status-colored icons and de-duplicated - Windows: hide the system title bar and use in-app window controls; macOS: brand row under the traffic lights - Focus rings only for keyboard users - Skills discovery and the prompt list show the last result from a local cache and refresh in the background - Drop the trailing ellipsis from 36 dialog-opening labels - Provider list fills the main area Co-authored-by: 千羽 <qyinter@users.noreply.github.com>
85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { GlobalProxySettings } from "@/components/settings/GlobalProxySettings";
|
|
|
|
vi.mock("react-i18next", () => ({
|
|
useTranslation: () => ({ t: (key: string) => key }),
|
|
}));
|
|
|
|
const mutateAsyncMock = vi.fn();
|
|
const testMutateAsyncMock = vi.fn();
|
|
const scanMutateAsyncMock = vi.fn();
|
|
|
|
vi.mock("@/hooks/useGlobalProxy", () => ({
|
|
useGlobalProxyUrl: () => ({
|
|
data: "http://127.0.0.1:7890",
|
|
isLoading: false,
|
|
}),
|
|
useSetGlobalProxyUrl: () => ({
|
|
mutateAsync: mutateAsyncMock,
|
|
isPending: false,
|
|
}),
|
|
useTestProxy: () => ({
|
|
mutateAsync: testMutateAsyncMock,
|
|
isPending: false,
|
|
}),
|
|
useScanProxies: () => ({
|
|
mutateAsync: scanMutateAsyncMock,
|
|
isPending: false,
|
|
}),
|
|
}));
|
|
|
|
describe("GlobalProxySettings", () => {
|
|
beforeEach(() => {
|
|
mutateAsyncMock.mockReset();
|
|
testMutateAsyncMock.mockReset();
|
|
scanMutateAsyncMock.mockReset();
|
|
});
|
|
|
|
it("renders proxy URL input with saved value", async () => {
|
|
render(<GlobalProxySettings />);
|
|
|
|
const urlInput = screen.getByPlaceholderText(
|
|
"http://127.0.0.1:7890 / socks5://127.0.0.1:1080",
|
|
);
|
|
// URL 对象会在末尾添加斜杠
|
|
await waitFor(() => expect(urlInput).toHaveValue("http://127.0.0.1:7890/"));
|
|
});
|
|
|
|
it("saves proxy URL when save button is clicked", async () => {
|
|
render(<GlobalProxySettings />);
|
|
|
|
const urlInput = screen.getByPlaceholderText(
|
|
"http://127.0.0.1:7890 / socks5://127.0.0.1:1080",
|
|
);
|
|
|
|
fireEvent.change(urlInput, { target: { value: "http://localhost:8080" } });
|
|
|
|
const saveButton = screen.getByRole("button", { name: "common.save" });
|
|
fireEvent.click(saveButton);
|
|
|
|
await waitFor(() => expect(mutateAsyncMock).toHaveBeenCalled());
|
|
// 没有用户名时,URL 不经过 URL 对象解析,所以没有尾部斜杠
|
|
expect(mutateAsyncMock).toHaveBeenCalledWith("http://localhost:8080");
|
|
});
|
|
|
|
it("clears proxy URL when clear button is clicked", async () => {
|
|
render(<GlobalProxySettings />);
|
|
|
|
const urlInput = screen.getByPlaceholderText(
|
|
"http://127.0.0.1:7890 / socks5://127.0.0.1:1080",
|
|
);
|
|
|
|
// Wait for initial value to load
|
|
await waitFor(() => expect(urlInput).toHaveValue("http://127.0.0.1:7890/"));
|
|
|
|
// Click clear button
|
|
const clearButton = screen.getByRole("button", {
|
|
name: "settings.globalProxy.clear",
|
|
});
|
|
fireEvent.click(clearButton);
|
|
|
|
expect(urlInput).toHaveValue("");
|
|
});
|
|
});
|