diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index 9407ff25a1f..ac13a12620d 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -9,8 +9,11 @@ "start": "next start", "lint": "eslint .", "test": "vitest", + "test:unit": "vitest run --project unit", + "test:component": "vitest run --project component", + "test:integration": "vitest run --project integration", "test:dot": "vitest --reporter=dot", - "test:types": "vitest --run --typecheck.only", + "test:types": "vitest run --project types", "test:watch": "vitest -w", "test:coverage": "vitest run --coverage", "format": "prettier --write .", diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_utils.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_utils.test.ts index 3c319e5ba18..25b4da869bb 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_utils.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_utils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { exportMultiToPDF, exportMultiToCSV } from "./multi_export_utils"; import type { MultiModelResult } from "./types"; diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createOAuthUiState.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createOAuthUiState.test.ts index e2e7814f0d7..94544ec6e2d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createOAuthUiState.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/createOAuthUiState.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { beforeEach, describe, expect, it, vi } from "vitest"; import { setSecureItem } from "@/utils/secureStorage"; import { CreateUiSnapshot, readCreateUiSnapshot, writeCreateUiSnapshot } from "./createOAuthUiState"; diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts index d80294aa2e6..7ed014d43b2 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import type { DateRangePickerValue } from "@/components/shared/date_picker_types"; import Papa from "papaparse"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts index cc4fe64e4c8..a38b96e74c2 100644 --- a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { describe, it, expect, beforeEach, vi } from "vitest"; import { clearTokenCookies, getCookie, storeLoginToken } from "./cookieUtils"; import { getToken, setToken } from "./mcpTokenStore"; diff --git a/ui/litellm-dashboard/src/utils/dataUtils.test.ts b/ui/litellm-dashboard/src/utils/dataUtils.test.ts index d975a4a73f4..f696780bc0a 100644 --- a/ui/litellm-dashboard/src/utils/dataUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/dataUtils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { describe, it, expect, beforeEach, vi, afterEach } from "vitest"; import { copyToClipboard, formatNumberWithCommas, getSpendString, updateExistingKeys } from "./dataUtils"; diff --git a/ui/litellm-dashboard/src/utils/localStorageUtils.test.ts b/ui/litellm-dashboard/src/utils/localStorageUtils.test.ts index 934c358cb74..2ef5e1d5b43 100644 --- a/ui/litellm-dashboard/src/utils/localStorageUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/localStorageUtils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { describe, it, expect, vi, beforeEach } from "vitest"; import { emitLocalStorageChange, diff --git a/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts b/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts index 0d096677f0d..e384f41042a 100644 --- a/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts +++ b/ui/litellm-dashboard/src/utils/mcpTokenStore.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { clearAllMcpTokens, getToken, isTokenValid, removeToken, setToken } from "./mcpTokenStore"; diff --git a/ui/litellm-dashboard/src/utils/returnUrlUtils.test.ts b/ui/litellm-dashboard/src/utils/returnUrlUtils.test.ts index 0f3a8b4bf69..3d1e83ad236 100644 --- a/ui/litellm-dashboard/src/utils/returnUrlUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/returnUrlUtils.test.ts @@ -1,3 +1,5 @@ +// @vitest-environment jsdom + import { buildLoginUrlWithReturn, clearStoredReturnUrl, diff --git a/ui/litellm-dashboard/tests/setup.unit.ts b/ui/litellm-dashboard/tests/setup.unit.ts new file mode 100644 index 00000000000..4eb0c473989 --- /dev/null +++ b/ui/litellm-dashboard/tests/setup.unit.ts @@ -0,0 +1,12 @@ +import { vi } from "vitest"; + +vi.mock("@/lib/toast", () => ({ + toast: { + success: vi.fn(), + info: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + fromError: vi.fn(), + dismiss: vi.fn(), + }, +})); diff --git a/ui/litellm-dashboard/vitest.config.ts b/ui/litellm-dashboard/vitest.config.ts index 7d8825909d8..ca2a25cba9f 100644 --- a/ui/litellm-dashboard/vitest.config.ts +++ b/ui/litellm-dashboard/vitest.config.ts @@ -12,17 +12,81 @@ const staticImageData: Plugin = { }, }; -const config: ViteUserConfig = { +const sharedViteConfig = { plugins: [staticImageData], + resolve: { alias: { "@": resolve(__dirname, "src") } }, + define: { "import.meta.vitest": "undefined" }, + esbuild: { jsx: "automatic", jsxImportSource: "react" } as const, +}; + +const TEST_TS_FILES_THAT_RENDER_REACT: readonly string[] = [ + "src/**/hooks/**/*.test.ts", + "src/**/cost-tracking/_components/**/use_*.test.ts", + "src/**/models-and-endpoints/detailNavigation.test.ts", + "src/**/models-and-endpoints/vertexCredentialsUpload.test.ts", + "src/components/chat/useChatHistory.test.ts", + "src/lib/forms/pickDirty.test.ts", +]; + +const jsdomTier = { + environment: "./tests/jsdomFetchEnv.ts", + setupFiles: ["tests/setupTests.ts"], + globals: true, + css: true, + testTimeout: 60_000, + hookTimeout: 30_000, +}; + +const config: ViteUserConfig = { + ...sharedViteConfig, test: { - environment: "./tests/jsdomFetchEnv.ts", - setupFiles: ["tests/setupTests.ts"], - globals: true, - css: true, // lets you import CSS/modules without extra mocks - testTimeout: 60000, - hookTimeout: 30000, + projects: [ + { + ...sharedViteConfig, + test: { + name: "unit", + environment: "node", + setupFiles: ["tests/setup.unit.ts"], + globals: true, + testTimeout: 60_000, + hookTimeout: 30_000, + include: ["src/**/*.test.ts", "tests/**/*.test.ts"], + exclude: ["node_modules/**", ...TEST_TS_FILES_THAT_RENDER_REACT], + }, + }, + { + ...sharedViteConfig, + test: { + ...jsdomTier, + name: "component", + include: ["src/**/*.test.tsx", "tests/**/*.test.tsx", ...TEST_TS_FILES_THAT_RENDER_REACT], + exclude: ["node_modules/**", "**/*.integration.test.tsx"], + }, + }, + { + ...sharedViteConfig, + test: { + ...jsdomTier, + name: "integration", + include: ["src/**/*.integration.test.tsx", "tests/**/*.integration.test.tsx"], + exclude: ["node_modules/**"], + }, + }, + { + ...sharedViteConfig, + test: { + name: "types", + include: [], + typecheck: { + enabled: true, + include: ["src/**/*.test-d.ts", "src/**/*.test-d.tsx"], + ignoreSourceErrors: true, + }, + }, + }, + ], silent: process.env.CI ? "passed-only" : false, - teardownTimeout: 60000, + teardownTimeout: 60_000, coverage: { provider: "v8", reporter: ["text", "lcov"], @@ -32,37 +96,16 @@ const config: ViteUserConfig = { "**/*.test.*", "**/*.test-d.*", "**/*.spec.*", - "tests/**", - "node_modules/**", ".next/**", "out/**", - "**/*.config.*", "postcss.config.*", "tailwind.config.*", "next.config.*", ], }, - exclude: ["node_modules/**"], - include: ["src/**/*.test.ts", "src/**/*.test.tsx", "tests/**/*.test.ts", "tests/**/*.test.tsx"], - typecheck: { - include: ["src/**/*.test-d.ts", "src/**/*.test-d.tsx"], - ignoreSourceErrors: true, - }, - }, - resolve: { - alias: { - "@": resolve(__dirname, "src"), - }, - }, - define: { - "import.meta.vitest": "undefined", - }, - esbuild: { - jsx: "automatic", - jsxImportSource: "react", }, };