diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/CopilotPage.test.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/CopilotPage.test.tsx new file mode 100644 index 0000000000..71791b5694 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/copilot/__tests__/CopilotPage.test.tsx @@ -0,0 +1,168 @@ +import { render, screen, cleanup } from "@/tests/integrations/test-utils"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { CopilotPage } from "../CopilotPage"; + +// Mock child components that are complex and not under test here +vi.mock("../components/ChatContainer/ChatContainer", () => ({ + ChatContainer: () =>
, +})); +vi.mock("../components/ChatSidebar/ChatSidebar", () => ({ + ChatSidebar: () =>
, +})); +vi.mock("../components/DeleteChatDialog/DeleteChatDialog", () => ({ + DeleteChatDialog: () => null, +})); +vi.mock("../components/MobileDrawer/MobileDrawer", () => ({ + MobileDrawer: () => null, +})); +vi.mock("../components/MobileHeader/MobileHeader", () => ({ + MobileHeader: () => null, +})); +vi.mock("../components/NotificationBanner/NotificationBanner", () => ({ + NotificationBanner: () => null, +})); +vi.mock("../components/NotificationDialog/NotificationDialog", () => ({ + NotificationDialog: () => null, +})); +vi.mock("../components/RateLimitResetDialog/RateLimitResetDialog", () => ({ + RateLimitResetDialog: () => null, +})); +vi.mock("../components/ScaleLoader/ScaleLoader", () => ({ + ScaleLoader: () =>
, +})); +vi.mock("../components/ArtifactPanel/ArtifactPanel", () => ({ + ArtifactPanel: () => null, +})); +vi.mock("@/components/ui/sidebar", () => ({ + SidebarProvider: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), +})); + +// Mock hooks that hit the network +vi.mock("@/app/api/__generated__/endpoints/chat/chat", () => ({ + useGetV2GetCopilotUsage: () => ({ + data: undefined, + isSuccess: false, + isError: false, + }), +})); +vi.mock("@/hooks/useCredits", () => ({ + default: () => ({ credits: null, fetchCredits: vi.fn() }), +})); +vi.mock("@/services/feature-flags/use-get-flag", () => ({ + Flag: { + ENABLE_PLATFORM_PAYMENT: "ENABLE_PLATFORM_PAYMENT", + ARTIFACTS: "ARTIFACTS", + CHAT_MODE_OPTION: "CHAT_MODE_OPTION", + }, + useGetFlag: () => false, +})); + +// Build the base mock return value for useCopilotPage +const basePageState = { + sessionId: null as string | null, + messages: [], + status: "ready" as const, + error: undefined, + stop: vi.fn(), + isReconnecting: false, + isSyncing: false, + createSession: vi.fn(), + onSend: vi.fn(), + isLoadingSession: false, + isSessionError: false, + isCreatingSession: false, + isUploadingFiles: false, + isUserLoading: false, + isLoggedIn: true, + hasMoreMessages: false, + isLoadingMore: false, + loadMore: vi.fn(), + isMobile: false, + isDrawerOpen: false, + sessions: [], + isLoadingSessions: false, + handleOpenDrawer: vi.fn(), + handleCloseDrawer: vi.fn(), + handleDrawerOpenChange: vi.fn(), + handleSelectSession: vi.fn(), + handleNewChat: vi.fn(), + sessionToDelete: null, + isDeleting: false, + handleConfirmDelete: vi.fn(), + handleCancelDelete: vi.fn(), + historicalDurations: {}, + rateLimitMessage: null, + dismissRateLimit: vi.fn(), + isDryRun: false, + sessionDryRun: false, +}; + +const mockUseCopilotPage = vi.fn(() => basePageState); + +vi.mock("../useCopilotPage", () => ({ + useCopilotPage: () => mockUseCopilotPage(), +})); + +afterEach(() => { + cleanup(); + mockUseCopilotPage.mockReset(); + mockUseCopilotPage.mockImplementation(() => basePageState); +}); + +describe("CopilotPage test-mode banner", () => { + it("does not show test-mode banner when there is no active session", () => { + render(); + expect( + screen.queryByText(/test mode.*this session runs agents/i), + ).toBeNull(); + }); + + it("does not show test-mode banner when session exists but sessionDryRun is false", () => { + mockUseCopilotPage.mockReturnValue({ + ...basePageState, + sessionId: "session-abc", + sessionDryRun: false, + }); + render(); + expect( + screen.queryByText(/test mode.*this session runs agents/i), + ).toBeNull(); + }); + + it("shows test-mode banner when session exists and sessionDryRun is true", () => { + mockUseCopilotPage.mockReturnValue({ + ...basePageState, + sessionId: "session-abc", + sessionDryRun: true, + }); + render(); + expect( + screen.getByText(/test mode.*this session runs agents/i), + ).toBeDefined(); + }); + + it("does not show test-mode banner when sessionDryRun is true but no sessionId", () => { + mockUseCopilotPage.mockReturnValue({ + ...basePageState, + sessionId: null, + sessionDryRun: true, + }); + render(); + expect( + screen.queryByText(/test mode.*this session runs agents/i), + ).toBeNull(); + }); + + it("shows loading spinner when user is loading", () => { + mockUseCopilotPage.mockReturnValue({ + ...basePageState, + isUserLoading: true, + isLoggedIn: false, + }); + render(); + expect(screen.getByTestId("scale-loader")).toBeDefined(); + expect(screen.queryByTestId("chat-container")).toBeNull(); + }); +});