diff --git a/app/coe/page.tsx b/app/coe/page.tsx index 737eddb..2cb52b4 100644 --- a/app/coe/page.tsx +++ b/app/coe/page.tsx @@ -1,17 +1,14 @@ import { HistoricalResult } from "@/components/HistoricalResult"; import { MonthlyResult } from "@/components/MonthlyResult"; import { API_URL } from "@/config"; +import { fetchApi } from "@/utils/fetchApi"; import { COEResult } from "@/types"; export const runtime = "edge"; const COEPage = async () => { - const fetchHistoricalResult: Promise = fetch( - `${API_URL}/coe`, - ).then((res) => res.json()); - const fetchMonthlyResult: Promise = fetch( - `${API_URL}/coe/latest`, - ).then((res) => res.json()); + const fetchHistoricalResult = fetchApi(`${API_URL}/coe`); + const fetchMonthlyResult = fetchApi(`${API_URL}/coe/latest`); let [historicalResult, monthlyResult] = await Promise.all([ fetchHistoricalResult, diff --git a/app/page.tsx b/app/page.tsx index 375d6c4..5882cab 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,13 +5,12 @@ import { API_URL, BASE_URL, EXCLUSION_LIST } from "@/config"; import { sortByMake } from "@/lib/sortByMake"; import type { Car } from "@/types"; import { WebSite, WithContext } from "schema-dts"; +import { fetchApi } from "@/utils/fetchApi"; export const runtime = "edge"; const Home = async () => { - const electricCars: Car[] = await fetch(API_URL, { cache: "no-store" }).then( - (res) => res.json(), - ); + const electricCars = await fetchApi(API_URL, { cache: "no-store" }); const totals = new Map(); electricCars.forEach((car) => { diff --git a/bun.lockb b/bun.lockb index 68fe27a..71235b9 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/jest.setup.js b/jest.setup.js index d0de870..b657df2 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1 +1,4 @@ import "@testing-library/jest-dom"; +import fetchMock from "jest-fetch-mock"; + +fetchMock.enableMocks(); diff --git a/package.json b/package.json index e2f94f8..1106992 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "eslint-config-next": "14.0.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "jest-fetch-mock": "^3.0.3", "postcss": "^8", "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.6", diff --git a/utils/fetchApi.test.ts b/utils/fetchApi.test.ts new file mode 100644 index 0000000..2ca3eb6 --- /dev/null +++ b/utils/fetchApi.test.ts @@ -0,0 +1,16 @@ +import fetch from "jest-fetch-mock"; +import { fetchApi } from "@/utils/fetchApi"; + +describe("fetchApi", () => { + beforeEach(() => fetch.resetMocks()); + + it("should return data for a successful API call", async () => { + fetch.mockResponseOnce(JSON.stringify({ data: "test" })); + + const url = "https://example.com/api/test"; + const data = await fetchApi(url); + + expect(fetch).toHaveBeenCalledTimes(1); + expect(data).toEqual({ data: "test" }); + }); +}); diff --git a/utils/fetchApi.ts b/utils/fetchApi.ts new file mode 100644 index 0000000..51ace83 --- /dev/null +++ b/utils/fetchApi.ts @@ -0,0 +1,16 @@ +interface Options extends RequestInit {} + +export const fetchApi = async ( + url: string, + options: Options = {}, +): Promise => { + const response = await fetch(url, options); + + if (!response.ok) { + throw new Error( + `API call failed: ${response.status} - ${response.statusText}`, + ); + } + + return await response.json(); +};