Skip to the code
cf.

Profile card

The tea shop's About page shows a card for each person on the team. Build ProfileCard, a named export of App.jsx, that draws one card from its props. The default export, App, is only for the Preview: it shows two cards.

ProfileCard takes name and role (strings), avatarUrl (the photo's address), bio (a string, maybe missing), and isPro (true or false, maybe missing).

The card is an <article>. Inside it, show an <img> whose src is avatarUrl and whose alt text is Photo of and the name, then the name in an <h2>, then the role in a <p>.

When isPro is true, show a badge: a <span> with the text Pro. When it's false or missing, show no badge.

Show the bio in a second <p> (the role's is the first, and the card has no others), but only when there is one. A missing bio, an empty string, or a bio of only spaces all mean no bio, and then the card has no bio paragraph at all, not even an empty one.

<ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" bio="Tastes every tea before we stock it." isPro />
 
// draws:
<article>
  <img src="/team/mei.jpg" alt="Photo of Mei Lin" />
  <h2>Mei Lin</h2>
  <p>Tea buyer</p>
  <span>Pro</span>
  <p>Tastes every tea before we stock it.</p>
</article>

What the tests check

  1. shows the name as a heading and the role
    render(<ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" />);
    const card = screen.getByRole("article");
    expect(within(card).getByRole("heading", { level: 2, name: "Mei Lin" })).toBeInTheDocument();
    expect(within(card).getByText("Tea buyer")).toBeInTheDocument();
    
  2. shows the photo with alt text naming the person
    render(<ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" />);
    const photo = screen.getByRole("img", { name: "Photo of Mei Lin" });
    expect(photo).toHaveAttribute("src", "/team/mei.jpg");
    
  3. shows the bio when there is one
    render(<ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" bio="Tastes every tea before we stock it." />);
    expect(screen.getByText("Tastes every tea before we stock it.")).toBeInTheDocument();
    expect(screen.getByRole("article").querySelectorAll("p")).toHaveLength(2);
    
  4. has no bio paragraph when the bio is missing
    render(<ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" />);
    expect(screen.getByRole("article").querySelectorAll("p")).toHaveLength(1);
    
  5. treats an empty bio or one of only spaces as no bio
    const { rerender } = render(<ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" bio="" />);
    expect(screen.getByRole("article").querySelectorAll("p")).toHaveLength(1);
    rerender(<ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" bio="   " />);
    expect(screen.getByRole("article").querySelectorAll("p")).toHaveLength(1);
    
  6. shows a Pro badge when isPro is true
    render(<ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" isPro />);
    expect(within(screen.getByRole("article")).getByText("Pro")).toBeInTheDocument();
    
  7. shows no badge when isPro is false or missing
    const { rerender } = render(<ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" isPro={false} />);
    expect(screen.queryByText("Pro")).not.toBeInTheDocument();
    rerender(<ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" />);
    expect(screen.queryByText("Pro")).not.toBeInTheDocument();
    
  8. draws each card from its own props
    render(
      <div>
        <ProfileCard name="Mei Lin" role="Tea buyer" avatarUrl="/team/mei.jpg" isPro />
        <ProfileCard name="Sam Ortiz" role="Barista" avatarUrl="/team/sam.jpg" bio="Pours the latte art." />
      </div>,
    );
    const [mei, sam] = screen.getAllByRole("article");
    expect(within(mei).getByRole("heading")).toHaveTextContent("Mei Lin");
    expect(within(mei).getByText("Pro")).toBeInTheDocument();
    expect(within(mei).queryByText("Pours the latte art.")).not.toBeInTheDocument();
    expect(within(sam).getByRole("img", { name: "Photo of Sam Ortiz" })).toHaveAttribute("src", "/team/sam.jpg");
    expect(within(sam).queryByText("Pro")).not.toBeInTheDocument();
    expect(within(sam).getByText("Pours the latte art.")).toBeInTheDocument();
    

Learn more

App.jsxSaved in this browser

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).