diff --git a/app/test/firehose_web/components/core_components_test.exs b/app/test/firehose_web/components/core_components_test.exs new file mode 100644 index 0000000..dc3d46e --- /dev/null +++ b/app/test/firehose_web/components/core_components_test.exs @@ -0,0 +1,226 @@ +defmodule FirehoseWeb.CoreComponentsTest do + # Pure render tests: no conn, no database, so plain ExUnit.Case (the same + # choice layouts_test.exs makes) instead of the ConnCase sandbox. + use ExUnit.Case, async: true + + import Phoenix.LiveViewTest + + alias FirehoseWeb.CoreComponents + + @checkbox_assigns %{ + type: "checkbox", + name: "prefs[news]", + id: "prefs_news", + label: "News", + value: "true", + rest: %{}, + errors: [], + field: nil + } + + @select_assigns %{ + type: "select", + name: "role", + id: "role", + label: "Role", + prompt: "Pick one", + options: [{"Admin", "admin"}, {"Editor", "editor"}], + value: "admin", + multiple: false, + rest: %{}, + errors: [], + field: nil + } + + @textarea_assigns %{ + type: "textarea", + name: "body", + id: "body", + label: "Body", + value: "hello world", + rest: %{}, + errors: [], + field: nil + } + + describe "input/1 checkbox" do + test "a checked box renders checked when the value is true" do + html = render_checkbox(%{}) + + assert attr(html, "input[type='checkbox']", "name") == "prefs[news]" + assert attr(html, "input[type='checkbox']", "value") == "true" + assert attr(html, "input[type='checkbox']", "checked") == "" + assert text(html) =~ "News" + end + + test "an unchecked box still posts false for the field" do + html = render_checkbox(%{value: "false"}) + + assert attr(html, "input[type='checkbox']", "checked") == nil + + # Markup is the behaviour here: the hidden field carrying the same name is + # what makes an unchecked box post "false" instead of posting nothing. + assert attr(html, "input[type='hidden']", "name") == "prefs[news]" + assert attr(html, "input[type='hidden']", "value") == "false" + end + + test "shows the error message when the field has errors" do + html = render_checkbox(%{errors: ["can't be blank"]}) + + assert text(html) =~ "can't be blank" + end + end + + describe "input/1 select" do + test "renders the prompt, every option, and preselects the current value" do + html = render_select(%{}) + + assert text(html) =~ "Pick one" + assert text(html) =~ "Admin" + assert text(html) =~ "Editor" + # The outcome, not the serialisation: the option carrying the current + # value is selected, the other one is not. + assert attr(html, "option[value='admin']", "selected") == "" + assert attr(html, "option[value='editor']", "selected") == nil + end + + test "marks the select erroneous and shows the message when given errors" do + html = render_select(%{errors: ["is invalid"]}) + + assert text(html) =~ "is invalid" + assert "select-error" in classes(html, "select") + end + end + + describe "input/1 textarea" do + test "keeps the value inside the textarea" do + html = render_textarea(%{value: "hello world"}) + + # normalize_value/2 prefixes the content with a newline, so compare the + # trimmed text: what matters is the value, not the surrounding whitespace. + assert String.trim(text(html, "textarea")) == "hello world" + end + + test "renders an empty textarea for a nil value instead of the text nil" do + html = render_textarea(%{value: nil}) + + assert String.trim(text(html, "textarea")) == "" + refute html =~ "nil" + end + + test "keeps a leading newline in the value" do + # HTML drops one leading newline of a