mirror of
https://github.com/django-components/django-components.git
synced 2025-08-30 18:57:20 +00:00
feat: add decorator for writing component tests (#1008)
* feat: add decorator for writing component tests * refactor: udpate changelog + update deps pins * refactor: fix deps * refactor: make cached_ref into generic and fix linter errors * refactor: fix coverage testing * refactor: use global var instead of env var for is_testing state
This commit is contained in:
parent
81ac59f7fb
commit
7dfcb447c4
62 changed files with 4428 additions and 3661 deletions
|
@ -1,86 +1,66 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from django.template import Context, Template, TemplateSyntaxError
|
||||
from django.utils.safestring import SafeString, mark_safe
|
||||
from pytest_django.asserts import assertHTMLEqual
|
||||
|
||||
from django_components import Component, register, types
|
||||
from django_components.attributes import append_attributes, attributes_to_string
|
||||
from django_components.testing import djc_test
|
||||
|
||||
from .django_test_setup import setup_test_config
|
||||
from .testutils import BaseTestCase, parametrize_context_behavior
|
||||
from .testutils import PARAMETRIZE_CONTEXT_BEHAVIOR, setup_test_config
|
||||
|
||||
setup_test_config({"autodiscover": False})
|
||||
|
||||
|
||||
class AttributesToStringTest(BaseTestCase):
|
||||
@djc_test
|
||||
class TestAttributesToString:
|
||||
def test_simple_attribute(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"foo": "bar"}),
|
||||
'foo="bar"',
|
||||
)
|
||||
assert attributes_to_string({"foo": "bar"}) == 'foo="bar"'
|
||||
|
||||
def test_multiple_attributes(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"class": "foo", "style": "color: red;"}),
|
||||
'class="foo" style="color: red;"',
|
||||
)
|
||||
assert attributes_to_string({"class": "foo", "style": "color: red;"}) == 'class="foo" style="color: red;"'
|
||||
|
||||
def test_escapes_special_characters(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"x-on:click": "bar", "@click": "'baz'"}),
|
||||
'x-on:click="bar" @click="'baz'"',
|
||||
)
|
||||
assert attributes_to_string({"x-on:click": "bar", "@click": "'baz'"}) == 'x-on:click="bar" @click="'baz'"' # noqa: E501
|
||||
|
||||
def test_does_not_escape_special_characters_if_safe_string(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"foo": mark_safe("'bar'")}),
|
||||
"foo=\"'bar'\"",
|
||||
)
|
||||
assert attributes_to_string({"foo": mark_safe("'bar'")}) == "foo=\"'bar'\""
|
||||
|
||||
def test_result_is_safe_string(self):
|
||||
result = attributes_to_string({"foo": mark_safe("'bar'")})
|
||||
self.assertTrue(isinstance(result, SafeString))
|
||||
assert isinstance(result, SafeString)
|
||||
|
||||
def test_attribute_with_no_value(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"required": None}),
|
||||
"",
|
||||
)
|
||||
assert attributes_to_string({"required": None}) == ""
|
||||
|
||||
def test_attribute_with_false_value(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"required": False}),
|
||||
"",
|
||||
)
|
||||
assert attributes_to_string({"required": False}) == ""
|
||||
|
||||
def test_attribute_with_true_value(self):
|
||||
self.assertEqual(
|
||||
attributes_to_string({"required": True}),
|
||||
"required",
|
||||
)
|
||||
assert attributes_to_string({"required": True}) == "required"
|
||||
|
||||
|
||||
class AppendAttributesTest(BaseTestCase):
|
||||
@djc_test
|
||||
class TestAppendAttributes:
|
||||
def test_single_dict(self):
|
||||
self.assertEqual(
|
||||
append_attributes(("foo", "bar")),
|
||||
{"foo": "bar"},
|
||||
)
|
||||
assert append_attributes(("foo", "bar")) == {"foo": "bar"}
|
||||
|
||||
def test_appends_dicts(self):
|
||||
self.assertEqual(
|
||||
append_attributes(("class", "foo"), ("id", "bar"), ("class", "baz")),
|
||||
{"class": "foo baz", "id": "bar"},
|
||||
)
|
||||
assert append_attributes(("class", "foo"), ("id", "bar"), ("class", "baz")) == {"class": "foo baz", "id": "bar"} # noqa: E501
|
||||
|
||||
|
||||
class HtmlAttrsTests(BaseTestCase):
|
||||
@djc_test
|
||||
class TestHtmlAttrs:
|
||||
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):
|
||||
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
||||
def test_tag_positional_args(self, components_settings):
|
||||
@register("test")
|
||||
class AttrsComponent(Component):
|
||||
template: types.django_html = """
|
||||
|
@ -98,7 +78,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div @click.stop="dispatch('click_event')" x-data="{hello: 'world'}" class="padding-top-8 added_class another-class" data-djc-id-a1bc3f data-id=123>
|
||||
|
@ -106,7 +86,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_raises_on_extra_positional_args(self):
|
||||
@register("test")
|
||||
|
@ -127,8 +107,9 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
|
||||
with self.assertRaisesMessage(
|
||||
TypeError, "Invalid parameters for tag 'html_attrs': takes 2 positional argument(s) but more were given"
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match=re.escape("Invalid parameters for tag 'html_attrs': takes 2 positional argument(s) but more were given"), # noqa: E501
|
||||
):
|
||||
template.render(Context({"class_var": "padding-top-8"}))
|
||||
|
||||
|
@ -150,7 +131,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div @click.stop="dispatch('click_event')" class="added_class another-class padding-top-8" data-djc-id-a1bc3f data-id="123" x-data="{hello: 'world'}">
|
||||
|
@ -158,7 +139,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_kwargs_2(self):
|
||||
@register("test")
|
||||
|
@ -178,7 +159,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div @click.stop="dispatch('click_event')" x-data="{hello: 'world'}" class="padding-top-8 added_class another-class" data-djc-id-a1bc3f data-id=123>
|
||||
|
@ -186,7 +167,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_spread(self):
|
||||
@register("test")
|
||||
|
@ -210,7 +191,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div @click.stop="dispatch('click_event')" class="added_class another-class padding-top-8" data-djc-id-a1bc3f data-id="123" x-data="{hello: 'world'}">
|
||||
|
@ -218,7 +199,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_aggregate_args(self):
|
||||
@register("test")
|
||||
|
@ -237,7 +218,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
|
||||
# NOTE: The attrs from self.template_str should be ignored because they are not used.
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div class="added_class another-class from_agg_key" data-djc-id-a1bc3f data-id="123" type="submit">
|
||||
|
@ -245,7 +226,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
# Note: Because there's both `attrs:class` and `defaults:class`, the `attrs`,
|
||||
# it's as if the template tag call was (ignoring the `class` and `data-id` attrs):
|
||||
|
@ -268,8 +249,9 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
|
||||
with self.assertRaisesMessage(
|
||||
TypeError, "Invalid parameters for tag 'html_attrs': got multiple values for argument 'attrs'"
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match=re.escape("Invalid parameters for tag 'html_attrs': got multiple values for argument 'attrs'"),
|
||||
):
|
||||
template.render(Context({"class_var": "padding-top-8"}))
|
||||
|
||||
|
@ -295,9 +277,9 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
|
||||
with self.assertRaisesMessage(
|
||||
with pytest.raises(
|
||||
TemplateSyntaxError,
|
||||
"Received argument 'defaults' both as a regular input",
|
||||
match=re.escape("Received argument 'defaults' both as a regular input"),
|
||||
):
|
||||
template.render(Context({"class_var": "padding-top-8"}))
|
||||
|
||||
|
@ -316,7 +298,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div class="added_class another-class override-me" data-djc-id-a1bc3f data-id=123>
|
||||
|
@ -345,7 +327,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
""" # noqa: E501
|
||||
template = Template(template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div @click.stop="dispatch('click_event')" x-data="{hello: 'world'}" class="padding-top-8 added_class another-class" data-djc-id-a1bc3f data-id=123>
|
||||
|
@ -353,7 +335,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""", # noqa: E501
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_no_attrs_no_defaults(self):
|
||||
@register("test")
|
||||
|
@ -370,7 +352,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div class="added_class another-class" data-djc-id-a1bc3f data-id="123">
|
||||
|
@ -378,7 +360,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""",
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_empty(self):
|
||||
@register("test")
|
||||
|
@ -398,7 +380,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div data-djc-id-a1bc3f>
|
||||
|
@ -406,7 +388,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""",
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
||||
def test_tag_null_attrs_and_defaults(self):
|
||||
@register("test")
|
||||
|
@ -426,7 +408,7 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
|
||||
template = Template(self.template_str)
|
||||
rendered = template.render(Context({"class_var": "padding-top-8"}))
|
||||
self.assertHTMLEqual(
|
||||
assertHTMLEqual(
|
||||
rendered,
|
||||
"""
|
||||
<div data-djc-id-a1bc3f>
|
||||
|
@ -434,4 +416,4 @@ class HtmlAttrsTests(BaseTestCase):
|
|||
</div>
|
||||
""",
|
||||
)
|
||||
self.assertNotIn("override-me", rendered)
|
||||
assert "override-me" not in rendered
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue