174 lines
4.6 KiB
Elixir
174 lines
4.6 KiB
Elixir
|
|
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
|