refactor: prepare registry for custom template tags and docs (#566)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Juro Oravec 2024-08-05 22:31:49 +02:00 committed by GitHub
parent c202c5a901
commit d6dec450ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 491 additions and 94 deletions

View file

@ -73,14 +73,11 @@ class AppendAttributesTest(BaseTestCase):
class HtmlAttrsTests(BaseTestCase):
def setUp(self):
super().setUp()
self.template_str: types.django_html = """
{% load component_tags %}
{% component "test" attrs:@click.stop="dispatch('click_event')" attrs:x-data="{hello: 'world'}" attrs:class=class_var %}
{% endcomponent %}
""" # noqa: E501
template_str: types.django_html = """
{% load component_tags %}
{% component "test" attrs:@click.stop="dispatch('click_event')" attrs:x-data="{hello: 'world'}" attrs:class=class_var %}
{% endcomponent %}
""" # noqa: E501
@parametrize_context_behavior(["django", "isolated"])
def test_tag_positional_args(self):

View file

@ -615,10 +615,6 @@ class ContextVarsIsFilledTests(BaseTestCase):
)
registry.register("negated_conditional_slot", self.ComponentWithNegatedConditionalSlot)
def tearDown(self) -> None:
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_is_filled_vars(self):
template: types.django_html = """

View file

@ -67,10 +67,6 @@ class MultistyleComponent(Component):
@override_settings(COMPONENTS={"RENDER_DEPENDENCIES": True})
class ComponentMediaRenderingTests(BaseTestCase):
def setUp(self):
# NOTE: registry is global, so need to clear before each test
registry.clear()
def test_no_dependencies_when_no_components_used(self):
registry.register(name="test", component=SimpleComponent)

View file

@ -1,5 +1,7 @@
import unittest
from django.template import Library
from django_components import AlreadyRegistered, Component, ComponentRegistry, NotRegistered, register, registry
from .django_test_setup import setup_test_config
@ -22,6 +24,7 @@ class MockComponentView(Component):
class ComponentRegistryTest(unittest.TestCase):
def setUp(self):
super().setUp()
self.registry = ComponentRegistry()
def test_register_class_decorator(self):
@ -31,6 +34,23 @@ class ComponentRegistryTest(unittest.TestCase):
self.assertEqual(registry.get("decorated_component"), TestComponent)
# Cleanup
registry.unregister("decorated_component")
def test_register_class_decorator_custom_registry(self):
my_lib = Library()
my_reg = ComponentRegistry(library=my_lib)
self.assertDictEqual(my_reg.all(), {})
self.assertDictEqual(registry.all(), {})
@register("decorated_component", registry=my_reg)
class TestComponent(Component):
pass
self.assertDictEqual(my_reg.all(), {"decorated_component": TestComponent})
self.assertDictEqual(registry.all(), {})
def test_simple_register(self):
self.registry.register(name="testcomponent", component=MockComponent)
self.assertEqual(self.registry.all(), {"testcomponent": MockComponent})
@ -46,6 +66,44 @@ class ComponentRegistryTest(unittest.TestCase):
},
)
def test_unregisters_only_unused_tags(self):
self.assertDictEqual(self.registry._tags, {})
# NOTE: We preserve the default component tags
self.assertIn("component", self.registry.library.tags)
# Register two components that use the same tag
self.registry.register(name="testcomponent", component=MockComponent)
self.registry.register(name="testcomponent2", component=MockComponent)
self.assertDictEqual(
self.registry._tags,
{
"#component": {"testcomponent", "testcomponent2"},
"component": {"testcomponent", "testcomponent2"},
},
)
self.assertIn("component", self.registry.library.tags)
# Unregister only one of the components. The tags should remain
self.registry.unregister(name="testcomponent")
self.assertDictEqual(
self.registry._tags,
{
"#component": {"testcomponent2"},
"component": {"testcomponent2"},
},
)
self.assertIn("component", self.registry.library.tags)
# Unregister the second components. The tags should be removed
self.registry.unregister(name="testcomponent2")
self.assertDictEqual(self.registry._tags, {})
self.assertIn("component", self.registry.library.tags)
def test_prevent_registering_different_components_with_the_same_name(self):
self.registry.register(name="testcomponent", component=MockComponent)
with self.assertRaises(AlreadyRegistered):

View file

@ -25,6 +25,7 @@ class TemplateInstrumentationTest(BaseTestCase):
saved_render_method: Callable # Assigned during setup.
def tearDown(self):
super().tearDown()
Template._render = self.saved_render_method
def setUp(self):
@ -92,14 +93,6 @@ class TemplateInstrumentationTest(BaseTestCase):
class BlockCompatTests(BaseTestCase):
def setUp(self):
registry.clear()
super().setUp()
def tearDown(self):
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_slots_inside_extends(self):
registry.register("slotted_component", SlottedComponent)

View file

@ -47,10 +47,6 @@ class ComponentTemplateTagTest(BaseTestCase):
css = "style.css"
js = "script.js"
def setUp(self):
# NOTE: registry is global, so need to clear before each test
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_single_component(self):
registry.register(name="test", component=self.SimpleComponent)
@ -190,9 +186,6 @@ class ComponentTemplateTagTest(BaseTestCase):
class MultiComponentTests(BaseTestCase):
def setUp(self):
registry.clear()
def register_components(self):
registry.register("first_component", SlottedComponent)
registry.register("second_component", SlottedComponentWithContext)
@ -265,18 +258,19 @@ class MultiComponentTests(BaseTestCase):
class ComponentIsolationTests(BaseTestCase):
def setUp(self):
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 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>
"""
registry.register("test", SlottedComponent)
def setUp(self):
super().setUp()
registry.register("test", self.SlottedComponent)
@parametrize_context_behavior(["django", "isolated"])
def test_instances_of_component_do_not_share_slots(self):
@ -358,10 +352,6 @@ class ComponentTemplateSyntaxErrorTests(BaseTestCase):
super().setUp()
registry.register("test", SlottedComponent)
def tearDown(self) -> None:
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_variable_outside_fill_tag_compiles_w_out_error(self):
# As of v0.28 this is valid, provided the component registered under "test"

View file

@ -32,10 +32,6 @@ class SlottedComponentWithContext(SlottedComponent):
class ComponentSlottedTemplateTagTest(BaseTestCase):
def setUp(self):
# NOTE: registry is global, so need to clear before each test
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_slotted_template_basic(self):
registry.register(name="test1", component=SlottedComponent)
@ -477,10 +473,6 @@ class ComponentSlottedTemplateTagTest(BaseTestCase):
class SlottedTemplateRegressionTests(BaseTestCase):
def setUp(self):
# NOTE: registry is global, so need to clear before each test
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_slotted_template_that_uses_missing_variable(self):
@register("test")
@ -517,13 +509,8 @@ class SlottedTemplateRegressionTests(BaseTestCase):
class SlotDefaultTests(BaseTestCase):
def setUp(self):
super().setUp()
registry.clear()
registry.register("test", SlottedComponent)
def tearDown(self):
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_basic(self):
template_str: types.django_html = """
@ -1115,10 +1102,6 @@ class SlotFillTemplateSyntaxErrorTests(BaseTestCase):
super().setUp()
registry.register("test", SlottedComponent)
def tearDown(self):
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_fill_with_no_parent_is_error(self):
with self.assertRaises(TemplateSyntaxError):

View file

@ -178,13 +178,8 @@ class ConditionalSlotTests(BaseTestCase):
def setUp(self):
super().setUp()
registry.clear()
registry.register("test", self.ConditionalComponent)
def tearDown(self):
super().tearDown()
registry.clear()
@parametrize_context_behavior(["django", "isolated"])
def test_no_content_if_branches_are_false(self):
template_str: types.django_html = """
@ -260,9 +255,6 @@ class SlotIterationTest(BaseTestCase):
"objects": objects,
}
def setUp(self):
registry.clear()
# NOTE: Second arg in tuple is expected result. In isolated mode, loops should NOT leak.
@parametrize_context_behavior(
[
@ -627,10 +619,6 @@ class ComponentNestingTests(BaseTestCase):
registry.register("complex_child", self.ComplexChildComponent)
registry.register("complex_parent", self.ComplexParentComponent)
def tearDown(self) -> None:
super().tearDown()
registry.clear()
# 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
# remain top-level context.