Build UserProfile, the default export: the profile card for one member of a small tea shop's club. It takes an id prop (default 1) and fetches /api/users/ followed by the id, like /api/users/7. The answer is JSON like { id: 7, name: "Asha Rao", email: "asha@tea.shop" }.
While the user is loading, show only Loading… (with the single … character). Then show the name in a heading and the email in a paragraph.
If the request fails (fetch rejects, or the response isn't ok), show Couldn't load this user. and a Retry button that fetches the same user again.
When id changes, fetch the new user and show Loading… until it arrives. An answer for an id the card no longer shows must never appear, even if it arrives late.
<UserProfile id={7} />
// While it loads:
<p>Loading…</p>
// Then:
<h2>Asha Rao</h2>
<p>asha@tea.shop</p>
const fetch = mockFetch(() => ({ id: 7, name: "Asha Rao", email: "asha@tea.shop" }));
render(<App id={7} />);
expect(await screen.findByText("Asha Rao")).toBeInTheDocument();
expect(fetch.calls.map((call) => call.url)).toEqual(["/api/users/7"]);
const answer = deferred();
mockFetch(() => answer.promise);
render(<App id={7} />);
expect(screen.getByText("Loading…")).toBeInTheDocument();
answer.resolve({ id: 7, name: "Asha Rao", email: "asha@tea.shop" });
expect(await screen.findByText("Asha Rao")).toBeInTheDocument();
expect(screen.queryByText("Loading…")).not.toBeInTheDocument();
mockFetch(() => ({ id: 7, name: "Asha Rao", email: "asha@tea.shop" }));
render(<App id={7} />);
expect(await screen.findByRole("heading", { name: "Asha Rao" })).toBeInTheDocument();
expect(screen.getByText("asha@tea.shop")).toBeInTheDocument();
mockFetch(() => fail(500));
render(<App id={7} />);
expect(await screen.findByText("Couldn't load this user.")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Retry" })).toBeInTheDocument();
expect(screen.queryByText("Loading…")).not.toBeInTheDocument();
mockFetch(() => {
throw new TypeError("Failed to fetch");
});
render(<App id={7} />);
expect(await screen.findByText("Couldn't load this user.")).toBeInTheDocument();
let attempts = 0;
const fetch = mockFetch(() => (++attempts === 1 ? fail(500) : { id: 7, name: "Asha Rao", email: "asha@tea.shop" }));
render(<App id={7} />);
await user.click(await screen.findByRole("button", { name: "Retry" }));
expect(await screen.findByText("Asha Rao")).toBeInTheDocument();
expect(screen.queryByText("Couldn't load this user.")).not.toBeInTheDocument();
expect(fetch.calls.map((call) => call.url)).toEqual(["/api/users/7", "/api/users/7"]);
const later = deferred();
const fetch = mockFetch((url) => (url === "/api/users/1" ? { id: 1, name: "Asha Rao", email: "asha@tea.shop" } : later.promise));
const { rerender } = render(<App id={1} />);
expect(await screen.findByText("Asha Rao")).toBeInTheDocument();
rerender(<App id={2} />);
expect(screen.getByText("Loading…")).toBeInTheDocument();
expect(screen.queryByText("Asha Rao")).not.toBeInTheDocument();
later.resolve({ id: 2, name: "Ben Okafor", email: "ben@tea.shop" });
expect(await screen.findByText("Ben Okafor")).toBeInTheDocument();
expect(fetch.calls.map((call) => call.url)).toEqual(["/api/users/1", "/api/users/2"]);
const first = deferred();
mockFetch((url) => (url === "/api/users/1" ? first.promise : { id: 2, name: "Ben Okafor", email: "ben@tea.shop" }));
const { rerender } = render(<App id={1} />);
rerender(<App id={2} />);
expect(await screen.findByText("Ben Okafor")).toBeInTheDocument();
first.resolve({ id: 1, name: "Asha Rao", email: "asha@tea.shop" });
await flush();
expect(screen.queryByText("Asha Rao")).not.toBeInTheDocument();
expect(screen.getByText("Ben Okafor")).toBeInTheDocument();
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with User profile fetch. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.