Преглед на файлове

setup env for controlled integration tests with redux (#1180)

sp.wack преди 1 година
родител
ревизия
426f387123
променени са 7 файла, в които са добавени 91 реда и са изтрити 16 реда
  1. 33 0
      frontend/src/components/Browser.test.tsx
  2. 0 5
      frontend/src/setupTests.ts
  3. 13 10
      frontend/src/store.ts
  4. 38 0
      frontend/test-utils.tsx
  5. 3 1
      frontend/tsconfig.json
  6. 1 0
      frontend/vite.config.ts
  7. 3 0
      frontend/vitest.setup.ts

+ 33 - 0
frontend/src/components/Browser.test.tsx

@@ -0,0 +1,33 @@
+import React from "react";
+import Browser from "./Browser";
+import { renderWithProviders } from "../../test-utils";
+
+describe("Browser", () => {
+  it("renders a message if no screenshotSrc is provided", () => {
+    const { getByText } = renderWithProviders(<Browser />, {
+      preloadedState: {
+        browser: {
+          url: "https://example.com",
+          screenshotSrc: "",
+        },
+      },
+    });
+
+    expect(getByText(/no screenshot available/i)).toBeInTheDocument();
+  });
+
+  it("renders the url and a screenshot", () => {
+    const { getByText, getByAltText } = renderWithProviders(<Browser />, {
+      preloadedState: {
+        browser: {
+          url: "https://example.com",
+          screenshotSrc:
+            "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN0uGvyHwAFCAJS091fQwAAAABJRU5ErkJggg==",
+        },
+      },
+    });
+
+    expect(getByText("https://example.com")).toBeInTheDocument();
+    expect(getByAltText(/browser screenshot/i)).toBeInTheDocument();
+  });
+});

+ 0 - 5
frontend/src/setupTests.ts

@@ -1,5 +0,0 @@
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import "@testing-library/jest-dom";

+ 13 - 10
frontend/src/store.ts

@@ -1,4 +1,4 @@
-import { configureStore } from "@reduxjs/toolkit";
+import { combineReducers, configureStore } from "@reduxjs/toolkit";
 import browserReducer from "./state/browserSlice";
 import chatReducer from "./state/chatSlice";
 import codeReducer from "./state/codeSlice";
@@ -7,19 +7,22 @@ import taskReducer from "./state/taskSlice";
 import errorsReducer from "./state/errorsSlice";
 import settingsReducer from "./state/settingsSlice";
 
+export const rootReducer = combineReducers({
+  browser: browserReducer,
+  chat: chatReducer,
+  code: codeReducer,
+  cmd: commandReducer,
+  task: taskReducer,
+  errors: errorsReducer,
+  settings: settingsReducer,
+});
+
 const store = configureStore({
-  reducer: {
-    browser: browserReducer,
-    chat: chatReducer,
-    code: codeReducer,
-    cmd: commandReducer,
-    task: taskReducer,
-    errors: errorsReducer,
-    settings: settingsReducer,
-  },
+  reducer: rootReducer,
 });
 
 export type RootState = ReturnType<typeof store.getState>;
+export type AppStore = typeof store;
 export type AppDispatch = typeof store.dispatch;
 
 export default store;

+ 38 - 0
frontend/test-utils.tsx

@@ -0,0 +1,38 @@
+// See https://redux.js.org/usage/writing-tests#setting-up-a-reusable-test-render-function for more information
+
+import React, { PropsWithChildren } from "react";
+import { Provider } from "react-redux";
+import { configureStore } from "@reduxjs/toolkit";
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { RenderOptions, render } from "@testing-library/react";
+import { AppStore, RootState, rootReducer } from "./src/store";
+
+const setupStore = (preloadedState?: Partial<RootState>): AppStore =>
+  configureStore({
+    reducer: rootReducer,
+    preloadedState,
+  });
+
+// 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 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<object>): JSX.Element {
+    return <Provider store={store}>{children}</Provider>;
+  }
+  return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
+}

+ 3 - 1
frontend/tsconfig.json

@@ -24,6 +24,8 @@
   "include": [
     "src",
     "vite-env.d.ts",
-    "vite.config.ts"
+    "vite.config.ts",
+    "vitest.setup.ts",
+    "test-utils.tsx"
   ]
 }

+ 1 - 0
frontend/vite.config.ts

@@ -35,5 +35,6 @@ export default defineConfig({
   test: {
     environment: "jsdom",
     globals: true,
+    setupFiles: ["vitest.setup.ts"],
   },
 });

+ 3 - 0
frontend/vitest.setup.ts

@@ -0,0 +1,3 @@
+// learn more: https://github.com/testing-library/jest-dom
+// eslint-disable-next-line import/no-extraneous-dependencies
+import "@testing-library/jest-dom";