test-utils.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // See https://redux.js.org/usage/writing-tests#setting-up-a-reusable-test-render-function for more information
  2. import React, { PropsWithChildren } from "react";
  3. import { Provider } from "react-redux";
  4. import { configureStore } from "@reduxjs/toolkit";
  5. import { RenderOptions, render } from "@testing-library/react";
  6. import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
  7. import { I18nextProvider, initReactI18next } from "react-i18next";
  8. import i18n from "i18next";
  9. import { vi } from "vitest";
  10. import { AppStore, RootState, rootReducer } from "./src/store";
  11. import { AuthProvider } from "#/context/auth-context";
  12. import { SettingsProvider } from "#/context/settings-context";
  13. import { ConversationProvider } from "#/context/conversation-context";
  14. // Mock useParams before importing components
  15. vi.mock("react-router", async () => {
  16. const actual =
  17. await vi.importActual<typeof import("react-router")>("react-router");
  18. return {
  19. ...actual,
  20. useParams: () => ({ conversationId: "test-conversation-id" }),
  21. };
  22. });
  23. // Initialize i18n for tests
  24. i18n.use(initReactI18next).init({
  25. lng: "en",
  26. fallbackLng: "en",
  27. ns: ["translation"],
  28. defaultNS: "translation",
  29. resources: {
  30. en: {
  31. translation: {},
  32. },
  33. },
  34. interpolation: {
  35. escapeValue: false,
  36. },
  37. });
  38. const setupStore = (preloadedState?: Partial<RootState>): AppStore =>
  39. configureStore({
  40. reducer: rootReducer,
  41. preloadedState,
  42. });
  43. // This type interface extends the default options for render from RTL, as well
  44. // as allows the user to specify other things such as initialState, store.
  45. interface ExtendedRenderOptions extends Omit<RenderOptions, "queries"> {
  46. preloadedState?: Partial<RootState>;
  47. store?: AppStore;
  48. }
  49. // Export our own customized renderWithProviders function that creates a new Redux store and renders a <Provider>
  50. // Note that this creates a separate Redux store instance for every test, rather than reusing the same store instance and resetting its state
  51. export function renderWithProviders(
  52. ui: React.ReactElement,
  53. {
  54. preloadedState = {},
  55. // Automatically create a store instance if no store was passed in
  56. store = setupStore(preloadedState),
  57. ...renderOptions
  58. }: ExtendedRenderOptions = {},
  59. ) {
  60. function Wrapper({ children }: PropsWithChildren) {
  61. return (
  62. <Provider store={store}>
  63. <QueryClientProvider client={new QueryClient()}>
  64. <SettingsProvider>
  65. <AuthProvider>
  66. <ConversationProvider>
  67. <I18nextProvider i18n={i18n}>{children}</I18nextProvider>
  68. </ConversationProvider>
  69. </AuthProvider>
  70. </SettingsProvider>
  71. </QueryClientProvider>
  72. </Provider>
  73. );
  74. }
  75. return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
  76. }