from textwrap import dedent
from pytest import raises as assert_raises
from minihtml import Element, Fragment, Slots, component, fragment
from minihtml.tags import (
body,
div,
h2,
head,
html,
img,
main,
p,
script,
style,
title,
)
def test_basic_component():
@component()
def my_component(slots: Slots, name: str) -> Element:
return div(name=name)
with div["container"] as elem:
my_component(name="component-name")
assert str(elem) == dedent("""\
""")
def test_component_slot():
@component()
def my_component(slots: Slots, name: str) -> Element:
with div(name=name) as elem:
slots.slot()
return elem
with div["container"] as elem:
with my_component(name="component-name"):
p("slot content")
assert str(elem) == dedent("""\
""")
def test_named_slots():
@component(slots=("head", "main"))
def my_component(slots: Slots) -> Element:
with html as elem:
with head:
slots.slot("head")
with body:
with main:
slots.slot("main")
return elem
with my_component() as comp:
with comp.slot("head"):
title("My website")
with comp.slot("main"):
p("My article")
assert str(comp) == dedent("""\
My website
My article
""")
def test_component_without_default_raises_if_default_slot_is_used():
@component(slots=["one"])
def my_component(slots: Slots) -> Element:
with div as elem:
slots.slot("one")
return elem
with assert_raises(KeyError):
with my_component():
p("default slot content")
def test_named_slots_with_default():
@component(slots=("head", "main"), default="main")
def my_component(slots: Slots) -> Element:
with html as elem:
with head:
slots.slot("head")
with body:
with main:
slots.slot()
return elem
with my_component() as comp1:
with comp1.slot("head"):
title("My website")
p("My article")
assert str(comp1) == dedent("""\
My website
My article
""")
with my_component() as comp2:
with comp2.slot("head"):
title("My website")
with comp2.slot("main"):
p("My article")
assert str(comp1) == str(comp2)
def test_slot_is_filled():
@component(slots=("icon", "main"), default="main")
def my_component(slots: Slots) -> Element:
with div["my-component"] as elem:
if slots.is_filled("icon"):
with div["icon"]:
slots.slot("icon")
if slots.is_filled():
with div["main"]:
slots.slot()
return elem
with my_component() as comp1:
p("My article")
assert str(comp1) == dedent("""\
""")
with my_component() as comp2:
with comp2.slot("icon"):
img(src="icon.png")
assert str(comp2) == dedent("""\
""")
def test_slots_with_default_content():
@component(slots=("title", "content"), default="content")
def my_component(slots: Slots) -> Fragment:
with fragment() as f:
with slots.slot("title"):
h2("Default title")
with slots.slot():
p("Default content")
return f
comp1 = my_component()
with my_component() as comp2:
with comp2.slot("title"):
h2("My title")
p("My content")
assert str(comp1) == dedent("""\
Default title
Default content
""")
assert str(comp2) == dedent("""\
My title
My content
""")
def test_default_slot_must_be_a_valid_slot_name():
with assert_raises(ValueError, match="Can't set default without slots: 'x'"):
component(default="x")
with assert_raises(
ValueError, match="Invalid default: 'x'. Available slots: 'a', 'b'"
):
component(slots=("a", "b"), default="x")
def test_stringifying_component_has_no_side_effect():
@component()
def my_component(slots: Slots) -> Element:
with div["my-component"] as elem:
slots.slot()
return elem
c1 = my_component()
with div as elem:
str(c1)
assert str(elem) == ""
def test_nested_components():
@component()
def inner(slots: Slots) -> Element:
with div["inner"] as elem:
slots.slot()
return elem
@component()
def outer(slots: Slots) -> Element:
with div["outer"] as elem:
with inner():
slots.slot()
return elem
with div["container"] as elem:
with outer():
p("content")
assert str(elem) == dedent("""\
""")
def test_component_style_and_script_has_no_effect_outside_of_template_context():
@component(
style=style(".my-component { background: #ccc }"),
script=script("// script goes here"),
)
def my_component(slots: Slots) -> Element:
return div["my-component"]
assert str(my_component()) == ''
def test_passing_component_as_argument():
@component()
def my_component(slots: Slots) -> Element:
return div["my-component"]
with div["#container"] as elem:
div(my_component())
assert str(elem) == dedent("""\
""")