From b16845fa065cbdd7cb64471e29d51497a54a646a Mon Sep 17 00:00:00 2001 From: Lee Kyeong Joon <165972574+KyeongJooni@users.noreply.github.com> Date: Thu, 11 Dec 2025 23:53:08 +0900 Subject: [PATCH] refactor(frontend): Refactor tests to use Zustand's native state setting instead of vi.mock for stores (#11980) Co-authored-by: amanape <83104063+amanape@users.noreply.github.com> --- .../__tests__/components/browser.test.tsx | 38 +++------------- .../components/chat/chat-interface.test.tsx | 45 +++++++------------ .../components/interactive-chat-box.test.tsx | 35 ++------------- frontend/__tests__/services/actions.test.tsx | 22 ++------- 4 files changed, 28 insertions(+), 112 deletions(-) diff --git a/frontend/__tests__/components/browser.test.tsx b/frontend/__tests__/components/browser.test.tsx index df6aeec640..9466133c34 100644 --- a/frontend/__tests__/components/browser.test.tsx +++ b/frontend/__tests__/components/browser.test.tsx @@ -30,61 +30,33 @@ vi.mock("react-i18next", async () => { }; }); -// Mock Zustand browser store -let mockBrowserState = { - url: "https://example.com", - screenshotSrc: "", - setUrl: vi.fn(), - setScreenshotSrc: vi.fn(), - reset: vi.fn(), -}; - -vi.mock("#/stores/browser-store", () => ({ - useBrowserStore: () => mockBrowserState, -})); - -// Import the component after all mocks are set up import { BrowserPanel } from "#/components/features/browser/browser"; +import { useBrowserStore } from "#/stores/browser-store"; describe("Browser", () => { afterEach(() => { vi.clearAllMocks(); - // Reset the mock state - mockBrowserState = { - url: "https://example.com", - screenshotSrc: "", - setUrl: vi.fn(), - setScreenshotSrc: vi.fn(), - reset: vi.fn(), - }; }); it("renders a message if no screenshotSrc is provided", () => { - // Set the mock state for this test - mockBrowserState = { + useBrowserStore.setState({ url: "https://example.com", screenshotSrc: "", - setUrl: vi.fn(), - setScreenshotSrc: vi.fn(), reset: vi.fn(), - }; + }); render(); - // i18n empty message key expect(screen.getByText("BROWSER$NO_PAGE_LOADED")).toBeInTheDocument(); }); it("renders the url and a screenshot", () => { - // Set the mock state for this test - mockBrowserState = { + useBrowserStore.setState({ url: "https://example.com", screenshotSrc: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN0uGvyHwAFCAJS091fQwAAAABJRU5ErkJggg==", - setUrl: vi.fn(), - setScreenshotSrc: vi.fn(), reset: vi.fn(), - }; + }); render(); diff --git a/frontend/__tests__/components/chat/chat-interface.test.tsx b/frontend/__tests__/components/chat/chat-interface.test.tsx index 9a68eb3805..43da7cfae7 100644 --- a/frontend/__tests__/components/chat/chat-interface.test.tsx +++ b/frontend/__tests__/components/chat/chat-interface.test.tsx @@ -25,10 +25,7 @@ import { useUnifiedUploadFiles } from "#/hooks/mutation/use-unified-upload-files import { OpenHandsAction } from "#/types/core/actions"; import { useEventStore } from "#/stores/use-event-store"; -// Mock the hooks vi.mock("#/context/ws-client-provider"); -vi.mock("#/stores/error-message-store"); -vi.mock("#/stores/optimistic-user-message-store"); vi.mock("#/hooks/query/use-config"); vi.mock("#/hooks/mutation/use-get-trajectory"); vi.mock("#/hooks/mutation/use-unified-upload-files"); @@ -102,24 +99,20 @@ describe("ChatInterface - Chat Suggestions", () => { }, }); - // Default mock implementations (useWsClient as unknown as ReturnType).mockReturnValue({ send: vi.fn(), isLoadingMessages: false, parsedEvents: [], }); - ( - useOptimisticUserMessageStore as unknown as ReturnType - ).mockReturnValue({ - setOptimisticUserMessage: vi.fn(), - getOptimisticUserMessage: vi.fn(() => null), + + useOptimisticUserMessageStore.setState({ + optimisticUserMessage: null, }); - ( - useErrorMessageStore as unknown as ReturnType - ).mockReturnValue({ - setErrorMessage: vi.fn(), - removeErrorMessage: vi.fn(), + + useErrorMessageStore.setState({ + errorMessage: null, }); + (useConfig as unknown as ReturnType).mockReturnValue({ data: { APP_MODE: "local" }, }); @@ -204,11 +197,8 @@ describe("ChatInterface - Chat Suggestions", () => { }); test("should hide chat suggestions when there is an optimistic user message", () => { - ( - useOptimisticUserMessageStore as unknown as ReturnType - ).mockReturnValue({ - setOptimisticUserMessage: vi.fn(), - getOptimisticUserMessage: vi.fn(() => "Optimistic message"), + useOptimisticUserMessageStore.setState({ + optimisticUserMessage: "Optimistic message", }); renderWithQueryClient(, queryClient); @@ -240,24 +230,19 @@ describe("ChatInterface - Empty state", () => { }); beforeEach(() => { - // Reset mocks to ensure empty state (useWsClient as unknown as ReturnType).mockReturnValue({ send: sendMock, status: "CONNECTED", isLoadingMessages: false, parsedEvents: [], }); - ( - useOptimisticUserMessageStore as unknown as ReturnType - ).mockReturnValue({ - setOptimisticUserMessage: vi.fn(), - getOptimisticUserMessage: vi.fn(() => null), + + useOptimisticUserMessageStore.setState({ + optimisticUserMessage: null, }); - ( - useErrorMessageStore as unknown as ReturnType - ).mockReturnValue({ - setErrorMessage: vi.fn(), - removeErrorMessage: vi.fn(), + + useErrorMessageStore.setState({ + errorMessage: null, }); (useConfig as unknown as ReturnType).mockReturnValue({ data: { APP_MODE: "local" }, diff --git a/frontend/__tests__/components/interactive-chat-box.test.tsx b/frontend/__tests__/components/interactive-chat-box.test.tsx index b518580650..34ba1eaafd 100644 --- a/frontend/__tests__/components/interactive-chat-box.test.tsx +++ b/frontend/__tests__/components/interactive-chat-box.test.tsx @@ -8,16 +8,10 @@ import { AgentState } from "#/types/agent-state"; import { useAgentState } from "#/hooks/use-agent-state"; import { useConversationStore } from "#/state/conversation-store"; -// Mock the agent state hook vi.mock("#/hooks/use-agent-state", () => ({ useAgentState: vi.fn(), })); -// Mock the conversation store -vi.mock("#/state/conversation-store", () => ({ - useConversationStore: vi.fn(), -})); - // Mock React Router hooks vi.mock("react-router", async () => { const actual = await vi.importActual("react-router"); @@ -58,44 +52,23 @@ vi.mock("#/hooks/use-conversation-name-context-menu", () => ({ describe("InteractiveChatBox", () => { const onSubmitMock = vi.fn(); - // Helper function to mock stores const mockStores = (agentState: AgentState = AgentState.INIT) => { vi.mocked(useAgentState).mockReturnValue({ curAgentState: agentState, }); - vi.mocked(useConversationStore).mockReturnValue({ + useConversationStore.setState({ images: [], files: [], - addImages: vi.fn(), - addFiles: vi.fn(), - clearAllFiles: vi.fn(), - addFileLoading: vi.fn(), - removeFileLoading: vi.fn(), - addImageLoading: vi.fn(), - removeImageLoading: vi.fn(), - submittedMessage: null, - setShouldHideSuggestions: vi.fn(), - setSubmittedMessage: vi.fn(), - isRightPanelShown: true, - selectedTab: "editor" as const, loadingFiles: [], loadingImages: [], + submittedMessage: null, messageToSend: null, shouldShownAgentLoading: false, shouldHideSuggestions: false, + isRightPanelShown: true, + selectedTab: "editor" as const, hasRightPanelToggled: true, - setIsRightPanelShown: vi.fn(), - setSelectedTab: vi.fn(), - setShouldShownAgentLoading: vi.fn(), - removeImage: vi.fn(), - removeFile: vi.fn(), - clearImages: vi.fn(), - clearFiles: vi.fn(), - clearAllLoading: vi.fn(), - setMessageToSend: vi.fn(), - resetConversationState: vi.fn(), - setHasRightPanelToggled: vi.fn(), }); }; diff --git a/frontend/__tests__/services/actions.test.tsx b/frontend/__tests__/services/actions.test.tsx index 05473dcb35..c6e2ac76e2 100644 --- a/frontend/__tests__/services/actions.test.tsx +++ b/frontend/__tests__/services/actions.test.tsx @@ -1,8 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import ActionType from "#/types/action-type"; import { ActionMessage } from "#/types/message"; +import { useCommandStore } from "#/state/command-store"; -// Mock the store and actions const mockDispatch = vi.fn(); const mockAppendInput = vi.fn(); @@ -12,26 +12,12 @@ vi.mock("#/store", () => ({ }, })); -vi.mock("#/state/command-store", () => ({ - useCommandStore: { - getState: () => ({ - appendInput: mockAppendInput, - }), - }, -})); - -vi.mock("#/state/metrics-slice", () => ({ - setMetrics: vi.fn(), -})); - -vi.mock("#/state/security-analyzer-slice", () => ({ - appendSecurityAnalyzerInput: vi.fn(), -})); - describe("handleActionMessage", () => { beforeEach(() => { - // Clear all mocks before each test vi.clearAllMocks(); + useCommandStore.setState({ + appendInput: mockAppendInput, + }); }); it("should handle RUN actions by adding input to terminal", async () => {