Create a context to wrap the fetch
.
import { createContext, useContext } from "react";
const API = {
getRandomFact(): Promise<string> {
return fetch("https://api.chucknorris.io/jokes/random")
.then((r) => r.json())
.then((d) => d.value);
},
};
export const ApiContext = createContext(API);
Use context in a component instead of using the regular fetch
import { useContext, useEffect, useState } from "react";
export function RandomFact() {
const { getRandomFact } = useContext(ApiContext);
const [fact, setFact] = useState("");
useEffect(() => {
getRandomFact().then(setFact);
return () => console.log("cancelling request");
}, []);
return <p> {fact}</p>;
}
Test the code using fake API. Note that no network call will be done. This way we can wrap a code with any external activities
import { expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import { ApiContext, RandomFact } from "./random-fact";
test("On load random fact should be called", async () => {
const fakeApi = { getRandomFact: () => Promise.resolve("fact") };
render(
<ApiContext.Provider value={fakeApi}>
<RandomFact />
</ApiContext.Provider>
);
const fact = await screen.findByText("fact");
expect(fact).toBeInTheDocument();
});
This code requires extra setup:
vite-config.ts
import { defineConfig } from 'vitest/config';
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
environment: "happy-dom",
setupFiles: ["./vitest-setup.js"],
},
});
And include vitest-setup.js
into the tsconfig.json