Skip to the code
cf.

Unread count in the tab title

The tea shop's staff app has an inbox for customer messages, and the team wants to see how many are unread from any other tab. Build InboxTitle: a component that takes count and keeps document.title in step with it.

With unread messages, the title is the count in brackets, a space, and Inbox: (3) Inbox. With none (count is 0), it's just Inbox. When count changes, the title changes with it.

When InboxTitle leaves the page, put back the title the page had before it arrived, whatever that was. That holds after any number of count changes, and in Strict Mode too.

InboxTitle shows nothing on the page itself: it returns null. Export it by name. The default export, App, is a small demo for the Preview, and the tests don't use it.

document.title = "Tea shop";
 
<InboxTitle count={3} />  // the tab reads "(3) Inbox"
<InboxTitle count={0} />  // the tab reads "Inbox"
// InboxTitle removed     // the tab reads "Tea shop" again

What the tests check

  1. sets the title to (3) Inbox for 3 unread messages
    document.title = "Tea shop";
    render(<InboxTitle count={3} />);
    expect(document.title).toBe("(3) Inbox");
    
  2. shows just Inbox when nothing is unread
    document.title = "Tea shop";
    render(<InboxTitle count={0} />);
    expect(document.title).toBe("Inbox");
    
  3. follows the count as it changes
    document.title = "Tea shop";
    const { rerender } = render(<InboxTitle count={1} />);
    rerender(<InboxTitle count={5} />);
    expect(document.title).toBe("(5) Inbox");
    rerender(<InboxTitle count={0} />);
    expect(document.title).toBe("Inbox");
    rerender(<InboxTitle count={2} />);
    expect(document.title).toBe("(2) Inbox");
    
  4. puts the old title back when it leaves the page
    document.title = "Tea shop";
    const { unmount } = render(<InboxTitle count={2} />);
    unmount();
    expect(document.title).toBe("Tea shop");
    
  5. puts the old title back after the count has changed
    document.title = "Orders | Tea shop";
    const { rerender, unmount } = render(<InboxTitle count={2} />);
    rerender(<InboxTitle count={7} />);
    rerender(<InboxTitle count={0} />);
    rerender(<InboxTitle count={4} />);
    unmount();
    expect(document.title).toBe("Orders | Tea shop");
    
  6. works in Strict Mode
    document.title = "Staff app";
    const { rerender, unmount } = render(
      <React.StrictMode>
        <InboxTitle count={2} />
      </React.StrictMode>,
    );
    expect(document.title).toBe("(2) Inbox");
    rerender(
      <React.StrictMode>
        <InboxTitle count={3} />
      </React.StrictMode>,
    );
    expect(document.title).toBe("(3) Inbox");
    unmount();
    expect(document.title).toBe("Staff app");
    
  7. shows nothing on the page
    const { container } = render(<InboxTitle count={2} />);
    expect(container.innerHTML).toBe("");
    

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