refactor: refactor tests to create components inside test functions (#1027)

This commit is contained in:
Juro Oravec 2025-03-17 11:06:32 +01:00 committed by GitHub
parent 8e7acd82be
commit ebfb26121a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 231 additions and 223 deletions

View file

@ -13,21 +13,17 @@ from .testutils import PARAMETRIZE_CONTEXT_BEHAVIOR, setup_test_config
setup_test_config({"autodiscover": False}) setup_test_config({"autodiscover": False})
class SlottedComponent(Component): def _gen_slotted_component():
template: types.django_html = """ class SlottedComponent(Component):
{% load component_tags %} template: types.django_html = """
<custom-template> {% load component_tags %}
<header>{% slot "header" %}Default header{% endslot %}</header> <custom-template>
<main>{% slot "main" %}Default main{% endslot %}</main> <header>{% slot "header" %}Default header{% endslot %}</header>
<footer>{% slot "footer" %}Default footer{% endslot %}</footer> <main>{% slot "main" %}Default main{% endslot %}</main>
</custom-template> <footer>{% slot "footer" %}Default footer{% endslot %}</footer>
""" </custom-template>
"""
return SlottedComponent
class SlottedComponentWithContext(SlottedComponent):
def get_context_data(self, variable):
return {"variable": variable}
####################### #######################
# TESTS # TESTS
@ -38,7 +34,7 @@ class SlottedComponentWithContext(SlottedComponent):
class TestComponentSlot: class TestComponentSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_slotted_template_basic(self, components_settings): def test_slotted_template_basic(self, components_settings):
registry.register(name="test1", component=SlottedComponent) registry.register(name="test1", component=_gen_slotted_component())
@register("test2") @register("test2")
class SimpleComponent(Component): class SimpleComponent(Component):
@ -145,7 +141,19 @@ class TestComponentSlot:
) )
) )
def test_slotted_template_with_context_var(self, components_settings, expected): def test_slotted_template_with_context_var(self, components_settings, expected):
registry.register(name="test1", component=SlottedComponentWithContext) @register("test1")
class SlottedComponentWithContext(Component):
template: types.django_html = """
{% load component_tags %}
<custom-template>
<header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "main" %}Default main{% endslot %}</main>
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
</custom-template>
"""
def get_context_data(self, variable):
return {"variable": variable}
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -176,7 +184,7 @@ class TestComponentSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_slotted_template_no_slots_filled(self, components_settings): def test_slotted_template_no_slots_filled(self, components_settings):
registry.register(name="test", component=SlottedComponent) registry.register(name="test", component=_gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -232,7 +240,7 @@ class TestComponentSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_variable_fill_name(self, components_settings): def test_variable_fill_name(self, components_settings):
registry.register(name="test", component=SlottedComponent) registry.register(name="test", component=_gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% with slotname="header" %} {% with slotname="header" %}
@ -697,7 +705,7 @@ class TestComponentSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_fill_tag_can_occur_within_component_nested_in_implicit_fill(self, components_settings): def test_fill_tag_can_occur_within_component_nested_in_implicit_fill(self, components_settings):
registry.register("slotted", SlottedComponent) registry.register("slotted", _gen_slotted_component())
@register("test_comp") @register("test_comp")
class ComponentWithDefaultSlot(Component): class ComponentWithDefaultSlot(Component):
@ -792,7 +800,7 @@ class TestComponentSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_implicit_fill_when_no_slot_marked_default(self, components_settings): def test_implicit_fill_when_no_slot_marked_default(self, components_settings):
registry.register("test_comp", SlottedComponent) registry.register("test_comp", _gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test_comp' %} {% component 'test_comp' %}
@ -1052,7 +1060,7 @@ class TestPassthroughSlots:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_passthrough_slots(self, components_settings): def test_passthrough_slots(self, components_settings):
registry.register("slotted", SlottedComponent) registry.register("slotted", _gen_slotted_component())
@register("test_comp") @register("test_comp")
class OuterComp(Component): class OuterComp(Component):
@ -1103,7 +1111,7 @@ class TestPassthroughSlots:
# with current implementation. So this tests serves as a documentation of the current behavior. # with current implementation. So this tests serves as a documentation of the current behavior.
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_passthrough_slots_unknown_fills_ignored(self, components_settings): def test_passthrough_slots_unknown_fills_ignored(self, components_settings):
registry.register("slotted", SlottedComponent) registry.register("slotted", _gen_slotted_component())
@register("test_comp") @register("test_comp")
class OuterComp(Component): class OuterComp(Component):
@ -1154,34 +1162,36 @@ class TestPassthroughSlots:
# See https://github.com/django-components/django-components/issues/698 # See https://github.com/django-components/django-components/issues/698
@djc_test @djc_test
class TestNestedSlots: class TestNestedSlots:
class NestedSlots(Component): def _gen_nested_slots_component(self):
template: types.django_html = """ class NestedSlots(Component):
{% load component_tags %} template: types.django_html = """
{% slot 'wrapper' %} {% load component_tags %}
<div> {% slot 'wrapper' %}
Wrapper Default <div>
{% slot 'parent1' %} Wrapper Default
<div> {% slot 'parent1' %}
Parent1 Default <div>
{% slot 'child1' %} Parent1 Default
<div> {% slot 'child1' %}
Child 1 Default <div>
</div> Child 1 Default
{% endslot %} </div>
</div> {% endslot %}
{% endslot %} </div>
{% slot 'parent2' %} {% endslot %}
<div> {% slot 'parent2' %}
Parent2 Default <div>
</div> Parent2 Default
{% endslot %} </div>
</div> {% endslot %}
{% endslot %} </div>
""" {% endslot %}
"""
return NestedSlots
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_empty(self, components_settings): def test_empty(self, components_settings):
registry.register("example", self.NestedSlots) registry.register("example", self._gen_nested_slots_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'example' %} {% component 'example' %}
@ -1207,7 +1217,7 @@ class TestNestedSlots:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_override_outer(self, components_settings): def test_override_outer(self, components_settings):
registry.register("example", self.NestedSlots) registry.register("example", self._gen_nested_slots_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'example' %} {% component 'example' %}
@ -1229,7 +1239,7 @@ class TestNestedSlots:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_override_middle(self, components_settings): def test_override_middle(self, components_settings):
registry.register("example", self.NestedSlots) registry.register("example", self._gen_nested_slots_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'example' %} {% component 'example' %}
@ -1257,7 +1267,7 @@ class TestNestedSlots:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_override_inner(self, components_settings): def test_override_inner(self, components_settings):
registry.register("example", self.NestedSlots) registry.register("example", self._gen_nested_slots_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'example' %} {% component 'example' %}
@ -1288,7 +1298,7 @@ class TestNestedSlots:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_override_all(self, components_settings): def test_override_all(self, components_settings):
registry.register("example", self.NestedSlots) registry.register("example", self._gen_nested_slots_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'example' %} {% component 'example' %}
@ -1358,7 +1368,7 @@ class TestSlottedTemplateRegression:
class TestSlotDefault: class TestSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_basic(self, components_settings): def test_basic(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component "test" %} {% component "test" %}
@ -1383,7 +1393,7 @@ class TestSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_multiple_calls(self, components_settings): def test_multiple_calls(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component "test" %} {% component "test" %}
@ -1409,7 +1419,7 @@ class TestSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_under_if_and_forloop(self, components_settings): def test_under_if_and_forloop(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component "test" %} {% component "test" %}
@ -1440,7 +1450,7 @@ class TestSlotDefault:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_nested_fills(self, components_settings): def test_nested_fills(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component "test" %} {% component "test" %}
@ -1954,61 +1964,67 @@ class TestScopedSlot:
@djc_test @djc_test
class TestDuplicateSlot: class TestDuplicateSlot:
class DuplicateSlotComponent(Component): def _gen_duplicate_slot_component(self):
template: types.django_html = """ class DuplicateSlotComponent(Component):
{% load component_tags %} template: types.django_html = """
<header>{% slot "header" %}Default header{% endslot %}</header> {% load component_tags %}
{# Slot name 'header' used twice. #} <header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "header" %}Default main header{% endslot %}</main> {# Slot name 'header' used twice. #}
<footer>{% slot "footer" %}Default footer{% endslot %}</footer> <main>{% slot "header" %}Default main header{% endslot %}</main>
""" <footer>{% slot "footer" %}Default footer{% endslot %}</footer>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
return { return {
"name": name, "name": name,
} }
return DuplicateSlotComponent
class DuplicateSlotNestedComponent(Component): def _gen_duplicate_slot_nested_component(self):
template: types.django_html = """ class DuplicateSlotNestedComponent(Component):
{% load component_tags %} template: types.django_html = """
{% slot "header" %}START{% endslot %} {% load component_tags %}
<div class="dashboard-component"> {% slot "header" %}START{% endslot %}
{% component "calendar" date="2020-06-06" %} <div class="dashboard-component">
{% fill "header" %} {# fills and slots with same name relate to diff. things. #} {% component "calendar" date="2020-06-06" %}
{% slot "header" %}NESTED{% endslot %} {% fill "header" %} {# fills and slots with same name relate to diff. things. #}
{% endfill %} {% slot "header" %}NESTED{% endslot %}
{% fill "body" %}Here are your to-do items for today:{% endfill %} {% endfill %}
{% endcomponent %} {% fill "body" %}Here are your to-do items for today:{% endfill %}
<ol> {% endcomponent %}
{% for item in items %} <ol>
<li>{{ item }}</li> {% for item in items %}
{% slot "header" %}LOOP {{ item }} {% endslot %} <li>{{ item }}</li>
{% endfor %} {% slot "header" %}LOOP {{ item }} {% endslot %}
</ol> {% endfor %}
</div> </ol>
""" </div>
"""
def get_context_data(self, items: List) -> Dict[str, Any]: def get_context_data(self, items: List) -> Dict[str, Any]:
return { return {
"items": items, "items": items,
} }
return DuplicateSlotNestedComponent
class CalendarComponent(Component): def _gen_calendar_component(self):
"""Nested in ComponentWithNestedComponent""" class CalendarComponent(Component):
"""Nested in ComponentWithNestedComponent"""
template: types.django_html = """ template: types.django_html = """
{% load component_tags %} {% load component_tags %}
<div class="calendar-component"> <div class="calendar-component">
<h1> <h1>
{% slot "header" %}Today's date is <span>{{ date }}</span>{% endslot %} {% slot "header" %}Today's date is <span>{{ date }}</span>{% endslot %}
</h1> </h1>
<main> <main>
{% slot "body" %} {% slot "body" %}
You have no events today. You have no events today.
{% endslot %} {% endslot %}
</main> </main>
</div> </div>
""" """
return CalendarComponent
# NOTE: Second arg is the input for the "name" component kwarg # NOTE: Second arg is the input for the "name" component kwarg
@djc_test( @djc_test(
@ -2024,8 +2040,8 @@ class TestDuplicateSlot:
) )
) )
def test_duplicate_slots(self, components_settings, input): def test_duplicate_slots(self, components_settings, input):
registry.register(name="duplicate_slot", component=self.DuplicateSlotComponent) registry.register(name="duplicate_slot", component=self._gen_duplicate_slot_component())
registry.register(name="calendar", component=self.CalendarComponent) registry.register(name="calendar", component=self._gen_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -2052,8 +2068,8 @@ class TestDuplicateSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_duplicate_slots_fallback(self, components_settings): def test_duplicate_slots_fallback(self, components_settings):
registry.register(name="duplicate_slot", component=self.DuplicateSlotComponent) registry.register(name="duplicate_slot", component=self._gen_duplicate_slot_component())
registry.register(name="calendar", component=self.CalendarComponent) registry.register(name="calendar", component=self._gen_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -2075,8 +2091,8 @@ class TestDuplicateSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_duplicate_slots_nested(self, components_settings): def test_duplicate_slots_nested(self, components_settings):
registry.register(name="duplicate_slot_nested", component=self.DuplicateSlotNestedComponent) registry.register(name="duplicate_slot_nested", component=self._gen_duplicate_slot_nested_component())
registry.register(name="calendar", component=self.CalendarComponent) registry.register(name="calendar", component=self._gen_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -2118,8 +2134,8 @@ class TestDuplicateSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_duplicate_slots_nested_fallback(self, components_settings): def test_duplicate_slots_nested_fallback(self, components_settings):
registry.register(name="duplicate_slot_nested", component=self.DuplicateSlotNestedComponent) registry.register(name="duplicate_slot_nested", component=self._gen_duplicate_slot_nested_component())
registry.register(name="calendar", component=self.CalendarComponent) registry.register(name="calendar", component=self._gen_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -2173,7 +2189,7 @@ class TestSlotFillTemplateSyntaxError:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_non_unique_fill_names_is_error(self, components_settings): def test_non_unique_fill_names_is_error(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
with pytest.raises( with pytest.raises(
TemplateSyntaxError, TemplateSyntaxError,
match=re.escape( match=re.escape(
@ -2192,7 +2208,7 @@ class TestSlotFillTemplateSyntaxError:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_non_unique_fill_names_is_error_via_vars(self, components_settings): def test_non_unique_fill_names_is_error_via_vars(self, components_settings):
registry.register("test", SlottedComponent) registry.register("test", _gen_slotted_component())
with pytest.raises( with pytest.raises(
TemplateSyntaxError, TemplateSyntaxError,
match=re.escape( match=re.escape(

View file

@ -13,41 +13,23 @@ from .testutils import PARAMETRIZE_CONTEXT_BEHAVIOR, setup_test_config
setup_test_config({"autodiscover": False}) setup_test_config({"autodiscover": False})
class SlottedComponent(Component):
template: types.django_html = """
{% load component_tags %}
<custom-template>
<header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "main" %}Default main{% endslot %}</main>
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
</custom-template>
"""
class SlottedComponentWithContext(SlottedComponent):
def get_context_data(self, variable):
return {"variable": variable}
#######################
# TESTS
#######################
@djc_test @djc_test
class TestNestedSlot: class TestNestedSlot:
class NestedComponent(Component): def _get_nested_component(self):
template: types.django_html = """ class NestedComponent(Component):
{% load component_tags %} template: types.django_html = """
{% slot 'outer' %} {% load component_tags %}
<div id="outer">{% slot 'inner' %}Default{% endslot %}</div> {% slot 'outer' %}
{% endslot %} <div id="outer">{% slot 'inner' %}Default{% endslot %}</div>
""" {% endslot %}
"""
return NestedComponent
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_default_slot_contents_render_correctly(self, components_settings): def test_default_slot_contents_render_correctly(self, components_settings):
registry.clear() registry.clear()
registry.register("test", self.NestedComponent) registry.register("test", self._get_nested_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' %}{% endcomponent %} {% component 'test' %}{% endcomponent %}
@ -59,7 +41,7 @@ class TestNestedSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_inner_slot_overriden(self, components_settings): def test_inner_slot_overriden(self, components_settings):
registry.clear() registry.clear()
registry.register("test", self.NestedComponent) registry.register("test", self._get_nested_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' %} {% component 'test' %}
@ -73,7 +55,7 @@ class TestNestedSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_outer_slot_overriden(self, components_settings): def test_outer_slot_overriden(self, components_settings):
registry.clear() registry.clear()
registry.register("test", self.NestedComponent) registry.register("test", self._get_nested_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' %}{% fill 'outer' %}<p>Override</p>{% endfill %}{% endcomponent %} {% component 'test' %}{% fill 'outer' %}<p>Override</p>{% endfill %}{% endcomponent %}
@ -85,7 +67,7 @@ class TestNestedSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_both_overriden_and_inner_removed(self, components_settings): def test_both_overriden_and_inner_removed(self, components_settings):
registry.clear() registry.clear()
registry.register("test", self.NestedComponent) registry.register("test", self._get_nested_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' %} {% component 'test' %}
@ -175,22 +157,25 @@ class TestNestedSlot:
# as provided by {% if %} tags was previously provided by this library. # as provided by {% if %} tags was previously provided by this library.
@djc_test @djc_test
class TestConditionalSlot: class TestConditionalSlot:
class ConditionalComponent(Component): def _get_conditional_component(self):
template: types.django_html = """ class ConditionalComponent(Component):
{% load component_tags %} template: types.django_html = """
{% if branch == 'a' %} {% load component_tags %}
<p id="a">{% slot 'a' %}Default A{% endslot %}</p> {% if branch == 'a' %}
{% elif branch == 'b' %} <p id="a">{% slot 'a' %}Default A{% endslot %}</p>
<p id="b">{% slot 'b' %}Default B{% endslot %}</p> {% elif branch == 'b' %}
{% endif %} <p id="b">{% slot 'b' %}Default B{% endslot %}</p>
""" {% endif %}
"""
def get_context_data(self, branch=None): def get_context_data(self, branch=None):
return {"branch": branch} return {"branch": branch}
return ConditionalComponent
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_no_content_if_branches_are_false(self, components_settings): def test_no_content_if_branches_are_false(self, components_settings):
registry.register("test", self.ConditionalComponent) registry.register("test", self._get_conditional_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' %} {% component 'test' %}
@ -204,7 +189,7 @@ class TestConditionalSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_default_content_if_no_slots(self, components_settings): def test_default_content_if_no_slots(self, components_settings):
registry.register("test", self.ConditionalComponent) registry.register("test", self._get_conditional_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' branch='a' %}{% endcomponent %} {% component 'test' branch='a' %}{% endcomponent %}
@ -222,7 +207,7 @@ class TestConditionalSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_one_slot_overridden(self, components_settings): def test_one_slot_overridden(self, components_settings):
registry.register("test", self.ConditionalComponent) registry.register("test", self._get_conditional_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' branch='a' %} {% component 'test' branch='a' %}
@ -244,7 +229,7 @@ class TestConditionalSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_both_slots_overridden(self, components_settings): def test_both_slots_overridden(self, components_settings):
registry.register("test", self.ConditionalComponent) registry.register("test", self._get_conditional_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
{% component 'test' branch='a' %} {% component 'test' branch='a' %}
@ -271,20 +256,23 @@ class TestConditionalSlot:
class TestSlotIteration: class TestSlotIteration:
"""Tests a behaviour of {% fill .. %} tag which is inside a template {% for .. %} loop.""" """Tests a behaviour of {% fill .. %} tag which is inside a template {% for .. %} loop."""
class ComponentSimpleSlotInALoop(Component): def _get_component_simple_slot_in_a_loop(self):
template: types.django_html = """ class ComponentSimpleSlotInALoop(Component):
{% load component_tags %} template: types.django_html = """
{% for object in objects %} {% load component_tags %}
{% slot 'slot_inner' %} {% for object in objects %}
{{ object }} default {% slot 'slot_inner' %}
{% endslot %} {{ object }} default
{% endfor %} {% endslot %}
""" {% endfor %}
"""
def get_context_data(self, objects, *args, **kwargs) -> dict: def get_context_data(self, objects, *args, **kwargs) -> dict:
return { return {
"objects": objects, "objects": objects,
} }
return ComponentSimpleSlotInALoop
# NOTE: Second arg in tuple is expected result. In isolated mode, loops should NOT leak. # NOTE: Second arg in tuple is expected result. In isolated mode, loops should NOT leak.
@djc_test( @djc_test(
@ -298,7 +286,7 @@ class TestSlotIteration:
) )
) )
def test_inner_slot_iteration_basic(self, components_settings, expected): def test_inner_slot_iteration_basic(self, components_settings, expected):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -327,7 +315,7 @@ class TestSlotIteration:
) )
) )
def test_inner_slot_iteration_with_variable_from_outer_scope(self, components_settings, expected): def test_inner_slot_iteration_with_variable_from_outer_scope(self, components_settings, expected):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -363,7 +351,7 @@ class TestSlotIteration:
) )
) )
def test_inner_slot_iteration_nested(self, components_settings, expected): def test_inner_slot_iteration_nested(self, components_settings, expected):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
objects = [ objects = [
{"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]}, {"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]},
@ -414,7 +402,7 @@ class TestSlotIteration:
) )
) )
def test_inner_slot_iteration_nested_with_outer_scope_variable(self, components_settings, expected): def test_inner_slot_iteration_nested_with_outer_scope_variable(self, components_settings, expected):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
objects = [ objects = [
{"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]}, {"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]},
@ -460,7 +448,7 @@ class TestSlotIteration:
) )
) )
def test_inner_slot_iteration_nested_with_slot_default(self, components_settings, expected): def test_inner_slot_iteration_nested_with_slot_default(self, components_settings, expected):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
objects = [ objects = [
{"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]}, {"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]},
@ -517,7 +505,7 @@ class TestSlotIteration:
components_settings, components_settings,
expected, expected,
): ):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
objects = [ objects = [
{"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]}, {"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]},
@ -554,7 +542,7 @@ class TestSlotIteration:
def test_inner_slot_iteration_nested_with_slot_default_and_outer_scope_variable__isolated_2( def test_inner_slot_iteration_nested_with_slot_default_and_outer_scope_variable__isolated_2(
self, self,
): ):
registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop) registry.register("slot_in_a_loop", self._get_component_simple_slot_in_a_loop())
objects = [ objects = [
{"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]}, {"inner": ["ITER1_OBJ1", "ITER1_OBJ2"]},
@ -608,40 +596,44 @@ class TestSlotIteration:
@djc_test @djc_test
class TestComponentNesting: class TestComponentNesting:
class CalendarComponent(Component): def _get_calendar_component(self):
"""Nested in ComponentWithNestedComponent""" class CalendarComponent(Component):
"""Nested in ComponentWithNestedComponent"""
template: types.django_html = """ template: types.django_html = """
{% load component_tags %} {% load component_tags %}
<div class="calendar-component"> <div class="calendar-component">
<h1> <h1>
{% slot "header" %}Today's date is <span>{{ date }}</span>{% endslot %} {% slot "header" %}Today's date is <span>{{ date }}</span>{% endslot %}
</h1> </h1>
<main> <main>
{% slot "body" %} {% slot "body" %}
You have no events today. You have no events today.
{% endslot %} {% endslot %}
</main> </main>
</div> </div>
""" """
return CalendarComponent
class DashboardComponent(Component): def _get_dashboard_component(self):
template: types.django_html = """ class DashboardComponent(Component):
{% load component_tags %} template: types.django_html = """
<div class="dashboard-component"> {% load component_tags %}
{% component "calendar" date="2020-06-06" %} <div class="dashboard-component">
{% fill "header" %} {# fills and slots with same name relate to diff. things. #} {% component "calendar" date="2020-06-06" %}
{% slot "header" %}Welcome to your dashboard!{% endslot %} {% fill "header" %} {# fills and slots with same name relate to diff. things. #}
{% endfill %} {% slot "header" %}Welcome to your dashboard!{% endslot %}
{% fill "body" %}Here are your to-do items for today:{% endfill %} {% endfill %}
{% endcomponent %} {% fill "body" %}Here are your to-do items for today:{% endfill %}
<ol> {% endcomponent %}
{% for item in items %} <ol>
<li>{{ item }}</li> {% for item in items %}
{% endfor %} <li>{{ item }}</li>
</ol> {% endfor %}
</div> </ol>
""" </div>
"""
return DashboardComponent
# NOTE: Second arg in tuple are expected names in nested fills. In "django" mode, # NOTE: Second arg in tuple are expected names in nested fills. In "django" mode,
# the value should be overridden by the component, while in "isolated" it should # the value should be overridden by the component, while in "isolated" it should
@ -657,8 +649,8 @@ class TestComponentNesting:
) )
) )
def test_component_inside_slot(self, components_settings, first_name, second_name): def test_component_inside_slot(self, components_settings, first_name, second_name):
registry.register("dashboard", self.DashboardComponent) registry.register("dashboard", self._get_dashboard_component())
registry.register("calendar", self.CalendarComponent) registry.register("calendar", self._get_calendar_component())
class SlottedComponent(Component): class SlottedComponent(Component):
template: types.django_html = """ template: types.django_html = """
@ -730,8 +722,8 @@ class TestComponentNesting:
) )
) )
def test_component_nesting_component_without_fill(self, components_settings, expected): def test_component_nesting_component_without_fill(self, components_settings, expected):
registry.register("dashboard", self.DashboardComponent) registry.register("dashboard", self._get_dashboard_component())
registry.register("calendar", self.CalendarComponent) registry.register("calendar", self._get_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -768,8 +760,8 @@ class TestComponentNesting:
) )
) )
def test_component_nesting_slot_inside_component_fill(self, components_settings, expected): def test_component_nesting_slot_inside_component_fill(self, components_settings, expected):
registry.register("dashboard", self.DashboardComponent) registry.register("dashboard", self._get_dashboard_component())
registry.register("calendar", self.CalendarComponent) registry.register("calendar", self._get_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}
@ -970,8 +962,8 @@ class TestComponentNesting:
) )
) )
def test_component_nesting_component_with_slot_default(self, components_settings, expected): def test_component_nesting_component_with_slot_default(self, components_settings, expected):
registry.register("dashboard", self.DashboardComponent) registry.register("dashboard", self._get_dashboard_component())
registry.register("calendar", self.CalendarComponent) registry.register("calendar", self._get_calendar_component())
template_str: types.django_html = """ template_str: types.django_html = """
{% load component_tags %} {% load component_tags %}