diff --git a/webview-ui/src/components/settings/__tests__/LiteLLM.test.tsx b/webview-ui/src/components/settings/__tests__/LiteLLM.test.tsx index c946ac1670..d38f74458a 100644 --- a/webview-ui/src/components/settings/__tests__/LiteLLM.test.tsx +++ b/webview-ui/src/components/settings/__tests__/LiteLLM.test.tsx @@ -18,10 +18,7 @@ jest.mock("@src/context/ExtensionStateContext", () => ({ ...jest.requireActual("@src/context/ExtensionStateContext"), useExtensionState: jest.fn(() => ({ routerModels: { - litellm: { - "gpt-4": { name: "GPT-4", description: "OpenAI GPT-4 model" }, - "claude-3": { name: "Claude 3", description: "Anthropic Claude 3 model" }, - }, + litellm: {}, }, })), ExtensionStateContextProvider: ({ children }: any) =>
{children}
, @@ -31,19 +28,9 @@ jest.mock("@src/context/ExtensionStateContext", () => ({ jest.mock("@src/i18n/TranslationContext", () => ({ useAppTranslation: () => ({ t: (key: string) => { - const translations: Record = { - "settings:providers.litellmBaseUrl": "LiteLLM Base URL", - "settings:providers.litellmApiKey": "LiteLLM API Key", - "settings:placeholders.baseUrl": "Enter base URL", - "settings:placeholders.apiKey": "Enter API key", - "settings:providers.apiKeyStorageNotice": "API keys are stored securely", - "settings:providers.refreshModels.label": "Refresh Models", - "settings:providers.refreshModels.loading": "Loading models...", - "settings:providers.refreshModels.success": "Models refreshed successfully", - "settings:providers.refreshModels.error": "Failed to refresh models", - "settings:providers.refreshModels.missingConfig": "Please provide both API key and base URL", - } - return translations[key] || key + // Return the key itself as a fallback for testing + // This makes tests more resilient to translation changes + return key }, }), })) @@ -119,16 +106,16 @@ describe("LiteLLM", () => { it("renders all required fields", () => { renderLiteLLM() - expect(screen.getByText("LiteLLM Base URL")).toBeInTheDocument() - expect(screen.getByText("LiteLLM API Key")).toBeInTheDocument() - expect(screen.getByText("Refresh Models")).toBeInTheDocument() + expect(screen.getByTestId("litellm-base-url-input")).toBeInTheDocument() + expect(screen.getByTestId("litellm-api-key-input")).toBeInTheDocument() + expect(screen.getByTestId("litellm-refresh-models-button")).toBeInTheDocument() expect(screen.getByTestId("model-picker")).toBeInTheDocument() }) it("updates base URL when input changes", () => { renderLiteLLM() - const baseUrlInput = screen.getByPlaceholderText("Enter base URL") + const baseUrlInput = screen.getByTestId("litellm-base-url-input") fireEvent.change(baseUrlInput, { target: { value: "https://api.litellm.ai" } }) expect(mockSetApiConfigurationField).toHaveBeenCalledWith("litellmBaseUrl", "https://api.litellm.ai") @@ -137,7 +124,7 @@ describe("LiteLLM", () => { it("updates API key when input changes", () => { renderLiteLLM() - const apiKeyInput = screen.getByPlaceholderText("Enter API key") + const apiKeyInput = screen.getByTestId("litellm-api-key-input") fireEvent.change(apiKeyInput, { target: { value: "test-api-key" } }) expect(mockSetApiConfigurationField).toHaveBeenCalledWith("litellmApiKey", "test-api-key") @@ -146,7 +133,7 @@ describe("LiteLLM", () => { it("disables refresh button when API key or base URL is missing", () => { renderLiteLLM() - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") expect(refreshButton).toBeDisabled() }) @@ -162,47 +149,10 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") expect(refreshButton).not.toBeDisabled() }) - it("sends flushRouterModels and requestRouterModels messages when refresh button is clicked", async () => { - const configWithCredentials: ProviderSettings = { - ...defaultApiConfiguration, - litellmBaseUrl: "https://api.litellm.ai", - litellmApiKey: "test-api-key", - } - - renderLiteLLM({ - ...defaultProps, - apiConfiguration: configWithCredentials, - }) - - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) - - await act(async () => { - fireEvent.click(refreshButton) - }) - - // Verify that flushRouterModels is called first - expect(vscode.postMessage).toHaveBeenCalledWith({ - type: "flushRouterModels", - text: "litellm", - }) - - // Verify that requestRouterModels is called with the correct parameters - expect(vscode.postMessage).toHaveBeenCalledWith({ - type: "requestRouterModels", - values: { - litellmApiKey: "test-api-key", - litellmBaseUrl: "https://api.litellm.ai", - }, - }) - - // Verify both messages were sent - expect(vscode.postMessage).toHaveBeenCalledTimes(2) - }) - it("ensures flushRouterModels is called before requestRouterModels", async () => { const configWithCredentials: ProviderSettings = { ...defaultApiConfiguration, @@ -215,7 +165,7 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") await act(async () => { fireEvent.click(refreshButton) @@ -253,14 +203,14 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") await act(async () => { fireEvent.click(refreshButton) }) // Should show loading state - expect(screen.getByText("Loading models...")).toBeInTheDocument() + expect(screen.getByTestId("litellm-loading-message")).toBeInTheDocument() expect(refreshButton).toBeDisabled() }) @@ -276,7 +226,7 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") await act(async () => { fireEvent.click(refreshButton) @@ -299,7 +249,7 @@ describe("LiteLLM", () => { }) await waitFor(() => { - expect(screen.getByText("Models refreshed successfully")).toBeInTheDocument() + expect(screen.getByTestId("litellm-success-message")).toBeInTheDocument() }) }) @@ -315,7 +265,7 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") await act(async () => { fireEvent.click(refreshButton) @@ -336,7 +286,7 @@ describe("LiteLLM", () => { }) await waitFor(() => { - expect(screen.getByText("Invalid API key")).toBeInTheDocument() + expect(screen.getByTestId("litellm-error-message")).toBeInTheDocument() }) }) @@ -352,7 +302,7 @@ describe("LiteLLM", () => { apiConfiguration: configWithCredentials, }) - const refreshButton = screen.getByRole("button", { name: /refresh models/i }) + const refreshButton = screen.getByTestId("litellm-refresh-models-button") // First refresh attempt with error await act(async () => { @@ -394,7 +344,7 @@ describe("LiteLLM", () => { }) await waitFor(() => { - expect(screen.getByText("Models refreshed successfully")).toBeInTheDocument() + expect(screen.getByTestId("litellm-success-message")).toBeInTheDocument() }) }) }) diff --git a/webview-ui/src/components/settings/providers/LiteLLM.tsx b/webview-ui/src/components/settings/providers/LiteLLM.tsx index cdf25e1bd1..b70cd04790 100644 --- a/webview-ui/src/components/settings/providers/LiteLLM.tsx +++ b/webview-ui/src/components/settings/providers/LiteLLM.tsx @@ -88,7 +88,8 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField }: LiteLLMP value={apiConfiguration?.litellmBaseUrl || ""} onInput={handleInputChange("litellmBaseUrl")} placeholder={t("settings:placeholders.baseUrl")} - className="w-full"> + className="w-full" + data-testid="litellm-base-url-input"> @@ -97,7 +98,8 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField }: LiteLLMP type="password" onInput={handleInputChange("litellmApiKey")} placeholder={t("settings:placeholders.apiKey")} - className="w-full"> + className="w-full" + data-testid="litellm-api-key-input"> @@ -111,7 +113,8 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField }: LiteLLMP disabled={ refreshStatus === "loading" || !apiConfiguration.litellmApiKey || !apiConfiguration.litellmBaseUrl } - className="w-full"> + className="w-full" + data-testid="litellm-refresh-models-button">
{refreshStatus === "loading" ? ( @@ -122,15 +125,17 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField }: LiteLLMP
{refreshStatus === "loading" && ( -
+
{t("settings:providers.refreshModels.loading")}
)} {refreshStatus === "success" && ( -
{t("settings:providers.refreshModels.success")}
+
+ {t("settings:providers.refreshModels.success")} +
)} {refreshStatus === "error" && ( -
+
{refreshError || t("settings:providers.refreshModels.error")}
)}