defmodule SimpleshopTheme.CartTest do use ExUnit.Case, async: true alias SimpleshopTheme.Cart describe "add_item/3" do test "adds a new item to an empty cart" do cart = Cart.add_item([], "variant-1") assert cart == [{"variant-1", 1}] end test "adds a new item with custom quantity" do cart = Cart.add_item([], "variant-1", 3) assert cart == [{"variant-1", 3}] end test "increments quantity for existing item" do cart = [{"variant-1", 2}] cart = Cart.add_item(cart, "variant-1", 1) assert cart == [{"variant-1", 3}] end test "adds different items separately" do cart = [] |> Cart.add_item("variant-1", 1) |> Cart.add_item("variant-2", 2) assert cart == [{"variant-1", 1}, {"variant-2", 2}] end end describe "update_quantity/3" do test "updates the quantity of an existing item" do cart = [{"variant-1", 2}] cart = Cart.update_quantity(cart, "variant-1", 5) assert cart == [{"variant-1", 5}] end test "removes item when quantity is zero" do cart = [{"variant-1", 2}] cart = Cart.update_quantity(cart, "variant-1", 0) assert cart == [] end test "removes item when quantity is negative" do cart = [{"variant-1", 2}] cart = Cart.update_quantity(cart, "variant-1", -1) assert cart == [] end test "does nothing for non-existent item" do cart = [{"variant-1", 2}] cart = Cart.update_quantity(cart, "variant-999", 5) assert cart == [{"variant-1", 2}] end end describe "remove_item/2" do test "removes an item from the cart" do cart = [{"variant-1", 2}, {"variant-2", 1}] cart = Cart.remove_item(cart, "variant-1") assert cart == [{"variant-2", 1}] end test "does nothing for non-existent item" do cart = [{"variant-1", 2}] cart = Cart.remove_item(cart, "variant-999") assert cart == [{"variant-1", 2}] end test "returns empty list when removing last item" do cart = Cart.remove_item([{"variant-1", 1}], "variant-1") assert cart == [] end end describe "get_quantity/2" do test "returns quantity for existing item" do cart = [{"variant-1", 3}] assert Cart.get_quantity(cart, "variant-1") == 3 end test "returns 0 for non-existent item" do assert Cart.get_quantity([], "variant-1") == 0 end end describe "item_count/1" do test "sums all quantities" do cart = [{"variant-1", 2}, {"variant-2", 3}] assert Cart.item_count(cart) == 5 end test "returns 0 for empty cart" do assert Cart.item_count([]) == 0 end end describe "format_price/1" do test "formats pence as GBP string" do assert Cart.format_price(2400) == "£24.00" end test "formats with pence correctly" do assert Cart.format_price(1499) == "£14.99" end test "formats zero" do assert Cart.format_price(0) == "£0.00" end test "formats single digit pence with padding" do assert Cart.format_price(105) == "£1.05" end test "returns fallback for non-integer" do assert Cart.format_price(nil) == "£0.00" assert Cart.format_price("foo") == "£0.00" end end describe "calculate_subtotal/1" do test "sums price * quantity for all items" do items = [ %{price: 2400, quantity: 1}, %{price: 1499, quantity: 2} ] assert Cart.calculate_subtotal(items) == 5398 end test "returns 0 for empty list" do assert Cart.calculate_subtotal([]) == 0 end end describe "serialize/1 and deserialize/1" do test "round-trips cart data" do cart = [{"variant-1", 2}, {"variant-2", 1}] assert cart == cart |> Cart.serialize() |> Cart.deserialize() end test "serialize converts tuples to lists" do assert Cart.serialize([{"v1", 3}]) == [["v1", 3]] end test "deserialize drops malformed entries" do assert Cart.deserialize([[1, 2]]) == [] assert Cart.deserialize([["valid", 1], [nil, 2]]) == [{"valid", 1}] end test "deserialize handles non-list input" do assert Cart.deserialize(nil) == [] assert Cart.deserialize("garbage") == [] end end describe "get_from_session/1" do test "returns cart items from session" do session = %{"cart" => [{"v1", 2}]} assert Cart.get_from_session(session) == [{"v1", 2}] end test "returns empty list when no cart in session" do assert Cart.get_from_session(%{}) == [] end test "returns empty list for invalid cart data" do assert Cart.get_from_session(%{"cart" => "garbage"}) == [] end end end