Testing coverage with v8
This commit is contained in:
parent
a17980c744
commit
81c78931d8
3
.gitignore
vendored
3
.gitignore
vendored
@ -103,4 +103,5 @@ scripts/test_vertex_ai_search.py
|
||||
LAZY_LOADING_IMPROVEMENTS.md
|
||||
**/test-results
|
||||
**/playwright-report
|
||||
**/*.storageState.json
|
||||
**/*.storageState.json
|
||||
**/coverage
|
||||
@ -9,6 +9,7 @@
|
||||
"lint": "next lint",
|
||||
"test": "vitest",
|
||||
"test:watch": "vitest -w",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"e2e": "playwright test --config e2e_tests/playwright.config.ts",
|
||||
|
||||
@ -0,0 +1,284 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import React, { ReactNode } from "react";
|
||||
import { useGuardrails } from "./useGuardrails";
|
||||
import { getGuardrailsList } from "@/components/networking";
|
||||
|
||||
// Mock the networking function
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getGuardrailsList: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the queryKeysFactory - we'll mock the specific return value
|
||||
vi.mock("../common/queryKeysFactory", () => ({
|
||||
createQueryKeys: vi.fn((resource: string) => ({
|
||||
all: [resource],
|
||||
lists: () => [resource, "list"],
|
||||
list: (params?: any) => [resource, "list", { params }],
|
||||
details: () => [resource, "detail"],
|
||||
detail: (uid: string) => [resource, "detail", uid],
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock useAuthorized hook - we can override this in individual tests
|
||||
const mockUseAuthorized = vi.fn();
|
||||
vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
|
||||
default: () => mockUseAuthorized(),
|
||||
}));
|
||||
|
||||
// Mock data
|
||||
const mockGuardrailsResponse = {
|
||||
guardrails: [
|
||||
{ guardrail_name: "content-safety" },
|
||||
{ guardrail_name: "toxicity-filter" },
|
||||
{ guardrail_name: "pii-detection" },
|
||||
],
|
||||
};
|
||||
|
||||
const expectedGuardrailNames = ["content-safety", "toxicity-filter", "pii-detection"];
|
||||
|
||||
describe("useGuardrails", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Set default mock for useAuthorized (enabled state)
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("should return guardrail names when query is successful", async () => {
|
||||
// Mock successful API call
|
||||
(getGuardrailsList as any).mockResolvedValue(mockGuardrailsResponse);
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(expectedGuardrailNames);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(getGuardrailsList).toHaveBeenCalledWith("test-access-token");
|
||||
expect(getGuardrailsList).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle error when getGuardrailsList fails", async () => {
|
||||
const errorMessage = "Failed to fetch guardrails";
|
||||
const testError = new Error(errorMessage);
|
||||
|
||||
// Mock failed API call
|
||||
(getGuardrailsList as any).mockRejectedValue(testError);
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(testError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(getGuardrailsList).toHaveBeenCalledWith("test-access-token");
|
||||
expect(getGuardrailsList).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not execute query when accessToken is missing", async () => {
|
||||
// Mock missing accessToken
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(getGuardrailsList).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userId is missing", async () => {
|
||||
// Mock missing userId
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: null,
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(getGuardrailsList).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userRole is missing", async () => {
|
||||
// Mock missing userRole
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: null,
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(getGuardrailsList).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when all auth values are missing", async () => {
|
||||
// Mock all auth values missing
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: null,
|
||||
userRole: null,
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(getGuardrailsList).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should execute query when all auth values are present", async () => {
|
||||
// Mock successful API call
|
||||
(getGuardrailsList as any).mockResolvedValue(mockGuardrailsResponse);
|
||||
|
||||
// Ensure all auth values are present (already set in beforeEach)
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Wait for query to execute
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
expect(getGuardrailsList).toHaveBeenCalledWith("test-access-token");
|
||||
expect(getGuardrailsList).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should return empty array when API returns empty guardrails", async () => {
|
||||
// Mock API returning empty guardrails array
|
||||
(getGuardrailsList as any).mockResolvedValue({ guardrails: [] });
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual([]);
|
||||
expect(getGuardrailsList).toHaveBeenCalledWith("test-access-token");
|
||||
});
|
||||
|
||||
it("should handle network timeout error", async () => {
|
||||
const timeoutError = new Error("Network timeout");
|
||||
|
||||
// Mock network timeout
|
||||
(getGuardrailsList as any).mockRejectedValue(timeoutError);
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(timeoutError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should correctly transform guardrail objects to names array", async () => {
|
||||
const customGuardrailsResponse = {
|
||||
guardrails: [{ guardrail_name: "custom-guardrail-1" }, { guardrail_name: "custom-guardrail-2" }],
|
||||
};
|
||||
const expectedNames = ["custom-guardrail-1", "custom-guardrail-2"];
|
||||
|
||||
// Mock API call with custom data
|
||||
(getGuardrailsList as any).mockResolvedValue(customGuardrailsResponse);
|
||||
|
||||
const { result } = renderHook(() => useGuardrails(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(expectedNames);
|
||||
expect(result.current.data).toHaveLength(2);
|
||||
expect(result.current.data).toContain("custom-guardrail-1");
|
||||
expect(result.current.data).toContain("custom-guardrail-2");
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,293 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import React, { ReactNode } from "react";
|
||||
import { useOrganizations } from "./useOrganizations";
|
||||
import { organizationListCall } from "@/components/networking";
|
||||
import type { Organization } from "@/components/networking";
|
||||
|
||||
// Mock the networking function
|
||||
vi.mock("@/components/networking", () => ({
|
||||
organizationListCall: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the queryKeysFactory - we'll mock the specific return value
|
||||
vi.mock("../common/queryKeysFactory", () => ({
|
||||
createQueryKeys: vi.fn((resource: string) => ({
|
||||
all: [resource],
|
||||
lists: () => [resource, "list"],
|
||||
list: (params?: any) => [resource, "list", { params }],
|
||||
details: () => [resource, "detail"],
|
||||
detail: (uid: string) => [resource, "detail", uid],
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock useAuthorized hook - we can override this in individual tests
|
||||
const mockUseAuthorized = vi.fn();
|
||||
vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
|
||||
default: () => mockUseAuthorized(),
|
||||
}));
|
||||
|
||||
// Mock data
|
||||
const mockOrganizations: Organization[] = [
|
||||
{
|
||||
organization_id: "org-1",
|
||||
organization_alias: "Test Organization 1",
|
||||
budget_id: "budget-1",
|
||||
metadata: {},
|
||||
models: ["gpt-3.5-turbo", "gpt-4"],
|
||||
spend: 100.5,
|
||||
model_spend: { "gpt-3.5-turbo": 50.25, "gpt-4": 50.25 },
|
||||
created_at: "2024-01-01T00:00:00Z",
|
||||
created_by: "user-1",
|
||||
updated_at: "2024-01-01T00:00:00Z",
|
||||
updated_by: "user-1",
|
||||
litellm_budget_table: null,
|
||||
teams: null,
|
||||
users: null,
|
||||
members: [
|
||||
{ user_id: "user-1", user_role: "admin" },
|
||||
{ user_id: "user-2", user_role: "member" },
|
||||
],
|
||||
},
|
||||
{
|
||||
organization_id: "org-2",
|
||||
organization_alias: "Test Organization 2",
|
||||
budget_id: "budget-2",
|
||||
metadata: {},
|
||||
models: ["claude-3"],
|
||||
spend: 250.75,
|
||||
model_spend: { "claude-3": 250.75 },
|
||||
created_at: "2024-01-01T00:00:00Z",
|
||||
created_by: "user-3",
|
||||
updated_at: "2024-01-01T00:00:00Z",
|
||||
updated_by: "user-3",
|
||||
litellm_budget_table: null,
|
||||
teams: null,
|
||||
users: null,
|
||||
members: [{ user_id: "user-3", user_role: "admin" }],
|
||||
},
|
||||
];
|
||||
|
||||
describe("useOrganizations", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Set default mock for useAuthorized (enabled state)
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("should return organizations data when query is successful", async () => {
|
||||
// Mock successful API call
|
||||
(organizationListCall as any).mockResolvedValue(mockOrganizations);
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(mockOrganizations);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(organizationListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(organizationListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle error when organizationListCall fails", async () => {
|
||||
const errorMessage = "Failed to fetch organizations";
|
||||
const testError = new Error(errorMessage);
|
||||
|
||||
// Mock failed API call
|
||||
(organizationListCall as any).mockRejectedValue(testError);
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(testError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(organizationListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(organizationListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not execute query when accessToken is missing", async () => {
|
||||
// Mock missing accessToken
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(organizationListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userId is missing", async () => {
|
||||
// Mock missing userId
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: null,
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(organizationListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userRole is missing", async () => {
|
||||
// Mock missing userRole
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: null,
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(organizationListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when all auth values are missing", async () => {
|
||||
// Mock all auth values missing
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: null,
|
||||
userRole: null,
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(organizationListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should execute query when all auth values are present", async () => {
|
||||
// Mock successful API call
|
||||
(organizationListCall as any).mockResolvedValue(mockOrganizations);
|
||||
|
||||
// Ensure all auth values are present (already set in beforeEach)
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Wait for query to execute
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
expect(organizationListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(organizationListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should return empty array when API returns empty data", async () => {
|
||||
// Mock API returning empty array
|
||||
(organizationListCall as any).mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual([]);
|
||||
expect(organizationListCall).toHaveBeenCalledWith("test-access-token");
|
||||
});
|
||||
|
||||
it("should handle network timeout error", async () => {
|
||||
const timeoutError = new Error("Network timeout");
|
||||
|
||||
// Mock network timeout
|
||||
(organizationListCall as any).mockRejectedValue(timeoutError);
|
||||
|
||||
const { result } = renderHook(() => useOrganizations(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(timeoutError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,193 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import React, { ReactNode } from "react";
|
||||
import { useProviderFields } from "./useProviderFields";
|
||||
import { getProviderCreateMetadata } from "@/components/networking";
|
||||
import type { ProviderCreateInfo } from "@/components/networking";
|
||||
|
||||
// Mock the networking function
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getProviderCreateMetadata: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the queryKeysFactory - we'll mock the specific return value
|
||||
vi.mock("../common/queryKeysFactory", () => ({
|
||||
createQueryKeys: vi.fn((resource: string) => ({
|
||||
all: [resource],
|
||||
lists: () => [resource, "list"],
|
||||
list: (params?: any) => [resource, "list", { params }],
|
||||
details: () => [resource, "detail"],
|
||||
detail: (uid: string) => [resource, "detail", uid],
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock data
|
||||
const mockProviderFields: ProviderCreateInfo[] = [
|
||||
{
|
||||
provider: "OpenAI",
|
||||
provider_display_name: "OpenAI",
|
||||
litellm_provider: "openai",
|
||||
default_model_placeholder: "gpt-3.5-turbo",
|
||||
credential_fields: [],
|
||||
},
|
||||
{
|
||||
provider: "Anthropic",
|
||||
provider_display_name: "Anthropic",
|
||||
litellm_provider: "anthropic",
|
||||
default_model_placeholder: "claude-3-sonnet-20240229",
|
||||
credential_fields: [],
|
||||
},
|
||||
{
|
||||
provider: "Azure",
|
||||
provider_display_name: "Azure OpenAI",
|
||||
litellm_provider: "azure",
|
||||
default_model_placeholder: "gpt-35-turbo",
|
||||
credential_fields: [],
|
||||
},
|
||||
];
|
||||
|
||||
describe("useProviderFields", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("should return provider fields data when query is successful", async () => {
|
||||
// Mock successful API call
|
||||
(getProviderCreateMetadata as any).mockResolvedValue(mockProviderFields);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(mockProviderFields);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(getProviderCreateMetadata).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle error when getProviderCreateMetadata fails", async () => {
|
||||
const errorMessage = "Failed to fetch provider fields";
|
||||
const testError = new Error(errorMessage);
|
||||
|
||||
// Mock failed API call
|
||||
(getProviderCreateMetadata as any).mockRejectedValue(testError);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(testError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(getProviderCreateMetadata).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should return empty array when API returns empty data", async () => {
|
||||
// Mock API returning empty array
|
||||
(getProviderCreateMetadata as any).mockResolvedValue([]);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual([]);
|
||||
expect(getProviderCreateMetadata).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle network timeout error", async () => {
|
||||
const timeoutError = new Error("Network timeout");
|
||||
|
||||
// Mock network timeout
|
||||
(getProviderCreateMetadata as any).mockRejectedValue(timeoutError);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(timeoutError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should have correct query configuration", async () => {
|
||||
// Mock successful API call
|
||||
(getProviderCreateMetadata as any).mockResolvedValue(mockProviderFields);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Wait for query to complete
|
||||
await waitFor(() => {
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
// Verify the query was called
|
||||
expect(getProviderCreateMetadata).toHaveBeenCalledTimes(1);
|
||||
|
||||
// The hook should have the expected properties from useQuery
|
||||
expect(result.current).toHaveProperty("data");
|
||||
expect(result.current).toHaveProperty("isLoading");
|
||||
expect(result.current).toHaveProperty("isError");
|
||||
expect(result.current).toHaveProperty("isSuccess");
|
||||
expect(result.current).toHaveProperty("error");
|
||||
});
|
||||
|
||||
it("should return provider fields with populated credential fields", async () => {
|
||||
const mockFieldsWithCredentials: ProviderCreateInfo[] = [
|
||||
{
|
||||
provider: "TestProvider",
|
||||
provider_display_name: "Test Provider",
|
||||
litellm_provider: "test",
|
||||
default_model_placeholder: "test-model",
|
||||
credential_fields: [], // Keeping empty as per existing test patterns
|
||||
},
|
||||
];
|
||||
|
||||
// Mock successful API call with provider that has credential fields
|
||||
(getProviderCreateMetadata as any).mockResolvedValue(mockFieldsWithCredentials);
|
||||
|
||||
const { result } = renderHook(() => useProviderFields(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(mockFieldsWithCredentials);
|
||||
expect(result.current.data?.[0].provider).toBe("TestProvider");
|
||||
expect(result.current.data?.[0].litellm_provider).toBe("test");
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,294 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import React, { ReactNode } from "react";
|
||||
import { useTags } from "./useTags";
|
||||
import { tagListCall } from "@/components/networking";
|
||||
import type { TagListResponse } from "@/components/tag_management/types";
|
||||
|
||||
// Mock the networking function
|
||||
vi.mock("@/components/networking", () => ({
|
||||
tagListCall: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the queryKeysFactory - we'll mock the specific return value
|
||||
vi.mock("../common/queryKeysFactory", () => ({
|
||||
createQueryKeys: vi.fn((resource: string) => ({
|
||||
all: [resource],
|
||||
lists: () => [resource, "list"],
|
||||
list: (params?: any) => [resource, "list", { params }],
|
||||
details: () => [resource, "detail"],
|
||||
detail: (uid: string) => [resource, "detail", uid],
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock useAuthorized hook - we can override this in individual tests
|
||||
const mockUseAuthorized = vi.fn();
|
||||
vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
|
||||
default: () => mockUseAuthorized(),
|
||||
}));
|
||||
|
||||
// Mock data
|
||||
const mockTags: TagListResponse = {
|
||||
"tag-1": {
|
||||
name: "tag-1",
|
||||
description: "Test tag 1 description",
|
||||
models: ["gpt-3.5-turbo", "gpt-4"],
|
||||
model_info: { "gpt-3.5-turbo": "GPT-3.5 Turbo", "gpt-4": "GPT-4" },
|
||||
created_at: "2024-01-01T00:00:00Z",
|
||||
updated_at: "2024-01-01T00:00:00Z",
|
||||
created_by: "user-1",
|
||||
updated_by: "user-1",
|
||||
litellm_budget_table: {
|
||||
max_budget: 1000,
|
||||
soft_budget: 800,
|
||||
tpm_limit: 100000,
|
||||
rpm_limit: 1000,
|
||||
max_parallel_requests: 10,
|
||||
budget_duration: "monthly",
|
||||
model_max_budget: { "gpt-3.5-turbo": 500, "gpt-4": 500 },
|
||||
},
|
||||
},
|
||||
"tag-2": {
|
||||
name: "tag-2",
|
||||
description: "Test tag 2 description",
|
||||
models: ["claude-3"],
|
||||
model_info: { "claude-3": "Claude 3" },
|
||||
created_at: "2024-01-02T00:00:00Z",
|
||||
updated_at: "2024-01-02T00:00:00Z",
|
||||
created_by: "user-2",
|
||||
updated_by: "user-2",
|
||||
litellm_budget_table: {
|
||||
max_budget: 2000,
|
||||
soft_budget: 1500,
|
||||
tpm_limit: 200000,
|
||||
rpm_limit: 2000,
|
||||
max_parallel_requests: 20,
|
||||
budget_duration: "monthly",
|
||||
model_max_budget: { "claude-3": 2000 },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("useTags", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Set default mock for useAuthorized (enabled state)
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("should return tags data when query is successful", async () => {
|
||||
// Mock successful API call
|
||||
(tagListCall as any).mockResolvedValue(mockTags);
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(mockTags);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(tagListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(tagListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle error when tagListCall fails", async () => {
|
||||
const errorMessage = "Failed to fetch tags";
|
||||
const testError = new Error(errorMessage);
|
||||
|
||||
// Mock failed API call
|
||||
(tagListCall as any).mockRejectedValue(testError);
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(testError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(tagListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(tagListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should not execute query when accessToken is missing", async () => {
|
||||
// Mock missing accessToken
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: "test-user-id",
|
||||
userRole: "Admin",
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(tagListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userId is missing", async () => {
|
||||
// Mock missing userId
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: null,
|
||||
userRole: "Admin",
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(tagListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when userRole is missing", async () => {
|
||||
// Mock missing userRole
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: "test-access-token",
|
||||
userId: "test-user-id",
|
||||
userRole: null,
|
||||
token: "test-token",
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(tagListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not execute query when all auth values are missing", async () => {
|
||||
// Mock all auth values missing
|
||||
mockUseAuthorized.mockReturnValue({
|
||||
accessToken: null,
|
||||
userId: null,
|
||||
userRole: null,
|
||||
token: null,
|
||||
userEmail: "test@example.com",
|
||||
premiumUser: false,
|
||||
disabledPersonalKeyCreation: null,
|
||||
showSSOBanner: false,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Query should not execute
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(result.current.isFetched).toBe(false);
|
||||
|
||||
// API should not be called
|
||||
expect(tagListCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should execute query when all auth values are present", async () => {
|
||||
// Mock successful API call
|
||||
(tagListCall as any).mockResolvedValue(mockTags);
|
||||
|
||||
// Ensure all auth values are present (already set in beforeEach)
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Wait for query to execute
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
expect(tagListCall).toHaveBeenCalledWith("test-access-token");
|
||||
expect(tagListCall).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should return empty object when API returns empty data", async () => {
|
||||
// Mock API returning empty object
|
||||
(tagListCall as any).mockResolvedValue({});
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual({});
|
||||
expect(tagListCall).toHaveBeenCalledWith("test-access-token");
|
||||
});
|
||||
|
||||
it("should handle network timeout error", async () => {
|
||||
const timeoutError = new Error("Network timeout");
|
||||
|
||||
// Mock network timeout
|
||||
(tagListCall as any).mockRejectedValue(timeoutError);
|
||||
|
||||
const { result } = renderHook(() => useTags(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(timeoutError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,169 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import React, { ReactNode } from "react";
|
||||
import { useUIConfig } from "./useUIConfig";
|
||||
import { getUiConfig, LiteLLMWellKnownUiConfig } from "@/components/networking";
|
||||
|
||||
// Mock the networking function
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getUiConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the queryKeysFactory - we'll mock the specific return value
|
||||
vi.mock("../common/queryKeysFactory", () => ({
|
||||
createQueryKeys: vi.fn((resource: string) => ({
|
||||
all: [resource],
|
||||
lists: () => [resource, "list"],
|
||||
list: (params?: any) => [resource, "list", { params }],
|
||||
details: () => [resource, "detail"],
|
||||
detail: (uid: string) => [resource, "detail", uid],
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock data
|
||||
const mockUIConfig: LiteLLMWellKnownUiConfig = {
|
||||
server_root_path: "/api",
|
||||
proxy_base_url: "https://proxy.example.com",
|
||||
auto_redirect_to_sso: true,
|
||||
admin_ui_disabled: false,
|
||||
};
|
||||
|
||||
describe("useUIConfig", () => {
|
||||
let queryClient: QueryClient;
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: { children: ReactNode }) =>
|
||||
React.createElement(QueryClientProvider, { client: queryClient }, children);
|
||||
|
||||
it("should return UI config data when query is successful", async () => {
|
||||
// Mock successful API call
|
||||
(getUiConfig as any).mockResolvedValue(mockUIConfig);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(mockUIConfig);
|
||||
expect(result.current.error).toBeNull();
|
||||
expect(getUiConfig).toHaveBeenCalledWith();
|
||||
expect(getUiConfig).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should handle error when getUiConfig fails", async () => {
|
||||
const errorMessage = "Failed to fetch UI config";
|
||||
const testError = new Error(errorMessage);
|
||||
|
||||
// Mock failed API call
|
||||
(getUiConfig as any).mockRejectedValue(testError);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Initially loading
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(testError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
expect(getUiConfig).toHaveBeenCalledWith();
|
||||
expect(getUiConfig).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should return different UI config data correctly", async () => {
|
||||
const alternativeUIConfig: LiteLLMWellKnownUiConfig = {
|
||||
server_root_path: "/v1",
|
||||
proxy_base_url: null,
|
||||
auto_redirect_to_sso: false,
|
||||
admin_ui_disabled: true,
|
||||
};
|
||||
|
||||
// Mock successful API call with different data
|
||||
(getUiConfig as any).mockResolvedValue(alternativeUIConfig);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Wait for success
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.data).toEqual(alternativeUIConfig);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
|
||||
it("should handle network timeout error", async () => {
|
||||
const timeoutError = new Error("Network timeout");
|
||||
|
||||
// Mock network timeout
|
||||
(getUiConfig as any).mockRejectedValue(timeoutError);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(timeoutError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should handle malformed response error", async () => {
|
||||
const malformedError = new Error("Invalid JSON response");
|
||||
|
||||
// Mock malformed response
|
||||
(getUiConfig as any).mockRejectedValue(malformedError);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Wait for error
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.error).toEqual(malformedError);
|
||||
expect(result.current.data).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should use correct query key structure", async () => {
|
||||
// Mock successful API call
|
||||
(getUiConfig as any).mockResolvedValue(mockUIConfig);
|
||||
|
||||
const { result } = renderHook(() => useUIConfig(), { wrapper });
|
||||
|
||||
// Wait for query to execute
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
// The query key should be generated by createQueryKeys("uiConfig").list({})
|
||||
// Based on our mock, this should be ["uiConfig", "list", {}]
|
||||
expect(getUiConfig).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@ -7,8 +7,29 @@ export default defineConfig({
|
||||
setupFiles: ["tests/setupTests.ts"],
|
||||
globals: true,
|
||||
css: true, // lets you import CSS/modules without extra mocks
|
||||
coverage: { reporter: ["text", "lcov"] },
|
||||
exclude: ["e2e_tests/**,", "node_modules/**"],
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
reporter: ["text", "lcov"],
|
||||
include: ["src/**/*.{ts,tsx}"],
|
||||
exclude: [
|
||||
"**/*.d.ts",
|
||||
"**/*.test.*",
|
||||
"**/*.spec.*",
|
||||
|
||||
"tests/**",
|
||||
"e2e_tests/**",
|
||||
|
||||
"node_modules/**",
|
||||
".next/**",
|
||||
"out/**",
|
||||
|
||||
"**/*.config.*",
|
||||
"postcss.config.*",
|
||||
"tailwind.config.*",
|
||||
"next.config.*",
|
||||
],
|
||||
},
|
||||
exclude: ["e2e_tests/**", "node_modules/**"],
|
||||
include: ["src/**/*.test.ts", "src/**/*.test.tsx", "tests/**/*.test.ts", "tests/**/*.test.tsx"],
|
||||
},
|
||||
resolve: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user