add no-JS progressive enhancement for all shop flows
All checks were successful
deploy / deploy (push) Successful in 1m23s

Every key shop flow now works via plain HTML forms when JS is
unavailable. LiveView progressively enhances when JS connects.

- PDP: form wraps variant/qty/add-to-cart with action="/cart/add"
- Cart page: qty +/- and remove use form POST fallbacks
- Cart/search header icons are now links with phx-click enhancement
- Collection sort form has GET action + noscript submit button
- New /search page with form-based search for no-JS users
- CartController gains add/remove/update_item POST actions
- CartHook gains update_quantity_form and remove_item_form handlers
- Fix flaky analytics tests caused by event table pollution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-24 22:56:19 +00:00
parent f788108665
commit 0b0adba0fe
16 changed files with 461 additions and 67 deletions

View File

@@ -68,41 +68,39 @@ defmodule BerrypodWeb.Shop.CartTest do
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("#main-content button[aria-label='Increase quantity of #{product.title}']")
|> render_click()
|> form("#main-content form[phx-submit='update_quantity_form']")
|> render_submit(%{"quantity" => "2"})
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("#main-content button[aria-label='Decrease quantity of #{product.title}']")
|> render_click()
|> form("#main-content form[phx-submit='update_quantity_form']")
|> render_submit(%{"quantity" => "0"})
assert html =~ "Your basket is empty"
end
test "remove button removes the item", %{conn: conn, product: product, variant: variant} do
test "remove button removes the item", %{conn: conn, 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()
|> form("#main-content form[phx-submit='remove_item_form']")
|> render_submit()
assert html =~ "Your basket is empty"
end

View File

@@ -292,11 +292,11 @@ defmodule BerrypodWeb.Shop.ProductShowTest do
view |> element("button[phx-click='increment_quantity']") |> render_click()
view |> element("button[phx-click='increment_quantity']") |> render_click()
# Add to cart
# Add to cart via form submit
html =
view
|> element("button", "Add to basket")
|> render_click()
|> form("form[phx-submit='add_to_cart']")
|> render_submit()
# Decrement should be disabled again (quantity reset to 1)
assert html =~ ~s(phx-click="decrement_quantity")
@@ -310,8 +310,8 @@ defmodule BerrypodWeb.Shop.ProductShowTest do
html =
view
|> element("button", "Add to basket")
|> render_click()
|> form("form[phx-submit='add_to_cart']")
|> render_submit()
assert html =~ "added to cart"
end
@@ -321,8 +321,8 @@ defmodule BerrypodWeb.Shop.ProductShowTest do
html =
view
|> element("button", "Add to basket")
|> render_click()
|> form("form[phx-submit='add_to_cart']")
|> render_submit()
assert html =~ "Mountain Sunrise Print"
end

View File

@@ -0,0 +1,57 @@
defmodule BerrypodWeb.Shop.SearchPageTest do
use BerrypodWeb.ConnCase, async: false
import Phoenix.LiveViewTest
import Berrypod.AccountsFixtures
alias Berrypod.ProductsFixtures
setup do
user_fixture()
{:ok, _} = Berrypod.Settings.set_site_live(true)
:ok
end
describe "GET /search" do
test "renders search page with empty query", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/search")
assert html =~ "Search"
assert html =~ ~s(placeholder="Search products...")
end
test "renders search results for a matching query", %{conn: conn} do
product =
ProductsFixtures.complete_product_fixture(%{title: "Blue Mountain Print"})
Berrypod.Search.index_product(product)
{:ok, _view, html} = live(conn, ~p"/search?q=mountain")
assert html =~ "Blue Mountain Print"
assert html =~ "1 result"
end
test "renders no-results message for unmatched query", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/search?q=nonexistent")
assert html =~ "No products found"
end
test "search form submits via LiveView and updates URL", %{conn: conn} do
product =
ProductsFixtures.complete_product_fixture(%{title: "Red Sunset Poster"})
Berrypod.Search.index_product(product)
{:ok, view, _html} = live(conn, ~p"/search")
html =
view
|> form(".search-page-form", %{"q" => "sunset"})
|> render_submit()
assert html =~ "Red Sunset Poster"
end
end
end