Build App: the tag box a tea shop uses to label its teas, with tags like green, smoky, and caffeine free.
There's a text box labelled Add a tag. Pressing Enter, or typing a comma, adds what's in the box as a tag, trimmed, and empties the box. The comma is never typed into the box.
If the trimmed text is empty, or is already a tag ignoring case (Green and green are the same tag), nothing is added and the box keeps its text.
The tags show in a list labelled Tags (<ul aria-label="Tags">), one list item per tag, in the order they were added. Each item shows the tag and a button whose accessible name is Remove and the tag, like Remove green tea. It removes that tag.
Pressing Backspace in the box while it's empty removes the last tag. With text in the box, Backspace deletes a character as usual.
<ul aria-label="Tags">
<li>green <button aria-label="Remove green">×</button></li>
<li>smoky <button aria-label="Remove smoky">×</button></li>
</ul>
<label for="tag">Add a tag</label>
<input id="tag" />
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, " green tea {Enter}");
const items = within(screen.getByRole("list", { name: "Tags" })).getAllByRole("listitem");
expect(items).toHaveLength(1);
expect(items[0]).toHaveTextContent("green tea");
expect(screen.getByRole("button", { name: "Remove green tea" })).toBeInTheDocument();
expect(box).toHaveValue("");
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, "smoky,");
expect(screen.getByRole("button", { name: "Remove smoky" })).toBeInTheDocument();
expect(box).toHaveValue("");
render(<App />);
await user.type(screen.getByLabelText("Add a tag"), " {Enter},");
expect(within(screen.getByRole("list", { name: "Tags" })).queryAllByRole("listitem")).toHaveLength(0);
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, "Green{Enter}");
await user.type(box, "green{Enter}");
expect(within(screen.getByRole("list", { name: "Tags" })).getAllByRole("listitem")).toHaveLength(1);
expect(box).toHaveValue("green");
render(<App />);
await user.type(screen.getByLabelText("Add a tag"), "oolong{Enter}smoky,floral{Enter}");
const items = within(screen.getByRole("list", { name: "Tags" })).getAllByRole("listitem");
expect(items).toHaveLength(3);
expect(items[0]).toHaveTextContent("oolong");
expect(items[1]).toHaveTextContent("smoky");
expect(items[2]).toHaveTextContent("floral");
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, "green{Enter}black{Enter}");
await user.keyboard("{Backspace}");
expect(screen.queryByRole("button", { name: "Remove black" })).not.toBeInTheDocument();
expect(screen.getByRole("button", { name: "Remove green" })).toBeInTheDocument();
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, "green{Enter}bla{Backspace}");
expect(box).toHaveValue("bl");
expect(screen.getByRole("button", { name: "Remove green" })).toBeInTheDocument();
render(<App />);
await user.type(screen.getByLabelText("Add a tag"), "green{Enter}black{Enter}white{Enter}");
await user.click(screen.getByRole("button", { name: "Remove black" }));
const items = within(screen.getByRole("list", { name: "Tags" })).getAllByRole("listitem");
expect(items).toHaveLength(2);
expect(items[0]).toHaveTextContent("green");
expect(items[1]).toHaveTextContent("white");
render(<App />);
const box = screen.getByLabelText("Add a tag");
await user.type(box, "chai{Enter}");
await user.click(screen.getByRole("button", { name: "Remove chai" }));
await user.type(box, "Chai{Enter}");
expect(screen.getByRole("button", { name: "Remove Chai" })).toBeInTheDocument();
expect(box).toHaveValue("");
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 Tag input. 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.