import os
import sys
from pathlib import Path
from django.forms.widgets import Media
from django.template import Context, Template
from django.templatetags.static import static
from django.test import override_settings
from django.utils.html import format_html, html_safe
from django.utils.safestring import mark_safe
from django_components import Component, registry, types
from .django_test_setup import setup_test_config
from .testutils import BaseTestCase, autodiscover_with_cleanup
setup_test_config()
class InlineComponentTest(BaseTestCase):
def test_html(self):
class InlineHTMLComponent(Component):
template = "
"""
def get_context_data(self, shadowing_variable=None, new_variable=None):
context = {}
if shadowing_variable is not None:
context["shadowing_variable"] = shadowing_variable
if new_variable is not None:
context["unique_variable"] = new_variable
return context
def setUp(self):
super().setUp()
registry.register(name="parent_component", component=self.ParentComponent)
registry.register(name="variable_display", component=self.VariableDisplay)
# Settings required for autodiscover to work
@override_settings(
BASE_DIR=Path(__file__).resolve().parent,
STATICFILES_DIRS=[
Path(__file__).resolve().parent / "components",
],
)
def test_component_with_relative_media_paths(self):
# Ensure that the module is executed again after import in autodiscovery
if "tests.components.relative_file.relative_file" in sys.modules:
del sys.modules["tests.components.relative_file.relative_file"]
# Fix the paths, since the "components" dir is nested
with autodiscover_with_cleanup(map_module=lambda p: f"tests.{p}"):
# Make sure that only relevant components are registered:
comps_to_remove = [
comp_name
for comp_name in registry.all()
if comp_name not in ["relative_file_component", "parent_component", "variable_display"]
]
for comp_name in comps_to_remove:
registry.unregister(comp_name)
template_str: types.django_html = """
{% load component_tags %}{% component_dependencies %}
{% component name='relative_file_component' variable=variable %}
{% endcomponent %}
"""
template = Template(template_str)
rendered = template.render(Context({"variable": "test"}))
self.assertHTMLEqual(
rendered,
"""
""",
)
# Settings required for autodiscover to work
@override_settings(
BASE_DIR=Path(__file__).resolve().parent,
STATICFILES_DIRS=[
Path(__file__).resolve().parent / "components",
],
)
def test_component_with_relative_media_paths_as_subcomponent(self):
# Ensure that the module is executed again after import in autodiscovery
if "tests.components.relative_file.relative_file" in sys.modules:
del sys.modules["tests.components.relative_file.relative_file"]
# Fix the paths, since the "components" dir is nested
with autodiscover_with_cleanup(map_module=lambda p: f"tests.{p}"):
registry.unregister("relative_file_pathobj_component")
template_str: types.django_html = """
{% load component_tags %}{% component_dependencies %}
{% component 'parent_component' %}
{% fill 'content' %}
{% component name='relative_file_component' variable='hello' %}
{% endcomponent %}
{% endfill %}
{% endcomponent %}
"""
template = Template(template_str)
rendered = template.render(Context({}))
self.assertIn('', rendered, rendered)
# Settings required for autodiscover to work
@override_settings(
BASE_DIR=Path(__file__).resolve().parent,
STATICFILES_DIRS=[
Path(__file__).resolve().parent / "components",
],
)
def test_component_with_relative_media_does_not_trigger_safestring_path_at__new__(self):
"""
Test that, for the __html__ objects are not coerced into string throughout
the class creation. This is important to allow to call `collectstatic` command.
Because some users use `static` inside the `__html__` or `__str__` methods.
So if we "render" the safestring using str() during component class creation (__new__),
then we force to call `static`. And if this happens during `collectstatic` run,
then this triggers an error, because `static` is called before the static files exist.
https://github.com/EmilStenstrom/django-components/issues/522#issuecomment-2173577094
"""
# Ensure that the module is executed again after import in autodiscovery
if "tests.components.relative_file_pathobj.relative_file_pathobj" in sys.modules:
del sys.modules["tests.components.relative_file_pathobj.relative_file_pathobj"]
# Fix the paths, since the "components" dir is nested
with autodiscover_with_cleanup(map_module=lambda p: f"tests.{p}"):
# Mark the PathObj instances of 'relative_file_pathobj_component' so they won raise
# error PathObj.__str__ is triggered.
CompCls = registry.get("relative_file_pathobj_component")
CompCls.Media.js[0].throw_on_calling_str = False # type: ignore
CompCls.Media.css["all"][0].throw_on_calling_str = False # type: ignore
rendered = CompCls().render_dependencies()
self.assertHTMLEqual(
rendered,
"""
""",
)