Build App: the cart of a small tea shop. It takes products, the teas for sale as { id, name, price } with the price in dollars, and initialCart, the cart to start with as a list of { id, quantity } lines (an empty cart when it isn't given). When products isn't given, as in the Preview, use a few teas of your own.
Each product has a button named Add and the tea's name: Add Green tea. Adding a tea that isn't in the cart puts a line for it at the end, with a quantity of 1. Adding one that's already there raises that line's quantity instead.
The cart is a list labelled Cart (<ul aria-label="Cart">). Each line shows the name and quantity as Green tea × 2, a − button labelled One less Green tea, a + button labelled One more Green tea, and the line's price, $9.00. Put Green tea × 2 and $9.00 each in an element of its own, like the <span>s below, so each can be found by its text. Taking a quantity below 1 removes the line.
Under the cart, Items: 3 counts every tea in it and Total: $13.50 adds up the lines, with two decimal places. When the cart is empty, Your cart is empty. shows instead of the list, with Items: 0 and Total: $0.00.
Never change products, initialCart, or the objects in them. The tests may freeze them, and they check that initialCart is the same after you've used the cart. Every update makes new arrays and objects instead.
<App
products={[
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
]}
initialCart={[{ id: "green", quantity: 2 }]}
/>
// one line of the cart:
<li>
<span>Green tea × 2</span>
<button aria-label="One less Green tea">−</button>
<button aria-label="One more Green tea">+</button>
<span>$9.00</span>
</li>
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
expect(screen.getByText("Your cart is empty.")).toBeInTheDocument();
expect(screen.queryByRole("list", { name: "Cart" })).not.toBeInTheDocument();
expect(screen.getByText("Items: 0")).toBeInTheDocument();
expect(screen.getByText("Total: $0.00")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
const cart = screen.getByRole("list", { name: "Cart" });
expect(within(cart).getByText("Green tea × 1")).toBeInTheDocument();
expect(within(cart).getByText("$4.50")).toBeInTheDocument();
expect(screen.getByText("Items: 1")).toBeInTheDocument();
expect(screen.getByText("Total: $4.50")).toBeInTheDocument();
expect(screen.queryByText("Your cart is empty.")).not.toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
const cart = screen.getByRole("list", { name: "Cart" });
expect(within(cart).getAllByRole("listitem")).toHaveLength(1);
expect(within(cart).getByText("Green tea × 2")).toBeInTheDocument();
expect(within(cart).getByText("$9.00")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Oolong" }));
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
const lines = within(screen.getByRole("list", { name: "Cart" })).getAllByRole("listitem");
expect(lines[0]).toHaveTextContent("Oolong × 1");
expect(lines[1]).toHaveTextContent("Green tea × 1");
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "One more Green tea" }));
await user.click(screen.getByRole("button", { name: "One more Green tea" }));
expect(screen.getByText("Green tea × 3")).toBeInTheDocument();
expect(screen.getByText("Items: 3")).toBeInTheDocument();
expect(screen.getByText("Total: $13.50")).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "One less Green tea" }));
expect(screen.getByText("Green tea × 2")).toBeInTheDocument();
expect(screen.getByText("Total: $9.00")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Oolong" }));
await user.click(screen.getByRole("button", { name: "One less Green tea" }));
const cart = screen.getByRole("list", { name: "Cart" });
expect(within(cart).getAllByRole("listitem")).toHaveLength(1);
expect(screen.queryByText(/Green tea ×/)).not.toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "One less Oolong" }));
expect(screen.getByText("Your cart is empty.")).toBeInTheDocument();
expect(screen.getByText("Total: $0.00")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Oolong" }));
await user.click(screen.getByRole("button", { name: "Add Masala chai" }));
expect(screen.getByText("Items: 4")).toBeInTheDocument();
expect(screen.getByText("Total: $20.25")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
render(<App products={products} initialCart={[{ id: "oolong", quantity: 3 }]} />);
expect(screen.getByText("Oolong × 3")).toBeInTheDocument();
expect(within(screen.getByRole("list", { name: "Cart" })).getByText("$18.75")).toBeInTheDocument();
expect(screen.getByText("Items: 3")).toBeInTheDocument();
expect(screen.getByText("Total: $18.75")).toBeInTheDocument();
const products = [
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
];
const initialCart = [{ id: "green", quantity: 2 }, { id: "oolong", quantity: 1 }];
const before = JSON.parse(JSON.stringify(initialCart));
render(<App products={products} initialCart={initialCart} />);
await user.click(screen.getByRole("button", { name: "One more Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Oolong" }));
await user.click(screen.getByRole("button", { name: "Add Masala chai" }));
await user.click(screen.getByRole("button", { name: "One less Masala chai" }));
expect(screen.getByText("Green tea × 3")).toBeInTheDocument();
expect(screen.getByText("Oolong × 2")).toBeInTheDocument();
expect(initialCart).toEqual(before);
const freeze = (list) => Object.freeze(list.map((item) => Object.freeze(item)));
const products = freeze([
{ id: "green", name: "Green tea", price: 4.5 },
{ id: "oolong", name: "Oolong", price: 6.25 },
{ id: "chai", name: "Masala chai", price: 5 },
]);
render(<App products={products} initialCart={freeze([{ id: "green", quantity: 1 }])} />);
await user.click(screen.getByRole("button", { name: "Add Green tea" }));
await user.click(screen.getByRole("button", { name: "Add Masala chai" }));
await user.click(screen.getByRole("button", { name: "One more Masala chai" }));
await user.click(screen.getByRole("button", { name: "One less Green tea" }));
expect(screen.getByText("Green tea × 1")).toBeInTheDocument();
expect(screen.getByText("Masala chai × 2")).toBeInTheDocument();
expect(screen.getByText("Total: $14.50")).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 Shopping cart with quantities. 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.