defmodule Dsl.HtmlTest do use ExUnit.Case, async: true use Dsl defmodule Component do defcomponent :flex do div(class: "flex") end defcomponent :takes_children do div do div(id: "static-child-1") @children div(id: "static-child-2") end end defcomponent :arbitrary_code do num = 1..10 |> Enum.reduce(0, fn x, sum -> x + sum end) div do text(num) end end defcomponent :uses_conditionals do if @condition do div() else span() end end defcomponent :arbitrary_data do for item <- @lists do div do text(inspect(item)) end end end defcomponent :safe do div() end defcomponent :safe_with_prop do div id: "safe-with-prop" do text(@prop) div do span do for x <- @lists do div(do: text(x)) end end end end end defcomponent :variable_as_prop do div id: @bob end defcomponent :variable_as_prop_with_block do div id: @bob do @children end end end describe "non-void elements" do test "renders two divs" do {:safe, result} = htm do div() div() end assert result == "
" end test "renders two els in the right order" do {:safe, result} = htm do div() span() end assert result == "
" end test "renders an el that taks attrs and a block" do {:safe, result} = htm do div class: "bob" do span() span() end end assert result == ~s{
} end test "renders one els nested inside an el" do {:safe, result} = htm do div do span() end end assert result == "
" end test "renders two els nested inside an el" do {:safe, result} = htm do div do span() span() end end assert result == "
" end test "renders two divs that are rendered by a loop" do {:safe, result} = htm do for _ <- 1..2 do div() end end assert result == "
" end test "renders two spans" do {:safe, result} = htm do span() span() end assert result == "" end test "renders a div within a div" do {:safe, result} = htm do div do div() end end assert result == "
" end test "renders an attribute on a div" do {:safe, result} = htm do div class: "hello" do div(class: "hi") end end assert result == ~s{
} end test "renders an attribute on a div passed as a variable" do attrs1 = [class: "hello"] attrs2 = [class: "hi"] {:safe, result} = htm do div attrs1 do div(attrs2) end end assert result == ~s{
} end test "renders multiple attributes on a div without block" do {:safe, result} = htm do div(class: "hello", id: "12") end assert result == ~s{
} end test "can accept content as the first argument" do {:safe, result} = htm do div("CONTENT") div("MORE", class: "hi") end assert result == ~s{
CONTENT
MORE
} end test "can accept content as first argument passed as a variable" do content = "CONTENT" more = "MORE" {:safe, result} = htm do div(content) div(more, class: "hi") end assert result == ~s{
CONTENT
MORE
} end end describe "void elements" do test "renders an input" do {:safe, result} = htm do input() end assert result == ~s{} end test "renders an input with an attribute" do {:safe, result} = htm do input(type: "number") end assert result == ~s{} end end describe "escaping" do test "text is excaped" do {:safe, result} = htm do text("
Text
") end assert result == ~s{<div>Text</div>} end end describe "data attributes" do test "can have one data attributes" do {:safe, result} = htm do div(data_controller: "stimulus-controller") end assert result == ~s{
} end test "can have multiple data attributes" do {:safe, result} = htm do div(data_controller: "stimulus-controller", data_target: "stimulus-target") end assert result == ~s{
} end end describe "custom component" do test "defines a basic component" do import Component {:safe, result} = htm do flex() end assert result == ~s{
} end test "defines a component that takes 1 child" do import Component {:safe, result} = htm do takes_children do div(id: "dynamic-child") end end assert result == ~s{
} end test "defines a component that takes multiple children" do import Component {:safe, result} = htm do takes_children do div(id: "dynamic-child-1") div(id: "dynamic-child-2") end end assert result == ~s{
} end test "can access a prop" do import Component {:safe, result} = htm do takes_children name: "mitch" do text(@name) end end assert result == ~s{
mitch
} end test "can have arbitrary code inside the definition" do import Component {:safe, result} = htm do arbitrary_code() end assert result == ~s{
55
} end test "can use conditionals to render different markup" do import Component {:safe, result} = htm do uses_conditionals(condition: true) uses_conditionals(condition: false) end assert result == ~s{
} end test "can pass arbitrary data as props" do import Component {:safe, result} = htm do arbitrary_data( lists: [:atom, %{key: "value"}, {:status, :tuple}, "string", 1, [1, 2, 3]] ) end assert result == ~s|
:atom
%{key: "value"}
{:status, :tuple}
"string"
1
[1, 2, 3]
| end test "can pass a variable as a prop" do import Component bob = "hi" {:safe, result} = htm do variable_as_prop bob: bob end assert result == ~s|
| end test "can pass a variable as a prop to a component with a block" do import Component bob = "hi" class = "joe" {:safe, result} = htm do variable_as_prop_with_block bob: bob do div() end end assert result == ~s|
| end test "can use string interpolation in props" do interop = "hi" {:safe, result} = htm do div(class: "#{interop} world") end assert result == ~s{
} end end end