Build App: a to-do list for the tea shop's morning jobs. It starts empty.
A text box labelled New task and an Add button add a task to the end of the list. Pressing Enter in the box adds it too. The text is trimmed before it's added, a box that's empty or only spaces adds nothing, and the box is emptied once a task is added.
Each task is a list item with a checkbox labelled by the task's text, which marks it done, and a Delete button that removes it. So that every Delete button has its own name, give it aria-label set to Delete and the task: aria-label="Delete Steep the oolong".
Three filter buttons, All, Active, and Done, choose which tasks the list shows: every task, the ones not done, or the ones done. The chosen filter has aria-pressed="true" and the other two "false". All is chosen at first.
Under the list, a line counts the tasks that aren't done, whatever the filter: 2 items left, 1 item left, 0 items left.
<form>
<label>New task <input /></label>
<button>Add</button>
</form>
<button aria-pressed="true">All</button>
<button aria-pressed="false">Active</button>
<button aria-pressed="false">Done</button>
<ul>
<li>
<label><input type="checkbox" /> Steep the oolong</label>
<button aria-label="Delete Steep the oolong">Delete</button>
</li>
</ul>
<p>1 item left</p>
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong");
await user.click(screen.getByRole("button", { name: "Add" }));
await user.clear(box);
await user.type(box, "Wash the pots");
await user.click(screen.getByRole("button", { name: "Add" }));
const items = screen.getAllByRole("listitem");
expect(items).toHaveLength(2);
expect(within(items[0]).getByRole("checkbox", { name: "Steep the oolong" })).not.toBeChecked();
expect(within(items[1]).getByRole("checkbox", { name: "Wash the pots" })).toBeInTheDocument();
expect(box).toHaveValue("");
render(<App />);
await user.type(screen.getByLabelText("New task"), "Wash the pots{Enter}");
expect(screen.getByRole("checkbox", { name: "Wash the pots" })).toBeInTheDocument();
expect(screen.getByLabelText("New task")).toHaveValue("");
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, " Sweep the floor {Enter}");
expect(screen.getByRole("button", { name: "Delete Sweep the floor" })).toHaveAttribute("aria-label", "Delete Sweep the floor");
await user.clear(box);
await user.type(box, " {Enter}");
await user.click(screen.getByRole("button", { name: "Add" }));
expect(screen.getAllByRole("listitem")).toHaveLength(1);
render(<App />);
await user.type(screen.getByLabelText("New task"), "Steep the oolong{Enter}");
const checkbox = screen.getByRole("checkbox", { name: "Steep the oolong" });
await user.click(checkbox);
expect(checkbox).toBeChecked();
await user.click(checkbox);
expect(checkbox).not.toBeChecked();
render(<App />);
expect(screen.getByText("0 items left")).toBeInTheDocument();
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong{Enter}");
expect(screen.getByText("1 item left")).toBeInTheDocument();
await user.clear(box);
await user.type(box, "Wash the pots{Enter}");
expect(screen.getByText("2 items left")).toBeInTheDocument();
await user.click(screen.getByRole("checkbox", { name: "Wash the pots" }));
expect(screen.getByText("1 item left")).toBeInTheDocument();
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong{Enter}");
await user.clear(box);
await user.type(box, "Wash the pots{Enter}");
await user.clear(box);
await user.type(box, "Sweep the floor{Enter}");
await user.click(screen.getByRole("checkbox", { name: "Sweep the floor" }));
await user.click(screen.getByRole("button", { name: "Delete Wash the pots" }));
const boxes = screen.getAllByRole("checkbox");
expect(boxes).toHaveLength(2);
expect(screen.getByRole("checkbox", { name: "Steep the oolong" })).not.toBeChecked();
expect(screen.getByRole("checkbox", { name: "Sweep the floor" })).toBeChecked();
expect(screen.getByText("1 item left")).toBeInTheDocument();
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong{Enter}");
await user.clear(box);
await user.type(box, "Wash the pots{Enter}");
await user.clear(box);
await user.type(box, "Sweep the floor{Enter}");
await user.click(screen.getByRole("checkbox", { name: "Wash the pots" }));
const all = screen.getByRole("button", { name: "All" });
const active = screen.getByRole("button", { name: "Active" });
const done = screen.getByRole("button", { name: "Done" });
expect(all).toHaveAttribute("aria-pressed", "true");
await user.click(active);
expect(active).toHaveAttribute("aria-pressed", "true");
expect(all).toHaveAttribute("aria-pressed", "false");
expect(screen.getAllByRole("checkbox")).toHaveLength(2);
expect(screen.queryByRole("checkbox", { name: "Wash the pots" })).not.toBeInTheDocument();
await user.click(done);
expect(done).toHaveAttribute("aria-pressed", "true");
expect(active).toHaveAttribute("aria-pressed", "false");
expect(screen.getAllByRole("checkbox")).toHaveLength(1);
expect(screen.getByRole("checkbox", { name: "Wash the pots" })).toBeChecked();
await user.click(all);
expect(screen.getAllByRole("checkbox")).toHaveLength(3);
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong{Enter}");
await user.clear(box);
await user.type(box, "Wash the pots{Enter}");
await user.click(screen.getByRole("checkbox", { name: "Wash the pots" }));
await user.click(screen.getByRole("button", { name: "Done" }));
expect(screen.getByText("1 item left")).toBeInTheDocument();
render(<App />);
const box = screen.getByLabelText("New task");
await user.type(box, "Steep the oolong{Enter}");
await user.clear(box);
await user.type(box, "Wash the pots{Enter}");
await user.click(screen.getByRole("button", { name: "Active" }));
await user.click(screen.getByRole("checkbox", { name: "Steep the oolong" }));
expect(screen.queryByRole("checkbox", { name: "Steep the oolong" })).not.toBeInTheDocument();
expect(screen.getAllByRole("checkbox")).toHaveLength(1);
expect(screen.getByText("1 item left")).toBeInTheDocument();
render(<App />);
await user.click(screen.getByRole("button", { name: "Done" }));
await user.type(screen.getByLabelText("New task"), "Steep the oolong{Enter}");
expect(screen.queryByRole("checkbox", { name: "Steep the oolong" })).not.toBeInTheDocument();
expect(screen.getByText("1 item left")).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "All" }));
expect(screen.getByRole("checkbox", { name: "Steep the oolong" })).not.toBeChecked();
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 To-do list with filters. 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.