diff --git a/test/aprsme_web/components/core_components_test.exs b/test/aprsme_web/components/core_components_test.exs index c084aa3..ad1dff5 100644 --- a/test/aprsme_web/components/core_components_test.exs +++ b/test/aprsme_web/components/core_components_test.exs @@ -279,10 +279,218 @@ defmodule AprsmeWeb.CoreComponentsTest do test "show_modal returns a JS struct" do assert %JS{} = CoreComponents.show_modal("my-modal") end + + test "hide_modal returns a JS struct" do + assert %JS{} = CoreComponents.hide_modal("my-modal") + end + end + + describe "translate_error/1" do + test "passes plain error tuples through gettext" do + # No :count opt → uses dgettext. + result = CoreComponents.translate_error({"is invalid", []}) + assert is_binary(result) + assert result =~ "invalid" + end + + test "uses dngettext for plural errors" do + result = CoreComponents.translate_error({"should be %{count} character(s)", [count: 5]}) + assert is_binary(result) + assert result =~ "5" + end + end + + describe "translate_errors/2" do + test "returns translated errors for the given field" do + errors = [ + {:name, {"can't be blank", []}}, + {:age, {"is not a number", []}}, + {:name, {"is too short", []}} + ] + + name_errors = CoreComponents.translate_errors(errors, :name) + assert length(name_errors) == 2 + assert Enum.all?(name_errors, &is_binary/1) + end + + test "returns an empty list when no errors match the field" do + assert CoreComponents.translate_errors([{:other, {"x", []}}], :missing) == [] + end + end + + describe "modal/1" do + test "renders a modal with the inner block and close button" do + html = + render_component(&CoreComponents.modal/1, %{ + id: "test-modal", + show: false, + inner_block: text_slot("Modal body content"), + title: [], + subtitle: [], + confirm: [], + cancel: [], + on_confirm: %JS{}, + on_cancel: %JS{} + }) + + assert html =~ ~s(id="test-modal") + assert html =~ "Modal body content" + assert html =~ ~s(aria-modal="true") + assert html =~ ~s(aria-label="close") + end + + test "renders the title and subtitle slots when supplied" do + html = + render_component(&CoreComponents.modal/1, %{ + id: "sample-modal", + show: false, + inner_block: text_slot(""), + title: slot_with_text(:title, "My Modal Title"), + subtitle: slot_with_text(:subtitle, "My subtitle"), + confirm: [], + cancel: [], + on_confirm: %JS{}, + on_cancel: %JS{} + }) + + assert html =~ "My Modal Title" + assert html =~ "My subtitle" + end + end + + describe "table/1" do + test "renders a row for each entry in :rows" do + html = + render_component(&CoreComponents.table/1, %{ + id: "users", + rows: [%{id: 1, name: "Alice"}, %{id: 2, name: "Bob"}], + row_click: nil, + col: [ + %{ + __slot__: :col, + label: "Name", + inner_block: fn _changed, user -> user.name end + } + ], + action: [] + }) + + assert html =~ "Alice" + assert html =~ "Bob" + assert html =~ ~s(id="users") + assert html =~ "Name" + end + + test "renders action slot when provided" do + html = + render_component(&CoreComponents.table/1, %{ + id: "users", + rows: [%{id: 1, name: "Alice"}], + row_click: nil, + col: [ + %{ + __slot__: :col, + label: "Name", + inner_block: fn _changed, user -> user.name end + } + ], + action: [ + %{ + __slot__: :action, + inner_block: fn _changed, _user -> "Edit" end + } + ] + }) + + assert html =~ "Edit" + end + end + + describe "list/1" do + test "renders a description list with each item" do + html = + render_component(&CoreComponents.list/1, %{ + item: [ + %{ + __slot__: :item, + title: "First", + inner_block: fn _changed, _ -> "alpha" end + }, + %{ + __slot__: :item, + title: "Second", + inner_block: fn _changed, _ -> "beta" end + } + ] + }) + + assert html =~ "First" + assert html =~ "alpha" + assert html =~ "Second" + assert html =~ "beta" + end + end + + describe "back/1" do + test "renders a back link with the given navigate target" do + html = + render_component(&CoreComponents.back/1, %{ + navigate: "/somewhere", + inner_block: text_slot("Go back") + }) + + assert html =~ "Go back" + assert html =~ ~s(href="/somewhere") + end + end + + describe "simple_form/1" do + test "renders a form with action buttons" do + html = + render_component(&CoreComponents.simple_form/1, %{ + for: %{}, + as: :user, + rest: %{}, + inner_block: text_slot("form fields"), + actions: [ + %{ + __slot__: :actions, + inner_block: fn _changed, _ -> "Save" end + } + ] + }) + + assert html =~ "