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), + }; +};