add integration tests for product, cart and home pages

37 new LiveView integration tests covering the three previously
untested shop pages. Product detail tests cover variant selection,
price updates and add-to-cart. Cart tests use DB fixtures with
session seeding for hydration. Home tests cover hero, categories,
featured products and navigation links. 612 total tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-08 14:57:10 +00:00
parent 3b8d5faf3b
commit 518da36c8f
4 changed files with 362 additions and 5 deletions

View File

@ -209,13 +209,15 @@ All 8 items from the plan done. Key wins: ThemeHook eliminated mount duplication
See: [docs/plans/dry-refactor.md](docs/plans/dry-refactor.md) for full analysis and plan
### Shop Page Integration Tests
**Status:** Follow-up
**Status:** Complete
Home, product detail, and cart pages have no LiveView integration tests. Collection and content pages are well-covered (16 and 10 tests respectively). Priority order by logic complexity:
All shop pages now have LiveView integration tests (612 total):
1. **Product detail page** — variant selection, add-to-cart, gallery, breadcrumb
2. **Cart page** — cart items, quantity changes, order summary, checkout link
3. **Home page** — hero section, featured products, category nav (mostly presentational)
- **Product detail page** (15 tests) — rendering, breadcrumbs, variant selection, price updates, add-to-cart, related products, fallback for unknown IDs
- **Cart page** (10 tests) — empty state, item display with DB fixtures, order summary, increment/decrement, remove, checkout button
- **Home page** (12 tests) — hero section, category nav, featured products, image+text section, navigation links
- **Collection page** (16 tests, pre-existing) — category filtering, sorting, URL params
- **Content pages** (10 tests, pre-existing) — about, delivery, privacy, terms
### Page Editor
**Status:** Future (Tier 4)

View File

@ -0,0 +1,111 @@
defmodule SimpleshopThemeWeb.ShopLive.CartTest do
use SimpleshopThemeWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias SimpleshopTheme.ProductsFixtures
defp create_cart_with_product(_context) do
product = ProductsFixtures.complete_product_fixture(%{title: "Test Art Print"})
variant = List.first(product.variants)
%{product: product, variant: variant}
end
defp conn_with_cart(conn, variant_id, qty \\ 1) do
conn
|> Phoenix.ConnTest.init_test_session(%{"cart" => [{variant_id, qty}]})
end
describe "Empty cart" do
test "renders empty cart state", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/cart")
assert html =~ "Your basket"
assert html =~ "Your basket is empty"
end
test "shows continue shopping link when empty", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/cart")
assert html =~ "Continue shopping"
end
end
describe "Cart with items" do
setup [:create_cart_with_product]
test "displays cart item name", %{conn: conn, product: product, variant: variant} do
{:ok, _view, html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
assert html =~ product.title
end
test "displays order summary", %{conn: conn, variant: variant} do
{:ok, _view, html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
assert html =~ "Order summary"
assert html =~ "Subtotal"
end
test "displays formatted subtotal", %{conn: conn, variant: variant} do
{:ok, _view, html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
assert html =~ SimpleshopTheme.Cart.format_price(variant.price)
end
test "displays checkout button", %{conn: conn, variant: variant} do
{:ok, _view, html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
assert html =~ "Checkout"
end
test "incrementing quantity updates the display", %{
conn: conn,
product: product,
variant: variant
} do
{:ok, view, _html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
html =
view
|> element("button[aria-label='Increase quantity of #{product.title}']")
|> render_click()
assert html =~ "Quantity updated to 2"
end
test "decrementing to zero removes the item", %{
conn: conn,
product: product,
variant: variant
} do
{:ok, view, _html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
html =
view
|> element("button[aria-label='Decrease quantity of #{product.title}']")
|> render_click()
assert html =~ "Your basket is empty"
end
test "remove button removes the item", %{conn: conn, product: product, variant: variant} do
{:ok, view, _html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
html =
view
|> element("#main-content button[aria-label='Remove #{product.title} from cart']")
|> render_click()
assert html =~ "Your basket is empty"
end
end
describe "Cart page title" do
test "page title is Cart", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/cart")
assert html =~ "<title>Cart</title>"
end
end
end

View File

@ -0,0 +1,89 @@
defmodule SimpleshopThemeWeb.ShopLive.HomeTest do
use SimpleshopThemeWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias SimpleshopTheme.Theme.PreviewData
describe "Home page" do
test "renders the home page", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ "Original designs, printed on demand"
end
test "renders hero section with CTA", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ "Shop the collection"
end
test "renders category navigation", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
categories = PreviewData.categories()
for category <- Enum.take(categories, 3) do
assert html =~ category.name
end
end
test "renders featured products section", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ "Featured products"
products = PreviewData.products()
first_product = List.first(products)
assert html =~ first_product.name
end
test "renders image and text section", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ "Made with passion, printed with care"
assert html =~ "Learn more about the studio"
end
test "renders header with shop name", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
# Header should be present (part of shop_layout)
assert html =~ "SimpleShop"
end
test "renders footer with links", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ ~s(href="/about")
assert html =~ ~s(href="/contact")
end
end
describe "Navigation links" do
test "category links point to collections", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ ~s(href="/collections/)
end
test "product links point to product pages", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ ~s(href="/products/)
end
test "hero CTA links to collections", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ ~s(href="/collections/all")
end
test "about link in image section", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ ~s(href="/about")
end
end
end

View File

@ -0,0 +1,155 @@
defmodule SimpleshopThemeWeb.ShopLive.ProductShowTest do
use SimpleshopThemeWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias SimpleshopTheme.Theme.PreviewData
describe "Product detail page" do
test "renders product page with product name", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ product.name
end
test "renders product description", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ product.description
end
test "renders product price", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ SimpleshopTheme.Cart.format_price(product.price)
end
test "renders breadcrumb with Home link", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ "Home"
assert html =~ ~s(href="/")
end
test "renders breadcrumb with category link", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ product.category
end
test "renders add to cart button", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ "Add to basket"
end
test "renders related products section", %{conn: conn} do
product = List.first(PreviewData.products())
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
# Should show other products, not the current one
other_product = Enum.at(PreviewData.products(), 1)
assert html =~ other_product.name
end
end
describe "Variant selection" do
test "renders variant selectors for product with options", %{conn: conn} do
# Product "1" (Mountain Sunrise Art Print) has Size options
{:ok, _view, html} = live(conn, ~p"/products/1")
assert html =~ "Size"
assert html =~ "8×10"
assert html =~ "12×18"
assert html =~ "18×24"
end
test "renders color and size selectors for apparel", %{conn: conn} do
# Product "6" (Forest Silhouette T-Shirt) has Color and Size options
{:ok, _view, html} = live(conn, ~p"/products/6")
assert html =~ "Color"
assert html =~ "Size"
end
test "selecting a size updates the price", %{conn: conn} do
# Product "1" has variants: 8×10 = £19.99, 12×18 = £24.00, 18×24 = £32.00
{:ok, view, _html} = live(conn, ~p"/products/1")
html =
view
|> element("button[phx-value-value='18×24']")
|> render_click()
assert html =~ "£32.00"
end
test "selecting a colour updates available sizes", %{conn: conn} do
# Product "6": White / XL and White / 2XL are unavailable
{:ok, view, _html} = live(conn, ~p"/products/6")
html =
view
|> element("button[aria-label='Select White']")
|> render_click()
# XL should be disabled (unavailable in White)
assert html =~ "disabled"
end
test "shows 'One size' for products without options", %{conn: conn} do
# Product "2" (Ocean Waves Art Print) has no option_types
{:ok, _view, html} = live(conn, ~p"/products/2")
assert html =~ "One size"
end
end
describe "Add to cart" do
test "add to cart opens the cart drawer", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/products/1")
html =
view
|> element("button", "Add to basket")
|> render_click()
# Cart drawer should now be open (the aria live region gets updated)
assert html =~ "added to cart"
end
test "add to cart updates cart count", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/products/1")
html =
view
|> element("button", "Add to basket")
|> render_click()
# The cart drawer should show the item
assert html =~ "Mountain Sunrise Art Print"
end
end
describe "Navigation" do
test "product links navigate to correct product page", %{conn: conn} do
product = Enum.at(PreviewData.products(), 1)
{:ok, _view, html} = live(conn, ~p"/products/#{product.id}")
assert html =~ product.name
end
test "falls back to first product for unknown ID", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/products/nonexistent")
first_product = List.first(PreviewData.products())
assert html =~ first_product.name
end
end
end