mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
test fixes
This commit is contained in:
parent
4b4d658e74
commit
3e98b44d39
2 changed files with 230 additions and 8 deletions
|
|
@ -6,31 +6,34 @@
|
|||
// Page descriptions for UI Settings configuration
|
||||
export const pageDescriptions: Record<string, string> = {
|
||||
"api-keys": "Manage virtual keys for API access and authentication",
|
||||
playground: "Interactive playground for testing LLM requests",
|
||||
"models-and-endpoints": "Configure and manage LLM models and endpoints",
|
||||
"llm-playground": "Interactive playground for testing LLM requests",
|
||||
models: "Configure and manage LLM models and endpoints",
|
||||
agents: "Create and manage AI agents",
|
||||
"mcp-servers": "Configure Model Context Protocol servers",
|
||||
guardrails: "Set up content moderation and safety guardrails",
|
||||
policies: "Define access control and usage policies",
|
||||
"search-tools": "Configure RAG search and retrieval tools",
|
||||
"vector-stores": "Manage vector databases for embeddings",
|
||||
usage: "View usage analytics and metrics",
|
||||
new_usage: "View usage analytics and metrics",
|
||||
logs: "Access request and response logs",
|
||||
"internal-users": "Manage internal user accounts and permissions",
|
||||
users: "Manage internal user accounts and permissions",
|
||||
teams: "Create and manage teams for access control",
|
||||
organizations: "Manage organizations and their members",
|
||||
budgets: "Set and monitor spending budgets",
|
||||
"api-reference": "Browse API documentation and endpoints",
|
||||
"ai-hub": "Explore available AI models and providers",
|
||||
api_ref: "Browse API documentation and endpoints",
|
||||
"model-hub-table": "Explore available AI models and providers",
|
||||
"learning-resources": "Access tutorials and documentation",
|
||||
caching: "Configure response caching settings",
|
||||
"transform-request": "Set up request transformation rules",
|
||||
"pass-through-endpoints": "Configure pass-through API endpoints",
|
||||
"cost-tracking": "Track and analyze API costs",
|
||||
"ui-themes": "Customize dashboard appearance",
|
||||
"ui-theme": "Customize dashboard appearance",
|
||||
"tag-management": "Organize resources with tags",
|
||||
prompts: "Manage and version prompt templates",
|
||||
"claude-code-plugins": "Configure Claude Code plugins",
|
||||
usage: "View legacy usage dashboard",
|
||||
"router-settings": "Configure routing and load balancing settings",
|
||||
"logging-and-alerts": "Set up logging and alert configurations",
|
||||
"admin-panel": "Access admin panel and settings",
|
||||
};
|
||||
|
||||
export interface PageMetadata {
|
||||
|
|
|
|||
219
ui/litellm-dashboard/src/components/page_utils.test.ts
Normal file
219
ui/litellm-dashboard/src/components/page_utils.test.ts
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
/**
|
||||
* Tests to ensure page metadata stays in sync with leftnav configuration
|
||||
* This catches issues when leftnav structure changes but page_utils/page_metadata aren't updated
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getAvailablePages } from "./page_utils";
|
||||
import { menuGroups } from "./leftnav";
|
||||
import { pageDescriptions } from "./page_metadata";
|
||||
|
||||
describe("Page Utils - LeftNav Sync", () => {
|
||||
it("should return all pages from leftnav configuration", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
|
||||
// Should have pages
|
||||
expect(availablePages.length).toBeGreaterThan(0);
|
||||
|
||||
// Each page should have required fields
|
||||
availablePages.forEach((page) => {
|
||||
expect(page).toHaveProperty("page");
|
||||
expect(page).toHaveProperty("label");
|
||||
expect(page).toHaveProperty("group");
|
||||
expect(page).toHaveProperty("description");
|
||||
expect(typeof page.page).toBe("string");
|
||||
expect(typeof page.label).toBe("string");
|
||||
expect(typeof page.group).toBe("string");
|
||||
expect(typeof page.description).toBe("string");
|
||||
});
|
||||
});
|
||||
|
||||
it("should include all navigable pages from menuGroups", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
const availablePageKeys = availablePages.map((p) => p.page);
|
||||
|
||||
// Collect all page keys from menuGroups (excluding parent containers)
|
||||
const menuPageKeys: string[] = [];
|
||||
const excludedParents = ["tools", "experimental", "settings"];
|
||||
|
||||
menuGroups.forEach((group) => {
|
||||
group.items.forEach((item) => {
|
||||
if (item.page && !excludedParents.includes(item.page)) {
|
||||
menuPageKeys.push(item.page);
|
||||
}
|
||||
|
||||
// Add children
|
||||
if (item.children) {
|
||||
item.children.forEach((child) => {
|
||||
menuPageKeys.push(child.page);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Every menu page should be in available pages
|
||||
menuPageKeys.forEach((pageKey) => {
|
||||
expect(
|
||||
availablePageKeys,
|
||||
`Page "${pageKey}" from menuGroups should be in getAvailablePages() output`
|
||||
).toContain(pageKey);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not include parent container pages (tools, experimental, settings)", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
const availablePageKeys = availablePages.map((p) => p.page);
|
||||
|
||||
const excludedParents = ["tools", "experimental", "settings"];
|
||||
|
||||
excludedParents.forEach((parent) => {
|
||||
expect(
|
||||
availablePageKeys,
|
||||
`Parent container "${parent}" should not be in available pages`
|
||||
).not.toContain(parent);
|
||||
});
|
||||
});
|
||||
|
||||
it("should have descriptions for all pages", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
|
||||
availablePages.forEach((page) => {
|
||||
expect(
|
||||
page.description,
|
||||
`Page "${page.page}" should have a description`
|
||||
).toBeTruthy();
|
||||
|
||||
expect(
|
||||
page.description,
|
||||
`Page "${page.page}" should not have placeholder description`
|
||||
).not.toBe("No description available");
|
||||
});
|
||||
});
|
||||
|
||||
it("should have pageDescriptions entry for all navigable pages in menuGroups", () => {
|
||||
// Collect all page keys from menuGroups
|
||||
const menuPageKeys: string[] = [];
|
||||
const excludedParents = ["tools", "experimental", "settings"];
|
||||
|
||||
menuGroups.forEach((group) => {
|
||||
group.items.forEach((item) => {
|
||||
if (item.page && !excludedParents.includes(item.page)) {
|
||||
menuPageKeys.push(item.page);
|
||||
}
|
||||
|
||||
if (item.children) {
|
||||
item.children.forEach((child) => {
|
||||
menuPageKeys.push(child.page);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Every menu page should have a description
|
||||
const missingDescriptions: string[] = [];
|
||||
menuPageKeys.forEach((pageKey) => {
|
||||
if (!pageDescriptions[pageKey]) {
|
||||
missingDescriptions.push(pageKey);
|
||||
}
|
||||
});
|
||||
|
||||
expect(
|
||||
missingDescriptions,
|
||||
`These pages are missing descriptions in page_metadata.ts: ${missingDescriptions.join(", ")}`
|
||||
).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should not have orphaned descriptions (descriptions for pages not in menuGroups)", () => {
|
||||
// Collect all page keys from menuGroups
|
||||
const menuPageKeys: string[] = [];
|
||||
const excludedParents = ["tools", "experimental", "settings"];
|
||||
|
||||
menuGroups.forEach((group) => {
|
||||
group.items.forEach((item) => {
|
||||
if (item.page && !excludedParents.includes(item.page)) {
|
||||
menuPageKeys.push(item.page);
|
||||
}
|
||||
|
||||
if (item.children) {
|
||||
item.children.forEach((child) => {
|
||||
menuPageKeys.push(child.page);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Check for descriptions that don't match any menu page
|
||||
const orphanedDescriptions: string[] = [];
|
||||
Object.keys(pageDescriptions).forEach((descKey) => {
|
||||
if (!menuPageKeys.includes(descKey)) {
|
||||
orphanedDescriptions.push(descKey);
|
||||
}
|
||||
});
|
||||
|
||||
expect(
|
||||
orphanedDescriptions,
|
||||
`These descriptions don't match any page in menuGroups: ${orphanedDescriptions.join(", ")}. Remove them or add the pages to leftnav.`
|
||||
).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should have proper group hierarchy for nested pages", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
|
||||
// Find pages that should be nested (children of Tools, Experimental, Settings)
|
||||
const nestedPages = availablePages.filter((page) =>
|
||||
page.group.includes(" > ")
|
||||
);
|
||||
|
||||
// Each nested page should have parent > child format
|
||||
nestedPages.forEach((page) => {
|
||||
const parts = page.group.split(" > ");
|
||||
expect(
|
||||
parts.length,
|
||||
`Nested page "${page.page}" should have exactly 2 parts in group hierarchy`
|
||||
).toBe(2);
|
||||
|
||||
// Parent should be one of the group labels
|
||||
const parentGroup = parts[0];
|
||||
const groupLabels = menuGroups.map((g) => g.groupLabel);
|
||||
expect(
|
||||
groupLabels,
|
||||
`Parent group "${parentGroup}" for page "${page.page}" should be a valid group label`
|
||||
).toContain(parentGroup);
|
||||
});
|
||||
});
|
||||
|
||||
it("should have unique page keys", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
const pageKeys = availablePages.map((p) => p.page);
|
||||
const uniquePageKeys = new Set(pageKeys);
|
||||
|
||||
expect(
|
||||
pageKeys.length,
|
||||
"All page keys should be unique (no duplicates)"
|
||||
).toBe(uniquePageKeys.size);
|
||||
});
|
||||
|
||||
it("should match the structure expected by PageVisibilitySettings component", () => {
|
||||
const availablePages = getAvailablePages();
|
||||
|
||||
// Group pages by their group (same logic as in PageVisibilitySettings)
|
||||
const grouped: Record<string, typeof availablePages> = {};
|
||||
availablePages.forEach((page) => {
|
||||
if (!grouped[page.group]) {
|
||||
grouped[page.group] = [];
|
||||
}
|
||||
grouped[page.group].push(page);
|
||||
});
|
||||
|
||||
// Should have multiple groups
|
||||
expect(Object.keys(grouped).length).toBeGreaterThan(1);
|
||||
|
||||
// Each group should have at least one page
|
||||
Object.entries(grouped).forEach(([groupName, pages]) => {
|
||||
expect(
|
||||
pages.length,
|
||||
`Group "${groupName}" should have at least one page`
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue