Adding unit tests for coverage

This commit is contained in:
yuneng-jiang
2026-01-06 22:46:06 -08:00
parent 6078f4687e
commit 6fd7b1cf56
4 changed files with 542 additions and 0 deletions
@@ -0,0 +1,185 @@
import { Form } from "antd";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../../../../../tests/test-utils";
import { afterEach, describe, expect, it, vi } from "vitest";
import BaseSSOSettingsForm, { renderProviderFields } from "./BaseSSOSettingsForm";
describe("BaseSSOSettingsForm", () => {
afterEach(() => {
vi.clearAllMocks();
});
it("should render", () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
expect(screen.getByText("SSO Provider")).toBeInTheDocument();
expect(screen.getByText("Proxy Admin Email")).toBeInTheDocument();
expect(screen.getByText("Proxy Base URL")).toBeInTheDocument();
});
it("should render provider fields when provider is selected", async () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
const providerSelect = screen.getByLabelText("SSO Provider");
await act(async () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const googleOption = screen.getByText(/google sso/i);
fireEvent.click(googleOption);
});
await waitFor(() => {
expect(screen.getByText("Google Client ID")).toBeInTheDocument();
expect(screen.getByText("Google Client Secret")).toBeInTheDocument();
});
});
it("should show role mappings fields for okta provider", async () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
const providerSelect = screen.getByLabelText("SSO Provider");
await act(async () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const oktaOption = screen.getByText(/okta/i);
fireEvent.click(oktaOption);
});
await waitFor(() => {
expect(screen.getByText("Use Role Mappings")).toBeInTheDocument();
});
});
it("should validate proxy base url format", async () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
const urlInput = screen.getByPlaceholderText("https://example.com");
await act(async () => {
fireEvent.change(urlInput, { target: { value: "invalid-url" } });
fireEvent.blur(urlInput);
});
await waitFor(() => {
expect(screen.getByText(/URL must start with http:\/\/ or https:\/\//i)).toBeInTheDocument();
});
});
it("should validate proxy base url trailing slash", async () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
const urlInput = screen.getByPlaceholderText("https://example.com");
await act(async () => {
fireEvent.change(urlInput, { target: { value: "https://example.com/" } });
fireEvent.blur(urlInput);
});
await waitFor(() => {
expect(screen.getByText(/URL must not end with a trailing slash/i)).toBeInTheDocument();
});
});
it("should show role mappings fields when use_role_mappings is checked for generic provider", async () => {
const TestWrapper = () => {
const [form] = Form.useForm();
const handleSubmit = vi.fn();
return <BaseSSOSettingsForm form={form} onFormSubmit={handleSubmit} />;
};
renderWithProviders(<TestWrapper />);
const providerSelect = screen.getByLabelText("SSO Provider");
await act(async () => {
fireEvent.mouseDown(providerSelect);
});
await waitFor(() => {
const genericOption = screen.getByText(/generic sso/i);
fireEvent.click(genericOption);
});
await waitFor(() => {
expect(screen.getByText("Use Role Mappings")).toBeInTheDocument();
});
const checkbox = screen.getByLabelText("Use Role Mappings");
await act(async () => {
fireEvent.click(checkbox);
});
await waitFor(() => {
expect(screen.getByText("Group Claim")).toBeInTheDocument();
expect(screen.getByText("Default Role")).toBeInTheDocument();
});
});
});
describe("renderProviderFields", () => {
it("should return null for unknown provider", () => {
const result = renderProviderFields("unknown");
expect(result).toBeNull();
});
it("should return fields for google provider", () => {
const result = renderProviderFields("google");
expect(result).not.toBeNull();
expect(result?.length).toBe(2);
});
it("should return fields for microsoft provider", () => {
const result = renderProviderFields("microsoft");
expect(result).not.toBeNull();
expect(result?.length).toBe(3);
});
it("should return fields for okta provider", () => {
const result = renderProviderFields("okta");
expect(result).not.toBeNull();
expect(result?.length).toBe(5);
});
it("should return fields for generic provider", () => {
const result = renderProviderFields("generic");
expect(result).not.toBeNull();
expect(result?.length).toBe(5);
});
});
@@ -0,0 +1,138 @@
import * as networking from "@/components/networking";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../../tests/test-utils";
import { afterEach, describe, expect, it, vi } from "vitest";
import AvailableTeamsPanel from "./available_teams";
vi.mock("@/components/networking", () => ({
availableTeamListCall: vi.fn(),
teamMemberAddCall: vi.fn(),
}));
describe("AvailableTeamsPanel", () => {
afterEach(() => {
vi.clearAllMocks();
});
it("should render", async () => {
vi.mocked(networking.availableTeamListCall).mockResolvedValue([]);
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("Team Name")).toBeInTheDocument();
});
});
it("should display teams when available", async () => {
const mockTeams = [
{
team_id: "team-1",
team_alias: "Test Team 1",
description: "Test Description 1",
models: ["gpt-4"],
members_with_roles: [{ user_id: "user-1", user_email: "user1@test.com", role: "admin" }],
},
{
team_id: "team-2",
team_alias: "Test Team 2",
description: "Test Description 2",
models: [],
members_with_roles: [{ user_id: "user-2", user_email: "user2@test.com", role: "user" }],
},
];
vi.mocked(networking.availableTeamListCall).mockResolvedValue(mockTeams);
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("Test Team 1")).toBeInTheDocument();
expect(screen.getByText("Test Team 2")).toBeInTheDocument();
});
});
it("should display empty state when no teams are available", async () => {
vi.mocked(networking.availableTeamListCall).mockResolvedValue([]);
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("No available teams to join")).toBeInTheDocument();
});
});
it("should call teamMemberAddCall when join team button is clicked", async () => {
const mockTeams = [
{
team_id: "team-1",
team_alias: "Test Team 1",
description: "Test Description 1",
models: ["gpt-4"],
members_with_roles: [{ user_id: "user-1", user_email: "user1@test.com", role: "admin" }],
},
];
vi.mocked(networking.availableTeamListCall).mockResolvedValue(mockTeams);
vi.mocked(networking.teamMemberAddCall).mockResolvedValue({});
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("Test Team 1")).toBeInTheDocument();
});
const joinButtons = screen.getAllByRole("button", { name: /join team/i });
await act(async () => {
fireEvent.click(joinButtons[0]);
});
await waitFor(() => {
expect(networking.teamMemberAddCall).toHaveBeenCalledWith("token-123", "team-1", {
user_id: "user-123",
role: "user",
});
});
});
it("should display All Proxy Models badge when team has no models", async () => {
const mockTeams = [
{
team_id: "team-1",
team_alias: "Test Team 1",
description: "Test Description 1",
models: [],
members_with_roles: [{ user_id: "user-1", user_email: "user1@test.com", role: "admin" }],
},
];
vi.mocked(networking.availableTeamListCall).mockResolvedValue(mockTeams);
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("All Proxy Models")).toBeInTheDocument();
});
});
it("should display model badges when team has models", async () => {
const mockTeams = [
{
team_id: "team-1",
team_alias: "Test Team 1",
description: "Test Description 1",
models: ["gpt-4", "gpt-3.5-turbo"],
members_with_roles: [{ user_id: "user-1", user_email: "user1@test.com", role: "admin" }],
},
];
vi.mocked(networking.availableTeamListCall).mockResolvedValue(mockTeams);
renderWithProviders(<AvailableTeamsPanel accessToken="token-123" userID="user-123" />);
await waitFor(() => {
expect(screen.getByText("gpt-4")).toBeInTheDocument();
expect(screen.getByText("gpt-3.5-turbo")).toBeInTheDocument();
});
});
});
@@ -0,0 +1,160 @@
import * as networking from "@/components/networking";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import { renderWithProviders } from "../../../tests/test-utils";
import { afterEach, describe, expect, it, vi } from "vitest";
import MemberPermissions from "./member_permissions";
vi.mock("@/components/networking", () => ({
getTeamPermissionsCall: vi.fn(),
teamPermissionsUpdateCall: vi.fn(),
}));
describe("MemberPermissions", () => {
afterEach(() => {
vi.clearAllMocks();
});
it("should render", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={true} />);
await waitFor(() => {
expect(screen.getByText("Member Permissions")).toBeInTheDocument();
});
});
it("should display permissions table when permissions are available", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={true} />);
await waitFor(() => {
expect(screen.getByText("Method")).toBeInTheDocument();
expect(screen.getByText("Endpoint")).toBeInTheDocument();
expect(screen.getByText("Description")).toBeInTheDocument();
expect(screen.getByText("Allow Access")).toBeInTheDocument();
});
});
it("should display empty state when no permissions are available", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: [],
team_member_permissions: [],
});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={true} />);
await waitFor(() => {
expect(screen.getByText("No permissions available")).toBeInTheDocument();
});
});
it("should save permissions when save button is clicked", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
vi.mocked(networking.teamPermissionsUpdateCall).mockResolvedValue({});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={true} />);
await waitFor(() => {
expect(screen.getByText("Member Permissions")).toBeInTheDocument();
});
const checkboxes = screen.getAllByRole("checkbox");
const unselectedCheckbox = checkboxes.find((cb) => !(cb as HTMLInputElement).checked);
if (unselectedCheckbox) {
await act(async () => {
fireEvent.click(unselectedCheckbox);
});
await waitFor(() => {
const saveButton = screen.getByRole("button", { name: /save changes/i });
expect(saveButton).toBeInTheDocument();
});
const saveButton = screen.getByRole("button", { name: /save changes/i });
await act(async () => {
fireEvent.click(saveButton);
});
await waitFor(() => {
expect(networking.teamPermissionsUpdateCall).toHaveBeenCalledWith(
"token-123",
"team-123",
expect.arrayContaining(["/key/generate", "/key/list"]),
);
});
}
});
it("should not show save button when canEditTeam is false", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={false} />);
await waitFor(() => {
expect(screen.getByText("Member Permissions")).toBeInTheDocument();
});
const checkboxes = screen.getAllByRole("checkbox");
checkboxes.forEach((checkbox) => {
expect(checkbox).toBeDisabled();
});
expect(screen.queryByRole("button", { name: /save changes/i })).not.toBeInTheDocument();
});
it("should handle reset button click", async () => {
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValue({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
renderWithProviders(<MemberPermissions teamId="team-123" accessToken="token-123" canEditTeam={true} />);
await waitFor(() => {
expect(screen.getByText("Member Permissions")).toBeInTheDocument();
});
const checkboxes = screen.getAllByRole("checkbox");
const unselectedCheckbox = checkboxes.find((cb) => !(cb as HTMLInputElement).checked);
if (unselectedCheckbox) {
await act(async () => {
fireEvent.click(unselectedCheckbox);
});
await waitFor(() => {
const resetButton = screen.getByRole("button", { name: /reset/i });
expect(resetButton).toBeInTheDocument();
});
vi.mocked(networking.getTeamPermissionsCall).mockResolvedValueOnce({
all_available_permissions: ["/key/generate", "/key/list"],
team_member_permissions: ["/key/generate"],
});
const resetButton = screen.getByRole("button", { name: /reset/i });
await act(async () => {
fireEvent.click(resetButton);
});
await waitFor(() => {
expect(networking.getTeamPermissionsCall).toHaveBeenCalledTimes(2);
});
}
});
});
@@ -0,0 +1,59 @@
import { describe, expect, it } from "vitest";
import { getMethodForEndpoint, getPermissionInfo, PERMISSION_DESCRIPTIONS } from "./permission_definitions";
describe("permission_definitions", () => {
describe("getMethodForEndpoint", () => {
it("should return GET for info endpoints", () => {
expect(getMethodForEndpoint("/key/info")).toBe("GET");
});
it("should return GET for list endpoints", () => {
expect(getMethodForEndpoint("/key/list")).toBe("GET");
});
it("should return POST for other endpoints", () => {
expect(getMethodForEndpoint("/key/generate")).toBe("POST");
expect(getMethodForEndpoint("/key/update")).toBe("POST");
expect(getMethodForEndpoint("/key/delete")).toBe("POST");
});
});
describe("getPermissionInfo", () => {
it("should return correct info for exact match permission", () => {
const result = getPermissionInfo("/key/generate");
expect(result.method).toBe("POST");
expect(result.endpoint).toBe("/key/generate");
expect(result.description).toBe(PERMISSION_DESCRIPTIONS["/key/generate"]);
expect(result.route).toBe("/key/generate");
});
it("should return GET method for info endpoint", () => {
const result = getPermissionInfo("/key/info");
expect(result.method).toBe("GET");
expect(result.endpoint).toBe("/key/info");
expect(result.description).toBe(PERMISSION_DESCRIPTIONS["/key/info"]);
});
it("should return GET method for list endpoint", () => {
const result = getPermissionInfo("/key/list");
expect(result.method).toBe("GET");
expect(result.endpoint).toBe("/key/list");
expect(result.description).toBe(PERMISSION_DESCRIPTIONS["/key/list"]);
});
it("should find partial match for permission with pattern", () => {
const result = getPermissionInfo("/key/service-account/generate");
expect(result.method).toBe("POST");
expect(result.endpoint).toBe("/key/service-account/generate");
expect(result.description).toBe(PERMISSION_DESCRIPTIONS["/key/service-account/generate"]);
});
it("should return fallback description for unknown permission", () => {
const result = getPermissionInfo("/unknown/endpoint");
expect(result.method).toBe("POST");
expect(result.endpoint).toBe("/unknown/endpoint");
expect(result.description).toBe("Access /unknown/endpoint");
expect(result.route).toBe("/unknown/endpoint");
});
});
});