refactor(frontend): remove store.ts file (#11119)

Co-authored-by: sp.wack <83104063+amanape@users.noreply.github.com>
This commit is contained in:
Hiep Le 2025-09-26 10:03:18 +07:00 committed by GitHub
parent b883fe37e6
commit 8a7a5cce5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 66 additions and 287 deletions

View File

@ -61,38 +61,6 @@ vi.mock("#/hooks/use-conversation-name-context-menu", () => ({
}),
}));
vi.mock("react-redux", async () => {
const actual = await vi.importActual("react-redux");
return {
...actual,
useSelector: vi.fn((selector) => {
// Create a mock state object
const mockState = {
agent: {
curAgentState: "AWAITING_USER_INPUT",
},
initialQuery: {
selectedRepository: null,
replayJson: null,
},
conversation: {
messageToSend: null,
files: [],
images: [],
loadingFiles: [],
loadingImages: [],
},
status: {
curStatusMessage: null,
},
};
// Execute the selector function with our mock state
return selector(mockState);
}),
useDispatch: vi.fn(() => vi.fn()),
};
});
// Helper function to render with Router context
const renderChatInterfaceWithRouter = () =>

View File

@ -3,7 +3,7 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import userEvent from "@testing-library/user-event";
import { createRoutesStub } from "react-router";
import React from "react";
import { renderWithQueryAndI18n } from "test-utils";
import { renderWithProviders } from "test-utils";
import { ConversationPanel } from "#/components/features/conversation-panel/conversation-panel";
import ConversationService from "#/api/conversation-service/conversation-service.api";
import { Conversation } from "#/api/open-hands.types";
@ -17,7 +17,7 @@ describe("ConversationPanel", () => {
},
]);
const renderConversationPanel = () => renderWithQueryAndI18n(<RouterStub />);
const renderConversationPanel = () => renderWithProviders(<RouterStub />);
beforeAll(() => {
vi.mock("react-router", async (importOriginal) => ({
@ -287,7 +287,7 @@ describe("ConversationPanel", () => {
},
]);
renderWithQueryAndI18n(<MyRouterStub />);
renderWithProviders(<MyRouterStub />);
const toggleButton = screen.getByText("Toggle");

View File

@ -1,7 +1,7 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, describe, expect, it, vi } from "vitest";
import { renderWithQueryAndI18n } from "test-utils";
import { renderWithProviders } from "test-utils";
import { ServerStatus } from "#/components/features/controls/server-status";
import { ServerStatusContextMenu } from "#/components/features/controls/server-status-context-menu";
import { ConversationStatus } from "#/types/conversation-status";
@ -84,7 +84,7 @@ describe("ServerStatus", () => {
mockAgentStore(AgentState.RUNNING);
// Test RUNNING status
const { rerender } = renderWithQueryAndI18n(
const { rerender } = renderWithProviders(
<ServerStatus conversationStatus="RUNNING" />,
);
expect(screen.getByText("Running")).toBeInTheDocument();
@ -108,7 +108,7 @@ describe("ServerStatus", () => {
// Mock agent store to return RUNNING state
mockAgentStore(AgentState.RUNNING);
renderWithQueryAndI18n(<ServerStatus conversationStatus="RUNNING" />);
renderWithProviders(<ServerStatus conversationStatus="RUNNING" />);
const statusContainer = screen.getByText("Running").closest("div");
expect(statusContainer).toBeInTheDocument();
@ -128,7 +128,7 @@ describe("ServerStatus", () => {
// Mock agent store to return STOPPED state
mockAgentStore(AgentState.STOPPED);
renderWithQueryAndI18n(<ServerStatus conversationStatus="STOPPED" />);
renderWithProviders(<ServerStatus conversationStatus="STOPPED" />);
const statusContainer = screen.getByText("Server Stopped").closest("div");
expect(statusContainer).toBeInTheDocument();
@ -148,7 +148,7 @@ describe("ServerStatus", () => {
// Mock agent store to return RUNNING state
mockAgentStore(AgentState.RUNNING);
renderWithQueryAndI18n(<ServerStatus conversationStatus="STARTING" />);
renderWithProviders(<ServerStatus conversationStatus="STARTING" />);
const statusContainer = screen.getByText("Running").closest("div");
expect(statusContainer).toBeInTheDocument();
@ -170,7 +170,7 @@ describe("ServerStatus", () => {
// Mock agent store to return RUNNING state
mockAgentStore(AgentState.RUNNING);
renderWithQueryAndI18n(<ServerStatus conversationStatus="RUNNING" />);
renderWithProviders(<ServerStatus conversationStatus="RUNNING" />);
const statusContainer = screen.getByText("Running").closest("div");
await user.click(statusContainer!);
@ -192,7 +192,7 @@ describe("ServerStatus", () => {
// Mock agent store to return STOPPED state
mockAgentStore(AgentState.STOPPED);
renderWithQueryAndI18n(<ServerStatus conversationStatus="STOPPED" />);
renderWithProviders(<ServerStatus conversationStatus="STOPPED" />);
const statusContainer = screen.getByText("Server Stopped").closest("div");
await user.click(statusContainer!);
@ -212,7 +212,7 @@ describe("ServerStatus", () => {
// Mock agent store to return RUNNING state
mockAgentStore(AgentState.RUNNING);
renderWithQueryAndI18n(<ServerStatus conversationStatus="RUNNING" />);
renderWithProviders(<ServerStatus conversationStatus="RUNNING" />);
const statusContainer = screen.getByText("Running").closest("div");
await user.click(statusContainer!);
@ -232,7 +232,7 @@ describe("ServerStatus", () => {
// Mock agent store to return STOPPED state
mockAgentStore(AgentState.STOPPED);
renderWithQueryAndI18n(<ServerStatus conversationStatus="STOPPED" />);
renderWithProviders(<ServerStatus conversationStatus="STOPPED" />);
const statusContainer = screen.getByText("Server Stopped").closest("div");
await user.click(statusContainer!);
@ -250,7 +250,7 @@ describe("ServerStatus", () => {
// Mock agent store to return RUNNING state
mockAgentStore(AgentState.RUNNING);
renderWithQueryAndI18n(<ServerStatus conversationStatus={null} />);
renderWithProviders(<ServerStatus conversationStatus={null} />);
const statusText = screen.getByText("Running");
expect(statusText).toBeInTheDocument();
@ -268,7 +268,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should render stop server button when status is RUNNING", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="RUNNING"
@ -281,7 +281,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should render start server button when status is STOPPED", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="STOPPED"
@ -294,7 +294,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should not render stop server button when onStopServer is not provided", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="RUNNING"
@ -305,7 +305,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should not render start server button when onStartServer is not provided", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="STOPPED"
@ -319,7 +319,7 @@ describe("ServerStatusContextMenu", () => {
const user = userEvent.setup();
const onStopServer = vi.fn();
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="RUNNING"
@ -337,7 +337,7 @@ describe("ServerStatusContextMenu", () => {
const user = userEvent.setup();
const onStartServer = vi.fn();
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="STOPPED"
@ -352,7 +352,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should render correct text content for stop server button", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="RUNNING"
@ -366,7 +366,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should render correct text content for start server button", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="STOPPED"
@ -382,7 +382,7 @@ describe("ServerStatusContextMenu", () => {
it("should call onClose when context menu is closed", () => {
const onClose = vi.fn();
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
onClose={onClose}
@ -397,7 +397,7 @@ describe("ServerStatusContextMenu", () => {
});
it("should not render any buttons for other conversation statuses", () => {
renderWithQueryAndI18n(
renderWithProviders(
<ServerStatusContextMenu
{...defaultProps}
conversationStatus="STARTING"

View File

@ -1,7 +1,5 @@
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import { setupStore } from "test-utils";
import { describe, expect, it, vi } from "vitest";
import { HomeHeader } from "#/components/features/home/home-header/home-header";
@ -26,11 +24,9 @@ vi.mock("react-i18next", async () => {
const renderHomeHeader = () => {
return render(<HomeHeader />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});
};

View File

@ -1,8 +1,6 @@
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import { createRoutesStub } from "react-router";
import { setupStore } from "test-utils";
import { describe, expect, it, vi } from "vitest";
import userEvent from "@testing-library/user-event";
import ConversationService from "#/api/conversation-service/conversation-service.api";
@ -43,11 +41,9 @@ const renderNewConversation = () => {
return render(<RouterStub />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});
};

View File

@ -2,8 +2,6 @@ import { render, screen, waitFor, within } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import userEvent from "@testing-library/user-event";
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { setupStore } from "test-utils";
import { Provider } from "react-redux";
import { createRoutesStub, Outlet } from "react-router";
import SettingsService from "#/settings-service/settings-service.api";
import ConversationService from "#/api/conversation-service/conversation-service.api";
@ -42,11 +40,9 @@ const renderRepoConnector = () => {
return render(<RouterStub />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});
};

View File

@ -2,9 +2,7 @@ import { render, screen } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import userEvent from "@testing-library/user-event";
import { Provider } from "react-redux";
import { createRoutesStub } from "react-router";
import { setupStore } from "test-utils";
import ConversationService from "#/api/conversation-service/conversation-service.api";
import UserService from "#/api/user-service/user-service.api";
import GitService from "#/api/git-service/git-service.api";
@ -41,11 +39,9 @@ const renderTaskCard = (task = MOCK_TASK_1) => {
return render(<RouterStub />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});
};

View File

@ -1,9 +1,7 @@
import { render, screen, waitFor } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Provider } from "react-redux";
import { createRoutesStub } from "react-router";
import { setupStore } from "test-utils";
import { TaskSuggestions } from "#/components/features/home/tasks/task-suggestions";
import { SuggestionsService } from "#/api/suggestions-service/suggestions-service.api";
import { MOCK_TASKS } from "#/mocks/task-suggestions-handlers";
@ -62,11 +60,9 @@ const renderTaskSuggestions = () => {
return render(<RouterStub />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});
};

View File

@ -1,7 +1,7 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderWithQueryAndI18n } from "test-utils";
import { renderWithProviders } from "test-utils";
import { MicroagentsModal } from "#/components/features/conversation-panel/microagents-modal";
import ConversationService from "#/api/conversation-service/conversation-service.api";
import { AgentState } from "#/types/agent-state";
@ -64,7 +64,7 @@ describe("MicroagentsModal - Refresh Button", () => {
describe("Refresh Button Rendering", () => {
it("should render the refresh button with correct text and test ID", async () => {
renderWithQueryAndI18n(<MicroagentsModal {...defaultProps} />);
renderWithProviders(<MicroagentsModal {...defaultProps} />);
// Wait for the component to load and render the refresh button
const refreshButton = await screen.findByTestId("refresh-microagents");
@ -77,7 +77,7 @@ describe("MicroagentsModal - Refresh Button", () => {
it("should call refetch when refresh button is clicked", async () => {
const user = userEvent.setup();
renderWithQueryAndI18n(<MicroagentsModal {...defaultProps} />);
renderWithProviders(<MicroagentsModal {...defaultProps} />);
const refreshSpy = vi.spyOn(ConversationService, "getMicroagents");

View File

@ -3,7 +3,7 @@ import { afterEach } from "node:test";
import { useTerminal } from "#/hooks/use-terminal";
import { Command, useCommandStore } from "#/state/command-store";
import { AgentState } from "#/types/agent-state";
import { renderWithQueryAndI18n } from "../../test-utils";
import { renderWithProviders } from "../../test-utils";
import { useAgentStore } from "#/stores/agent-store";
// Mock the WsClient context
@ -60,7 +60,7 @@ describe("useTerminal", () => {
});
it("should render", () => {
renderWithQueryAndI18n(<TestTerminalComponent commands={[]} />);
renderWithProviders(<TestTerminalComponent commands={[]} />);
});
it("should render the commands in the terminal", () => {
@ -69,7 +69,7 @@ describe("useTerminal", () => {
{ content: "hello", type: "output" },
];
renderWithQueryAndI18n(<TestTerminalComponent commands={commands} />);
renderWithProviders(<TestTerminalComponent commands={commands} />);
expect(mockTerminal.writeln).toHaveBeenNthCalledWith(1, "echo hello");
expect(mockTerminal.writeln).toHaveBeenNthCalledWith(2, "hello");
@ -87,7 +87,7 @@ describe("useTerminal", () => {
{ content: secret, type: "output" },
];
renderWithQueryAndI18n(<TestTerminalComponent commands={commands} />);
renderWithProviders(<TestTerminalComponent commands={commands} />);
// This test is no longer relevant as secrets filtering has been removed
});

View File

@ -3,8 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import userEvent from "@testing-library/user-event";
import { createRoutesStub } from "react-router";
import { Provider } from "react-redux";
import { createAxiosNotFoundErrorObject, setupStore } from "test-utils";
import { createAxiosNotFoundErrorObject } from "test-utils";
import HomeScreen from "#/routes/home";
import { GitRepository } from "#/types/git";
import SettingsService from "#/settings-service/settings-service.api";
@ -66,11 +65,9 @@ const selectRepository = async (repoName: string) => {
const renderHomeScreen = () =>
render(<RouterStub />, {
wrapper: ({ children }) => (
<Provider store={setupStore()}>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
</Provider>
<QueryClientProvider client={new QueryClient()}>
{children}
</QueryClientProvider>
),
});

View File

@ -15,7 +15,6 @@
"@react-router/node": "^7.9.1",
"@react-router/serve": "^7.9.1",
"@react-types/shared": "^3.32.0",
"@reduxjs/toolkit": "^2.9.0",
"@stripe/react-stripe-js": "^4.0.2",
"@stripe/stripe-js": "^7.9.0",
"@tailwindcss/postcss": "^4.1.13",
@ -47,7 +46,6 @@
"react-i18next": "^15.7.2",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-redux": "^9.2.0",
"react-router": "^7.9.1",
"react-syntax-highlighter": "^15.6.6",
"remark-breaks": "^4.0.0",
@ -4977,32 +4975,6 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/@reduxjs/toolkit": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.0.tgz",
"integrity": "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==",
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"@standard-schema/utils": "^0.3.0",
"immer": "^10.0.3",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"reselect": "^5.1.0"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.35",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz",
@ -5337,18 +5309,6 @@
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@standard-schema/spec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
"license": "MIT"
},
"node_modules/@standard-schema/utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
"integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
"license": "MIT"
},
"node_modules/@stripe/react-stripe-js": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-4.0.2.tgz",
@ -6350,12 +6310,6 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
"license": "MIT"
},
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
@ -10830,6 +10784,8 @@
"resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz",
"integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==",
"license": "MIT",
"optional": true,
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
@ -14754,29 +14710,6 @@
"react": ">=18"
}
},
"node_modules/react-redux": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
},
"peerDependencies": {
"@types/react": "^18.2.25 || ^19",
"react": "^18.0 || ^19",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@ -14879,21 +14812,6 @@
"node": ">=8"
}
},
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
},
"node_modules/redux-thunk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
"license": "MIT",
"peerDependencies": {
"redux": "^5.0.0"
}
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@ -15164,12 +15082,6 @@
"node": ">=0.10.5"
}
},
"node_modules/reselect": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
"license": "MIT"
},
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",

View File

@ -14,7 +14,6 @@
"@react-router/node": "^7.9.1",
"@react-router/serve": "^7.9.1",
"@react-types/shared": "^3.32.0",
"@reduxjs/toolkit": "^2.9.0",
"@stripe/react-stripe-js": "^4.0.2",
"@stripe/stripe-js": "^7.9.0",
"@tailwindcss/postcss": "^4.1.13",
@ -46,7 +45,6 @@
"react-i18next": "^15.7.2",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-redux": "^9.2.0",
"react-router": "^7.9.1",
"react-syntax-highlighter": "^15.6.6",
"remark-breaks": "^4.0.0",

View File

@ -1,4 +1,3 @@
import { PayloadAction } from "@reduxjs/toolkit";
import { useEffect, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import Markdown from "react-markdown";
@ -30,8 +29,8 @@ interface ExpandableMessageProps {
message: string;
type: string;
success?: boolean;
observation?: PayloadAction<OpenHandsObservation>;
action?: PayloadAction<OpenHandsAction>;
observation?: { payload: OpenHandsObservation };
action?: { payload: OpenHandsAction };
}
export function ExpandableMessage({

View File

@ -8,11 +8,9 @@
import { HydratedRouter } from "react-router/dom";
import React, { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { Provider } from "react-redux";
import posthog from "posthog-js";
import "./i18n";
import { QueryClientProvider } from "@tanstack/react-query";
import store from "./store";
import OptionService from "./api/option-service/option-service.api";
import { displayErrorToast } from "./utils/custom-toast-handlers";
import { queryClient } from "./query-client-config";
@ -63,12 +61,10 @@ prepareApp().then(() =>
hydrateRoot(
document,
<StrictMode>
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<HydratedRouter />
<PosthogInit />
</QueryClientProvider>
</Provider>
<QueryClientProvider client={queryClient}>
<HydratedRouter />
<PosthogInit />
</QueryClientProvider>
<div id="modal-portal-exit" />
</StrictMode>,
);

View File

@ -1,4 +1,3 @@
import { PayloadAction } from "@reduxjs/toolkit";
import { OpenHandsObservation } from "./types/core/observations";
import { OpenHandsAction } from "./types/core/actions";
@ -12,6 +11,6 @@ export type Message = {
pending?: boolean;
translationID?: string;
eventID?: number;
observation?: PayloadAction<OpenHandsObservation>;
action?: PayloadAction<OpenHandsAction>;
observation?: { payload: OpenHandsObservation };
action?: { payload: OpenHandsAction };
};

View File

@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { handleStatusMessage } from "../actions";
import { StatusMessage } from "#/types/message";
import { queryClient } from "#/query-client-config";
import store from "#/store";
import { useStatusStore } from "#/state/status-store";
import { trackError } from "#/utils/error-handler";
@ -13,12 +12,6 @@ vi.mock("#/query-client-config", () => ({
},
}));
vi.mock("#/store", () => ({
default: {
dispatch: vi.fn(),
},
}));
vi.mock("#/state/status-store", () => ({
useStatusStore: {
getState: vi.fn(() => ({
@ -56,9 +49,6 @@ describe("handleStatusMessage", () => {
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
queryKey: ["user", "conversation", "conversation-123"],
});
// Verify that store.dispatch was not called
expect(store.dispatch).not.toHaveBeenCalled();
});
it("should call setCurStatusMessage for info messages without conversation_title", () => {
@ -109,9 +99,6 @@ describe("handleStatusMessage", () => {
metadata: { msgId: "ERROR_ID" },
});
// Verify that store.dispatch was not called
expect(store.dispatch).not.toHaveBeenCalled();
// Verify that queryClient.invalidateQueries was not called
expect(queryClient.invalidateQueries).not.toHaveBeenCalled();
});

View File

@ -1,13 +0,0 @@
import { combineReducers, configureStore } from "@reduxjs/toolkit";
export const rootReducer = combineReducers({});
const store = configureStore({
reducer: rootReducer,
});
export type RootState = ReturnType<typeof store.getState>;
export type AppStore = typeof store;
export type AppDispatch = typeof store.dispatch;
export default store;

View File

@ -1,15 +1,12 @@
// See https://redux.js.org/usage/writing-tests#setting-up-a-reusable-test-render-function for more information
// Test utilities for React components
import React, { PropsWithChildren } from "react";
import { Provider } from "react-redux";
import { configureStore } from "@reduxjs/toolkit";
import { RenderOptions, render } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { I18nextProvider, initReactI18next } from "react-i18next";
import i18n from "i18next";
import { vi } from "vitest";
import { AxiosError } from "axios";
import { AppStore, RootState, rootReducer } from "./src/store";
// Mock useParams before importing components
vi.mock("react-router", async () => {
@ -37,53 +34,14 @@ i18n.use(initReactI18next).init({
},
});
export const setupStore = (preloadedState?: Partial<RootState>): AppStore =>
configureStore({
reducer: rootReducer,
preloadedState,
});
// This type interface extends the default options for render from RTL
interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {}
// This type interface extends the default options for render from RTL, as well
// as allows the user to specify other things such as initialState, store.
interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {
preloadedState?: Partial<RootState>;
store?: AppStore;
}
// Export our own customized renderWithProviders function that creates a new Redux store and renders a <Provider>
// Note that this creates a separate Redux store instance for every test, rather than reusing the same store instance and resetting its state
// Export our own customized renderWithProviders function that renders with QueryClient and i18next providers
// Since we're using Zustand stores, we don't need a Redux Provider wrapper
export function renderWithProviders(
ui: React.ReactElement,
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState),
...renderOptions
}: ExtendedRenderOptions = {},
) {
function Wrapper({ children }: PropsWithChildren) {
return (
<Provider store={store}>
<QueryClientProvider
client={
new QueryClient({
defaultOptions: { queries: { retry: false } },
})
}
>
<I18nextProvider i18n={i18n}>{children}</I18nextProvider>
</QueryClientProvider>
</Provider>
);
}
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
}
// Export a render function for components that only need QueryClient and i18next providers
// (without Redux store)
export function renderWithQueryAndI18n(
ui: React.ReactElement,
renderOptions: Omit<RenderOptions, "wrapper"> = {},
renderOptions: ExtendedRenderOptions = {},
) {
function Wrapper({ children }: PropsWithChildren) {
return (

View File

@ -35,11 +35,9 @@ export default defineConfig(({ mode }) => {
include: [
// Pre-bundle ALL dependencies to prevent runtime optimization and page reloads
// These are discovered during initial app load:
"react-redux",
"posthog-js",
"@tanstack/react-query",
"react-hot-toast",
"@reduxjs/toolkit",
"i18next",
"i18next-http-backend",
"i18next-browser-languagedetector",
@ -62,7 +60,7 @@ export default defineConfig(({ mode }) => {
"react-icons/lu",
"react-icons/di",
"react-icons/io5",
"react-icons/io", // Added to prevent runtime optimization
"react-icons/io", // Added to prevent runtime optimization
"@monaco-editor/react",
"react-textarea-autosize",
"react-markdown",