From 4261ddae510e07312d6fbbdaf2018bbe4e3469da Mon Sep 17 00:00:00 2001
From: Mamadou DICKO <63923024+mamadoudicko@users.noreply.github.com>
Date: Thu, 6 Jul 2023 19:01:23 +0200
Subject: [PATCH] Frontend/test/explore/1 (#544)
* refactor(): add useExplore
* feat(api): add useBrainApi
* test(useBrainApi): add unit tests
---
frontend/app/explore/hooks/useExplore.ts | 56 +++++++++++++++++++
frontend/app/explore/page.tsx | 51 +----------------
.../api/brain/__tests__/useBrainApi.test.ts | 37 ++++++++++++
frontend/lib/api/brain/brain.ts | 14 +++++
frontend/lib/api/brain/useBrainApi.ts | 13 +++++
5 files changed, 122 insertions(+), 49 deletions(-)
create mode 100644 frontend/app/explore/hooks/useExplore.ts
create mode 100644 frontend/lib/api/brain/__tests__/useBrainApi.test.ts
create mode 100644 frontend/lib/api/brain/brain.ts
create mode 100644 frontend/lib/api/brain/useBrainApi.ts
diff --git a/frontend/app/explore/hooks/useExplore.ts b/frontend/app/explore/hooks/useExplore.ts
new file mode 100644
index 000000000..abf9681a3
--- /dev/null
+++ b/frontend/app/explore/hooks/useExplore.ts
@@ -0,0 +1,56 @@
+import { UUID } from "crypto";
+import { useEffect, useState } from "react";
+
+import { useBrainApi } from "@/lib/api/brain/useBrainApi";
+import { getBrainFromLocalStorage } from "@/lib/context/BrainProvider/helpers/brainLocalStorage";
+import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
+import { useSupabase } from "@/lib/context/SupabaseProvider";
+import { useAxios } from "@/lib/hooks";
+import { Document } from "@/lib/types/Document";
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export const useExplore = () => {
+ const [documents, setDocuments] = useState([]);
+ const [isPending, setIsPending] = useState(true);
+ const { session } = useSupabase();
+ const { axiosInstance } = useAxios();
+ const { setActiveBrain, setDefaultBrain, currentBrainId } = useBrainContext();
+ const { getBrainDocuments } = useBrainApi();
+ const fetchAndSetActiveBrain = async () => {
+ const storedBrain = getBrainFromLocalStorage();
+ if (storedBrain) {
+ setActiveBrain({ ...storedBrain });
+
+ return storedBrain;
+ } else {
+ const defaultBrain = await setDefaultBrain();
+
+ return defaultBrain;
+ }
+ };
+
+ useEffect(() => {
+ const fetchDocuments = async (brainId: UUID | null) => {
+ setIsPending(true);
+ await fetchAndSetActiveBrain();
+ try {
+ if (brainId === null) {
+ throw new Error("Brain id not found");
+ }
+ const brainDocuments = await getBrainDocuments(brainId);
+ setDocuments(brainDocuments);
+ } catch (error) {
+ console.error("Error fetching documents", error);
+ setDocuments([]);
+ }
+ setIsPending(false);
+ };
+ void fetchDocuments(currentBrainId);
+ }, [session?.access_token, axiosInstance, currentBrainId]);
+
+ return {
+ isPending,
+ documents,
+ setDocuments,
+ };
+};
diff --git a/frontend/app/explore/page.tsx b/frontend/app/explore/page.tsx
index 6ad588360..7caff649f 100644
--- a/frontend/app/explore/page.tsx
+++ b/frontend/app/explore/page.tsx
@@ -3,68 +3,21 @@
import { AnimatePresence, motion } from "framer-motion";
import Link from "next/link";
import { redirect } from "next/navigation";
-import { useEffect, useState } from "react";
import Button from "@/lib/components/ui/Button";
import Spinner from "@/lib/components/ui/Spinner";
import { useSupabase } from "@/lib/context/SupabaseProvider";
-import { useAxios } from "@/lib/hooks";
-import { Document } from "@/lib/types/Document";
-import { getBrainFromLocalStorage } from "@/lib/context/BrainProvider/helpers/brainLocalStorage";
-import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
-import { UUID } from "crypto";
import DocumentItem from "./DocumentItem";
+import { useExplore } from "./hooks/useExplore";
const ExplorePage = (): JSX.Element => {
- const [documents, setDocuments] = useState([]);
- const [isPending, setIsPending] = useState(true);
const { session } = useSupabase();
- const { axiosInstance } = useAxios();
- const { setActiveBrain, setDefaultBrain, currentBrain, currentBrainId } =
- useBrainContext();
-
- const fetchAndSetActiveBrain = async () => {
- const storedBrain = getBrainFromLocalStorage();
- if (storedBrain) {
- setActiveBrain({ ...storedBrain });
- return storedBrain;
- } else {
- const defaultBrain = await setDefaultBrain();
- return defaultBrain;
- }
- };
-
+ const { documents, setDocuments, isPending } = useExplore();
if (session === null) {
redirect("/login");
}
- useEffect(() => {
- const fetchDocuments = async (brainId: UUID | null) => {
- setIsPending(true);
- await fetchAndSetActiveBrain();
- try {
- if (brainId === undefined || brainId === null) {
- throw new Error("Brain id not found");
- }
-
- console.log(
- `Fetching documents from ${process.env.NEXT_PUBLIC_BACKEND_URL}/explore/?brain_id=${brainId}`
- );
-
- const response = await axiosInstance.get<{ documents: Document[] }>(
- `/explore/?brain_id=${brainId}`
- );
- setDocuments(response.data.documents);
- } catch (error) {
- console.error("Error fetching documents", error);
- setDocuments([]);
- }
- setIsPending(false);
- };
- fetchDocuments(currentBrainId);
- }, [session.access_token, axiosInstance, currentBrainId]);
-
return (
diff --git a/frontend/lib/api/brain/__tests__/useBrainApi.test.ts b/frontend/lib/api/brain/__tests__/useBrainApi.test.ts
new file mode 100644
index 000000000..fd4deb881
--- /dev/null
+++ b/frontend/lib/api/brain/__tests__/useBrainApi.test.ts
@@ -0,0 +1,37 @@
+import { renderHook } from "@testing-library/react";
+import { afterEach, describe, expect, it, vi } from "vitest";
+
+import { useBrainApi } from "../useBrainApi";
+
+const axiosGetMock = vi.fn(() => ({
+ data: {
+ documents: [],
+ },
+}));
+
+vi.mock("@/lib/hooks", () => ({
+ useAxios: vi.fn(() => ({
+ axiosInstance: {
+ get: axiosGetMock,
+ },
+ })),
+}));
+
+describe("useBrainApi", () => {
+ afterEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should call getBrainDocuments with the correct parameters", async () => {
+ const {
+ result: {
+ current: { getBrainDocuments },
+ },
+ } = renderHook(() => useBrainApi());
+ const brainId = "123";
+ await getBrainDocuments(brainId);
+
+ expect(axiosGetMock).toHaveBeenCalledTimes(1);
+ expect(axiosGetMock).toHaveBeenCalledWith(`/explore/?brain_id=${brainId}`);
+ });
+});
diff --git a/frontend/lib/api/brain/brain.ts b/frontend/lib/api/brain/brain.ts
new file mode 100644
index 000000000..be0e1aab5
--- /dev/null
+++ b/frontend/lib/api/brain/brain.ts
@@ -0,0 +1,14 @@
+import { AxiosInstance } from "axios";
+
+import { Document } from "@/lib/types/Document";
+
+export const getBrainDocuments = async (
+ brainId: string,
+ axiosInstance: AxiosInstance
+): Promise => {
+ const response = await axiosInstance.get<{ documents: Document[] }>(
+ `/explore/?brain_id=${brainId}`
+ );
+
+ return response.data.documents;
+};
diff --git a/frontend/lib/api/brain/useBrainApi.ts b/frontend/lib/api/brain/useBrainApi.ts
new file mode 100644
index 000000000..9a7bef39a
--- /dev/null
+++ b/frontend/lib/api/brain/useBrainApi.ts
@@ -0,0 +1,13 @@
+import { useAxios } from "@/lib/hooks";
+
+import { getBrainDocuments } from "./brain";
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export const useBrainApi = () => {
+ const { axiosInstance } = useAxios();
+
+ return {
+ getBrainDocuments: async (brainId: string) =>
+ getBrainDocuments(brainId, axiosInstance),
+ };
+};