defmodule BerrypodWeb.PageRendererTest do use BerrypodWeb.ConnCase, async: false import Phoenix.LiveViewTest alias Berrypod.Pages alias Berrypod.Settings.ThemeSettings alias BerrypodWeb.PageRenderer # Minimal assigns that every page needs (the stuff shop_layout requires) defp base_assigns do %{ __changed__: nil, theme_settings: %ThemeSettings{}, logo_image: nil, header_image: nil, mode: :shop, cart_items: [], cart_count: 0, cart_subtotal: "£0.00", cart_total: nil, cart_drawer_open: false, cart_status: nil, is_admin: false, search_query: "", search_results: [], search_open: false, categories: [], shipping_estimate: nil, country_code: "GB", available_countries: [], flash: %{} } end defp render_page(slug, extra_assigns \\ %{}) do page = Pages.get_page(slug) assigns = base_assigns() |> Map.merge(extra_assigns) |> Map.put(:page, page) PageRenderer.render_page(assigns) |> rendered_to_string() end describe "render_page/1" do test "home page renders hero and featured products" do html = render_page("home", %{products: []}) assert html =~ "Original designs, printed on demand" assert html =~ "Shop the collection" assert html =~ "Featured products" assert html =~ "Made with passion, printed with care" end test "about page renders hero and content area" do html = render_page("about", %{content_blocks: [%{type: :paragraph, text: "Test about text"}]}) assert html =~ "About the studio" assert html =~ "content-body" end test "delivery page renders hero" do html = render_page("delivery", %{content_blocks: []}) assert html =~ "Delivery & returns" end test "privacy page renders hero" do html = render_page("privacy", %{content_blocks: []}) assert html =~ "Privacy policy" end test "terms page renders hero" do html = render_page("terms", %{content_blocks: []}) assert html =~ "Terms of service" end test "contact page renders hero, form, and sidebar blocks" do html = render_page("contact", %{tracking_state: :idle}) assert html =~ "Get in touch" assert html =~ "Send a message" assert html =~ "Track your order" assert html =~ "Handy to know" assert html =~ "Newsletter" end test "collection page renders header, filter bar, and grid" do html = render_page("collection", %{products: [], collection_title: "All Products"}) assert html =~ "All Products" assert html =~ "filter-bar" end test "pdp page renders breadcrumb and product hero when product provided" do product = %{ id: "test-id", title: "Test Product", slug: "test-product", category: "Art Prints", description: "A lovely test product", cheapest_price: 2500, compare_at_price: nil, on_sale: false, in_stock: true, provider_data: %{} } html = render_page("pdp", %{ product: product, gallery_images: [], display_price: 2500, selected_variant: nil, option_types: [], selected_options: %{}, available_options: %{}, option_urls: %{}, quantity: 1, related_products: [], reviews: [], average_rating: 5, total_count: 0 }) assert html =~ "Art Prints" assert html =~ "Test Product" assert html =~ "pdp-grid" assert html =~ "Add to basket" end test "cart page renders empty state when no items" do html = render_page("cart") assert html =~ "Your basket" assert html =~ "cart-empty" end test "cart page renders items when present" do items = [ %{ variant_id: "v1", name: "Test T-Shirt", variant: "Black / M", price: 2500, quantity: 1, image: nil, product_id: "test-t-shirt", in_stock: true } ] html = render_page("cart", %{ cart_items: items, cart_count: 1, cart_subtotal: "£25.00", cart_page_subtotal: 2500 }) assert html =~ "Your basket" assert html =~ "cart-page-list" end test "search page renders search form" do html = render_page("search", %{search_page_query: "", search_page_results: []}) assert html =~ "Search" assert html =~ ~s(name="q") assert html =~ "Search products..." end test "checkout success renders pending state when no order" do html = render_page("checkout_success", %{order: nil}) assert html =~ "Processing your payment" end test "orders page renders empty state when orders nil" do html = render_page("orders", %{orders: nil, lookup_email: nil}) assert html =~ "Your orders" assert html =~ "expired or is invalid" end test "orders page renders no orders message" do html = render_page("orders", %{orders: [], lookup_email: "test@example.com"}) assert html =~ "test@example.com" assert html =~ "No orders found" end test "order detail page renders nothing when no order" do html = render_page("order_detail", %{order: nil}) # Should not crash, just render empty assert html =~ "main" end test "error page renders error hero" do html = render_page("error", %{ error_code: "404", error_title: "Page not found", error_description: "Sorry, we couldn't find that page.", products: [] }) assert html =~ "404" assert html =~ "Page not found" assert html =~ "Go to Homepage" end end describe "page_main_class/1" do test "returns correct classes for each page" do assert PageRenderer.page_main_class("contact") == "page-container contact-main" assert PageRenderer.page_main_class("cart") == "page-container" assert PageRenderer.page_main_class("checkout_success") == "page-container checkout-main" assert PageRenderer.page_main_class("orders") == "page-container orders-main" assert PageRenderer.page_main_class("order_detail") == "page-container order-detail-main" assert PageRenderer.page_main_class("error") == "error-main" assert PageRenderer.page_main_class("about") == "content-page" assert PageRenderer.page_main_class("home") == nil end end describe "utility blocks" do setup do on_exit(fn -> import Ecto.Query Berrypod.Repo.delete_all(from p in Berrypod.Pages.Page, where: p.slug == "home") Berrypod.Pages.PageCache.invalidate_all() end) :ok end test "spacer block renders with size" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [%{"id" => "blk_sp", "type" => "spacer", "settings" => %{"size" => "large"}}] }) html = render_page("home", %{products: []}) assert html =~ ~s(class="block-spacer") assert html =~ ~s(data-size="large") end test "divider block renders with style" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [%{"id" => "blk_dv", "type" => "divider", "settings" => %{"style" => "dots"}}] }) html = render_page("home", %{products: []}) assert html =~ ~s(class="block-divider") assert html =~ ~s(data-style="dots") end test "button block renders themed link" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [ %{ "id" => "blk_btn", "type" => "button", "settings" => %{ "text" => "Shop now", "href" => "/collections/all", "style" => "primary", "alignment" => "centre" } } ] }) html = render_page("home", %{products: []}) assert html =~ "Shop now" assert html =~ ~s(data-align="centre") assert html =~ "themed-button" end test "video embed renders YouTube iframe" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [ %{ "id" => "blk_vid", "type" => "video_embed", "settings" => %{ "url" => "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "caption" => "Demo video" } } ] }) html = render_page("home", %{products: []}) assert html =~ "youtube-nocookie.com/embed/dQw4w9WgXcQ" assert html =~ "Demo video" assert html =~ "video-embed" end test "video embed renders Vimeo iframe" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [ %{ "id" => "blk_vim", "type" => "video_embed", "settings" => %{"url" => "https://vimeo.com/123456789"} } ] }) html = render_page("home", %{products: []}) assert html =~ "player.vimeo.com/video/123456789" end test "video embed shows fallback link for unknown URLs" do {:ok, _} = Pages.save_page("home", %{ title: "Home", blocks: [ %{ "id" => "blk_unk", "type" => "video_embed", "settings" => %{"url" => "https://example.com/video", "caption" => "My video"} } ] }) html = render_page("home", %{products: []}) assert html =~ "video-embed-fallback" assert html =~ "My video" refute html =~ "