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