diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.test.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.test.tsx new file mode 100644 index 00000000000..4eea35c8a87 --- /dev/null +++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.test.tsx @@ -0,0 +1,72 @@ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import * as networking from "@/components/networking"; +import { LogViewer } from "./LogViewer"; + +vi.mock("@/components/networking", () => ({ + uiSpendLogsCall: vi.fn(), +})); + +vi.mock("@/components/view_logs/LogDetailsDrawer", () => ({ + LogDetailsDrawer: ({ open, logEntry }: { open: boolean; logEntry: { request_id: string } | null }) => + open && logEntry ?
{logEntry.request_id}
: null, +})); + +const mockUiSpendLogsCall = vi.mocked(networking.uiSpendLogsCall); + +const originalTimezone = process.env.TZ; + +function wrapper({ children }: { children: React.ReactNode }) { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return {children}; +} + +describe("LogViewer", () => { + beforeEach(() => { + // UTC+2: a day window built in the wrong order collapses onto the previous day + process.env.TZ = "Europe/Berlin"; + mockUiSpendLogsCall.mockReset(); + }); + + afterEach(() => { + process.env.TZ = originalTimezone; + }); + + it("should open the drawer for a log on the last day of the range in a UTC+ timezone", async () => { + mockUiSpendLogsCall.mockResolvedValue({ + data: [{ request_id: "req-1" }], + total: 1, + }); + + render( + , + { wrapper }, + ); + + fireEvent.click(screen.getByText("hello")); + + await waitFor(() => expect(mockUiSpendLogsCall).toHaveBeenCalled()); + const { start_date, end_date, params } = mockUiSpendLogsCall.mock.calls[0][0]; + expect(params?.request_id).toBe("req-1"); + expect(Date.parse(`${start_date}Z`)).toBeLessThanOrEqual(Date.parse("2026-07-22T09:38:46Z")); + expect(Date.parse(`${end_date}Z`)).toBeGreaterThanOrEqual(Date.parse("2026-07-22T09:38:46Z")); + + expect(await screen.findByTestId("log-drawer")).toHaveTextContent("req-1"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.tsx index 8d073feae82..ef0f1c19154 100644 --- a/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.tsx +++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/LogViewer.tsx @@ -69,10 +69,10 @@ export function LogViewer({ const filters: Array<"all" | "blocked" | "flagged" | "passed"> = ["all", "blocked", "flagged", "passed"]; const startTime = startDate - ? moment(startDate).utc().format("YYYY-MM-DD HH:mm:ss") + ? moment(startDate).startOf("day").utc().format("YYYY-MM-DD HH:mm:ss") : moment().subtract(24, "hours").utc().format("YYYY-MM-DD HH:mm:ss"); const endTime = endDate - ? moment(endDate).utc().endOf("day").format("YYYY-MM-DD HH:mm:ss") + ? moment(endDate).endOf("day").utc().format("YYYY-MM-DD HH:mm:ss") : moment().utc().format("YYYY-MM-DD HH:mm:ss"); const { data: fullLogResponse } = useQuery({