defmodule BerrypodWeb.PageEditorHookTest do use BerrypodWeb.ConnCase, async: false import Phoenix.LiveViewTest import Berrypod.AccountsFixtures import Berrypod.ProductsFixtures alias Berrypod.Pages alias Berrypod.Pages.PageCache setup do PageCache.invalidate_all() user = user_fixture() {:ok, _} = Berrypod.Settings.set_site_live(true) provider_conn = provider_connection_fixture() product = product_fixture(%{ provider_connection: provider_conn, title: "Test Product", category: "Test Category" }) product_variant_fixture(%{product: product, title: "Standard", price: 1999}) Berrypod.Products.recompute_cached_fields(product) %{user: user, product: product} end describe "non-admin cannot access edit mode" do test "visiting with ?edit=true shows normal page, no sidebar", %{conn: conn} do {:ok, _view, html} = live(conn, "/?edit=true") refute html =~ "page-editor-sidebar" refute html =~ "page-editor-live" end end describe "edit button visibility" do test "admin sees edit pencil in shop header", %{conn: conn, user: user} do conn = log_in_user(conn, user) {:ok, _view, html} = live(conn, "/") assert html =~ "Edit page" end test "non-admin does not see edit pencil", %{conn: conn} do {:ok, _view, html} = live(conn, "/") refute html =~ "Edit page" end end describe "entering and exiting edit mode" do setup %{conn: conn, user: user} do %{conn: log_in_user(conn, user)} end test "admin enters edit mode with ?edit=true", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") assert has_element?(view, ".page-editor-sidebar") assert has_element?(view, ".page-editor-content") assert has_element?(view, ".block-card") end test "sidebar shows the page title", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") assert has_element?(view, ".page-editor-sidebar-title", "Home page") end test "done button exits edit mode", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") # editor_done uses push_navigate, which causes a redirect {:error, {:live_redirect, %{to: "/"}}} = view |> element("button[phx-click='editor_done']") |> render_click() end test "toggle sidebar hides and shows via header pencil", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") # Sidebar starts open, pencil button in header is hidden assert has_element?(view, "[data-sidebar-open='true']") refute has_element?( view, "button[phx-click='editor_toggle_sidebar'][aria-label='Show editor sidebar']" ) # Close the sidebar via the X button view |> element("button[phx-click='editor_toggle_sidebar'][aria-label='Close sidebar']") |> render_click() assert has_element?(view, "[data-sidebar-open='false']") # Pencil button appears in header to re-open assert has_element?( view, "button[phx-click='editor_toggle_sidebar'][aria-label='Show editor sidebar']" ) # Re-open via pencil in header view |> element("button[phx-click='editor_toggle_sidebar'][aria-label='Show editor sidebar']") |> render_click() assert has_element?(view, "[data-sidebar-open='true']") end test "clicking backdrop hides the sidebar", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") # Backdrop present when sidebar is open assert has_element?(view, ".page-editor-backdrop") # Click backdrop to dismiss view |> element(".page-editor-backdrop") |> render_click() assert has_element?(view, "[data-sidebar-open='false']") # Backdrop gone when sidebar is hidden refute has_element?(view, ".page-editor-backdrop") end end describe "block manipulation in edit mode" do setup %{conn: conn, user: user} do %{conn: log_in_user(conn, user)} end test "move block down reorders the list", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") # Home page default: hero is first block first_card = view |> element(".block-card:first-child") first_html = render(first_card) assert first_html =~ "Hero" # Get the hero block's ID and move it down blocks = Pages.get_page("home").blocks hero_id = List.first(blocks)["id"] view |> element("button[phx-click='editor_move_down'][phx-value-id='#{hero_id}']") |> render_click() # After move, hero is no longer the first card updated_first = view |> element(".block-card:first-child") |> render() refute updated_first =~ "Hero" end test "dirty indicator appears after changes", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") refute has_element?(view, ".admin-badge-warning", "Unsaved changes") # Move a block to trigger dirty state blocks = Pages.get_page("home").blocks second_id = Enum.at(blocks, 1)["id"] view |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']") |> render_click() assert has_element?(view, ".admin-badge-warning", "Unsaved changes") end end describe "save and reset" do setup %{conn: conn, user: user} do %{conn: log_in_user(conn, user)} end test "save persists block changes", %{conn: conn} do {:ok, view, _html} = live(conn, "/?edit=true") # Move a block to make changes blocks = Pages.get_page("home").blocks original_first_type = List.first(blocks)["type"] second_id = Enum.at(blocks, 1)["id"] view |> element("button[phx-click='editor_move_up'][phx-value-id='#{second_id}']") |> render_click() # Save view |> element("button[phx-click='editor_save']") |> render_click() assert has_element?(view, "#shop-flash-info", "Page saved") # Verify persistence updated = Pages.get_page("home") refute List.first(updated.blocks)["type"] == original_first_type end test "reset restores default blocks", %{conn: conn} do # First, save a modified page original = Pages.get_page("home") reordered = Enum.reverse(original.blocks) Pages.save_page("home", %{title: original.title, blocks: reordered}) PageCache.invalidate_all() {:ok, view, _html} = live(conn, "/?edit=true") # Reset view |> element("button[phx-click='editor_reset_defaults']") |> render_click() assert has_element?(view, "#shop-flash-info", "Page reset to defaults") # Verify the blocks are back to defaults reset_page = Pages.get_page("home") assert List.first(reset_page.blocks)["type"] == List.first(original.blocks)["type"] end end describe "content pages (deferred init)" do setup %{conn: conn, user: user} do %{conn: log_in_user(conn, user)} end test "editing works on about page via deferred init", %{conn: conn} do {:ok, view, _html} = live(conn, "/about?edit=true") assert has_element?(view, ".page-editor-sidebar") assert has_element?(view, ".page-editor-sidebar-title", "About") assert has_element?(view, ".block-card") end end end