login page
This commit is contained in:
0
Lib/site-packages/crispy_forms/tests/__init__.py
Normal file
0
Lib/site-packages/crispy_forms/tests/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
35
Lib/site-packages/crispy_forms/tests/conftest.py
Normal file
35
Lib/site-packages/crispy_forms/tests/conftest.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
|
||||
from crispy_forms.layout import HTML, Div, Field, Fieldset, Layout, Submit
|
||||
|
||||
only_uni_form = pytest.mark.only("uni_form")
|
||||
only_bootstrap = pytest.mark.only("bootstrap", "bootstrap3", "bootstrap4")
|
||||
only_bootstrap3 = pytest.mark.only("bootstrap3")
|
||||
only_bootstrap4 = pytest.mark.only("bootstrap4")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def advanced_layout():
|
||||
return Layout(
|
||||
Div(
|
||||
Div(Div("email")),
|
||||
Div(Field("password1")),
|
||||
Submit("save", "save"),
|
||||
Fieldset("legend", "first_name", HTML("extra text"),),
|
||||
Layout("password2",),
|
||||
),
|
||||
"last_name",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, params=("uni_form", "bootstrap", "bootstrap3", "bootstrap4"))
|
||||
def template_packs(request, settings):
|
||||
check_template_pack(request.node, request.param)
|
||||
settings.CRISPY_TEMPLATE_PACK = request.param
|
||||
|
||||
|
||||
def check_template_pack(node, template_pack):
|
||||
mark = node.get_closest_marker("only")
|
||||
if mark:
|
||||
if template_pack not in mark.args:
|
||||
pytest.skip("Requires %s template pack" % " or ".join(mark.args))
|
||||
163
Lib/site-packages/crispy_forms/tests/forms.py
Normal file
163
Lib/site-packages/crispy_forms/tests/forms.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from django import forms
|
||||
from django.db import models
|
||||
|
||||
from crispy_forms.helper import FormHelper
|
||||
|
||||
|
||||
class SampleForm(forms.Form):
|
||||
is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
|
||||
email = forms.EmailField(
|
||||
label="email", max_length=30, required=True, widget=forms.TextInput(), help_text="Insert your email"
|
||||
)
|
||||
password1 = forms.CharField(label="password", max_length=30, required=True, widget=forms.PasswordInput())
|
||||
password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())
|
||||
first_name = forms.CharField(label="first name", max_length=5, required=True, widget=forms.TextInput())
|
||||
last_name = forms.CharField(label="last name", max_length=5, required=True, widget=forms.TextInput())
|
||||
datetime_field = forms.SplitDateTimeField(label="date time", widget=forms.SplitDateTimeWidget())
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
password1 = self.cleaned_data.get("password1", None)
|
||||
password2 = self.cleaned_data.get("password2", None)
|
||||
if not password1 and not password2 or password1 != password2:
|
||||
raise forms.ValidationError("Passwords dont match")
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
class SampleForm2(SampleForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper(self)
|
||||
|
||||
|
||||
class CheckboxesSampleForm(forms.Form):
|
||||
checkboxes = forms.MultipleChoiceField(
|
||||
choices=((1, "Option one"), (2, "Option two"), (3, "Option three")),
|
||||
initial=(1,),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
alphacheckboxes = forms.MultipleChoiceField(
|
||||
choices=(("option_one", "Option one"), ("option_two", "Option two"), ("option_three", "Option three")),
|
||||
initial=("option_two", "option_three"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
numeric_multiple_checkboxes = forms.MultipleChoiceField(
|
||||
choices=((1, "Option one"), (2, "Option two"), (3, "Option three")),
|
||||
initial=(1, 2),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
inline_radios = forms.ChoiceField(
|
||||
choices=(("option_one", "Option one"), ("option_two", "Option two"),),
|
||||
widget=forms.RadioSelect,
|
||||
initial="option_two",
|
||||
)
|
||||
|
||||
|
||||
class CrispyTestModel(models.Model):
|
||||
email = models.CharField(max_length=20)
|
||||
password = models.CharField(max_length=20)
|
||||
|
||||
|
||||
class SampleForm3(forms.ModelForm):
|
||||
class Meta:
|
||||
model = CrispyTestModel
|
||||
fields = ["email", "password"]
|
||||
exclude = ["password"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper(self)
|
||||
|
||||
|
||||
class SampleForm4(forms.ModelForm):
|
||||
class Meta:
|
||||
"""
|
||||
before Django1.6, one cannot use __all__ shortcut for fields
|
||||
without getting the following error:
|
||||
django.core.exceptions.FieldError: Unknown field(s) (a, l, _) specified for CrispyTestModel
|
||||
because obviously it casts the string to a set
|
||||
"""
|
||||
|
||||
model = CrispyTestModel
|
||||
fields = "__all__" # eliminate RemovedInDjango18Warning
|
||||
|
||||
|
||||
class SampleForm5(forms.Form):
|
||||
choices = [
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(1000, 1000),
|
||||
]
|
||||
checkbox_select_multiple = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=choices)
|
||||
radio_select = forms.ChoiceField(widget=forms.RadioSelect, choices=choices)
|
||||
pk = forms.IntegerField()
|
||||
|
||||
|
||||
class SampleFormWithMedia(forms.Form):
|
||||
class Media:
|
||||
css = {"all": ("test.css",)}
|
||||
js = ("test.js",)
|
||||
|
||||
|
||||
class SampleFormWithMultiValueField(forms.Form):
|
||||
multi = forms.SplitDateTimeField()
|
||||
|
||||
|
||||
class CrispyEmptyChoiceTestModel(models.Model):
|
||||
fruit = models.CharField(choices=[("apple", "Apple"), ("pear", "Pear")], null=True, blank=True,)
|
||||
|
||||
|
||||
class SampleForm6(forms.ModelForm):
|
||||
class Meta:
|
||||
"""
|
||||
When allowing null=True in a model field,
|
||||
the corresponding field will have a choice
|
||||
for the empty value.
|
||||
|
||||
When the form is initialized by an instance
|
||||
with initial value None, this choice should
|
||||
be selected.
|
||||
"""
|
||||
|
||||
model = CrispyEmptyChoiceTestModel
|
||||
fields = ["fruit"]
|
||||
widgets = {"fruit": forms.RadioSelect()}
|
||||
|
||||
|
||||
class SampleForm7(forms.ModelForm):
|
||||
is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
|
||||
password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())
|
||||
|
||||
class Meta:
|
||||
model = CrispyTestModel
|
||||
fields = ("email", "password", "password2")
|
||||
|
||||
|
||||
class SampleForm8(forms.ModelForm):
|
||||
is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
|
||||
password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())
|
||||
|
||||
class Meta:
|
||||
model = CrispyTestModel
|
||||
fields = ("email", "password2", "password")
|
||||
|
||||
|
||||
class FakeFieldFile:
|
||||
"""
|
||||
Quacks like a FieldFile (has a .url and string representation), but
|
||||
doesn't require us to care about storages etc.
|
||||
"""
|
||||
|
||||
url = "something"
|
||||
|
||||
def __str__(self):
|
||||
return self.url
|
||||
|
||||
|
||||
class FileForm(forms.Form):
|
||||
file_field = forms.FileField(widget=forms.FileInput)
|
||||
clearable_file = forms.FileField(widget=forms.ClearableFileInput, required=False, initial=FakeFieldFile())
|
||||
@@ -0,0 +1,3 @@
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% crispy form %}
|
||||
@@ -0,0 +1,2 @@
|
||||
<h1>Special custom field</h1>
|
||||
{% include 'bootstrap/field.html' %}
|
||||
@@ -0,0 +1,2 @@
|
||||
<h1>Special custom form</h1>
|
||||
{% include "bootstrap/whole_uni_form.html" %}
|
||||
@@ -0,0 +1,4 @@
|
||||
<h1>Special custom form with context passthrough</h1>
|
||||
Got prefix: {{ prefix }}.
|
||||
{% include "bootstrap/whole_uni_form.html" %}
|
||||
Got suffix: {{ suffix }}.
|
||||
354
Lib/site-packages/crispy_forms/tests/test_dynamic_api.py
Normal file
354
Lib/site-packages/crispy_forms/tests/test_dynamic_api.py
Normal file
@@ -0,0 +1,354 @@
|
||||
import pytest
|
||||
|
||||
from django import forms
|
||||
|
||||
from crispy_forms.bootstrap import AppendedText
|
||||
from crispy_forms.exceptions import DynamicError
|
||||
from crispy_forms.helper import FormHelper, FormHelpersException
|
||||
from crispy_forms.layout import HTML, Div, Field, Fieldset, Layout, MultiField
|
||||
from crispy_forms.tests.forms import SampleForm
|
||||
|
||||
from .conftest import only_uni_form
|
||||
|
||||
|
||||
def test_wrap_all_fields():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper.all().wrap(Field, css_class="test-class")
|
||||
for field in layout.fields:
|
||||
assert isinstance(field, Field)
|
||||
assert field.attrs["class"] == "test-class"
|
||||
|
||||
assert layout[0][0] == "email"
|
||||
assert layout[1][0] == "password1"
|
||||
assert layout[2][0] == "password2"
|
||||
|
||||
|
||||
def test_wrap_selected_fields():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper[1:3].wrap(Field, css_class="test-class")
|
||||
assert not isinstance(layout.fields[0], Field)
|
||||
assert isinstance(layout.fields[1], Field)
|
||||
assert isinstance(layout.fields[2], Field)
|
||||
|
||||
helper[0].wrap(Fieldset, "legend", css_class="test-class")
|
||||
assert isinstance(layout[0], Fieldset)
|
||||
assert layout[0].legend == "legend"
|
||||
assert layout[0][0] == "email"
|
||||
|
||||
|
||||
def test_wrap_together_with_slices():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
helper[1:3].wrap_together(Field, css_class="test-class")
|
||||
assert layout.fields[0] == "email"
|
||||
assert isinstance(layout.fields[1], Field)
|
||||
assert layout.fields[1][0] == "password1"
|
||||
assert layout.fields[1][1] == "password2"
|
||||
|
||||
layout = Layout(Div("email"), "password1", "password2",)
|
||||
helper.layout = layout
|
||||
helper[0:3].wrap_together(Field, css_class="test-class")
|
||||
assert isinstance(layout.fields[0], Field)
|
||||
assert isinstance(layout.fields[0][0], Div)
|
||||
assert layout.fields[0][0][0] == "email"
|
||||
assert layout.fields[0][1] == "password1"
|
||||
assert layout.fields[0][2] == "password2"
|
||||
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
helper[0].wrap_together(Field, css_class="test-class")
|
||||
assert isinstance(layout.fields[0], Field)
|
||||
assert layout.fields[1] == "password1"
|
||||
assert layout.fields[2] == "password2"
|
||||
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
helper[0].wrap_together(Fieldset, "legend", css_class="test-class")
|
||||
assert isinstance(layout.fields[0], Fieldset)
|
||||
assert layout.fields[0].legend == "legend"
|
||||
assert layout.fields[1] == "password1"
|
||||
assert layout.fields[2] == "password2"
|
||||
|
||||
|
||||
def test_wrap_together_partial_slices():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper[:2].wrap_together(Field, css_class="test-class")
|
||||
assert isinstance(layout.fields[0], Field)
|
||||
assert layout.fields[1] == "password2"
|
||||
assert layout.fields[0][0] == "email"
|
||||
assert layout.fields[0][1] == "password1"
|
||||
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", "password1", "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper[1:].wrap_together(Field, css_class="test-class")
|
||||
assert layout.fields[0] == "email"
|
||||
assert isinstance(layout.fields[1], Field)
|
||||
assert layout.fields[1][0] == "password1"
|
||||
assert layout.fields[1][1] == "password2"
|
||||
|
||||
|
||||
def test_update_attributes():
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout("email", Field("password1"), "password2",)
|
||||
helper["password1"].update_attributes(readonly=True)
|
||||
assert "readonly" in helper.layout[1].attrs
|
||||
|
||||
|
||||
def test_update_attributes_and_wrap_once():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", Field("password1"), "password2",)
|
||||
helper.layout = layout
|
||||
helper.filter(Field).update_attributes(readonly=True)
|
||||
assert isinstance(layout[1], Field)
|
||||
assert layout[1].attrs == {"readonly": True}
|
||||
|
||||
layout = Layout("email", Div(Field("password1")), "password2",)
|
||||
helper.layout = layout
|
||||
helper.filter(Field, max_level=2).update_attributes(readonly=True)
|
||||
assert isinstance(layout[1][0], Field)
|
||||
assert layout[1][0].attrs == {"readonly": True}
|
||||
|
||||
layout = Layout("email", Div(Field("password1")), "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper.filter(str, greedy=True).wrap_once(Field)
|
||||
helper.filter(Field, greedy=True).update_attributes(readonly=True)
|
||||
|
||||
assert isinstance(layout[0], Field)
|
||||
assert isinstance(layout[1][0], Field)
|
||||
assert isinstance(layout[1][0][0], str)
|
||||
assert isinstance(layout[2], Field)
|
||||
assert layout[1][0].attrs == {"readonly": True}
|
||||
assert layout[0].attrs == {"readonly": True}
|
||||
assert layout[2].attrs == {"readonly": True}
|
||||
|
||||
|
||||
def test_get_layout_objects():
|
||||
layout_1 = Layout(Div())
|
||||
assert layout_1.get_layout_objects(Div) == [[[0], "div"]]
|
||||
|
||||
layout_2 = Layout(Div(Div(Div("email")), Div("password1"), "password2"))
|
||||
assert layout_2.get_layout_objects(Div) == [[[0], "div"]]
|
||||
assert layout_2.get_layout_objects(Div, max_level=1) == [[[0], "div"], [[0, 0], "div"], [[0, 1], "div"]]
|
||||
assert layout_2.get_layout_objects(Div, max_level=2) == [
|
||||
[[0], "div"],
|
||||
[[0, 0], "div"],
|
||||
[[0, 0, 0], "div"],
|
||||
[[0, 1], "div"],
|
||||
]
|
||||
|
||||
layout_3 = Layout("email", Div("password1"), "password2",)
|
||||
assert layout_3.get_layout_objects(str, max_level=2) == [[[0], "email"], [[1, 0], "password1"], [[2], "password2"]]
|
||||
|
||||
layout_4 = Layout(Div(Div("field_name"), "field_name2",), Div("password"), "extra_field")
|
||||
assert layout_4.get_layout_objects(Div) == [[[0], "div"], [[1], "div"]]
|
||||
assert layout_4.get_layout_objects(Div, max_level=1) == [[[0], "div"], [[0, 0], "div"], [[1], "div"]]
|
||||
|
||||
|
||||
def test_filter_and_wrap():
|
||||
helper = FormHelper()
|
||||
layout = Layout("email", Div("password1"), "password2",)
|
||||
helper.layout = layout
|
||||
|
||||
helper.filter(str).wrap(Field, css_class="test-class")
|
||||
assert isinstance(layout.fields[0], Field)
|
||||
assert isinstance(layout.fields[1], Div)
|
||||
assert isinstance(layout.fields[2], Field)
|
||||
assert layout[2][0] == "password2"
|
||||
|
||||
# Wrapping a div in a div
|
||||
helper.filter(Div).wrap(Div, css_class="test-class")
|
||||
assert isinstance(layout.fields[1], Div)
|
||||
assert isinstance(layout.fields[1].fields[0], Div)
|
||||
assert layout[1][0][0] == "password1"
|
||||
|
||||
|
||||
def test_filter_and_wrap_side_effects():
|
||||
helper = FormHelper()
|
||||
layout = Layout(Div("extra_field", Div("password1"),),)
|
||||
helper.layout = layout
|
||||
with pytest.raises(DynamicError):
|
||||
helper.filter(Div, max_level=2).wrap(Div, css_class="test-class")
|
||||
|
||||
|
||||
def test_get_field_names():
|
||||
layout_1 = Div("field_name")
|
||||
assert layout_1.get_field_names() == [[[0], "field_name"]]
|
||||
|
||||
layout_2 = Div(Div("field_name"))
|
||||
assert layout_2.get_field_names() == [[[0, 0], "field_name"]]
|
||||
|
||||
layout_3 = Div(Div("field_name"), "password")
|
||||
assert layout_3.get_field_names() == [[[0, 0], "field_name"], [[1], "password"]]
|
||||
|
||||
layout_4 = Div(Div(Div("field_name"), "field_name2",), Div("password"), "extra_field")
|
||||
assert layout_4.get_field_names() == [
|
||||
[[0, 0, 0], "field_name"],
|
||||
[[0, 1], "field_name2"],
|
||||
[[1, 0], "password"],
|
||||
[[2], "extra_field"],
|
||||
]
|
||||
|
||||
layout_5 = Div(Div("field_name", "field_name2",), "extra_field")
|
||||
assert layout_5.get_field_names() == [
|
||||
[[0, 0], "field_name"],
|
||||
[[0, 1], "field_name2"],
|
||||
[[1], "extra_field"],
|
||||
]
|
||||
|
||||
|
||||
def test_layout_get_field_names():
|
||||
layout_1 = Layout(Div("field_name"), "password")
|
||||
assert layout_1.get_field_names() == [
|
||||
[[0, 0], "field_name"],
|
||||
[[1], "password"],
|
||||
]
|
||||
|
||||
layout_2 = Layout(Div("field_name"), "password", Fieldset("legend", "extra_field"))
|
||||
assert layout_2.get_field_names() == [
|
||||
[[0, 0], "field_name"],
|
||||
[[1], "password"],
|
||||
[[2, 0], "extra_field"],
|
||||
]
|
||||
|
||||
layout_3 = Layout(Div(Div(Div("email")), Div("password1"), "password2"))
|
||||
assert layout_3.get_field_names() == [
|
||||
[[0, 0, 0, 0], "email"],
|
||||
[[0, 1, 0], "password1"],
|
||||
[[0, 2], "password2"],
|
||||
]
|
||||
|
||||
|
||||
def test_filter_by_widget(advanced_layout):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper(form)
|
||||
form.helper.layout = advanced_layout
|
||||
assert form.helper.filter_by_widget(forms.PasswordInput).slice == [
|
||||
[[0, 1, 0, 0], "password1"],
|
||||
[[0, 4, 0], "password2"],
|
||||
]
|
||||
|
||||
|
||||
def test_exclude_by_widget(advanced_layout):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper(form)
|
||||
form.helper.layout = advanced_layout
|
||||
assert form.helper.exclude_by_widget(forms.PasswordInput).slice == [
|
||||
[[0, 0, 0, 0], "email"],
|
||||
[[0, 3, 0], "first_name"],
|
||||
[[1], "last_name"],
|
||||
]
|
||||
|
||||
|
||||
def test_exclude_by_widget_and_wrap(advanced_layout):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper(form)
|
||||
form.helper.layout = advanced_layout
|
||||
form.helper.exclude_by_widget(forms.PasswordInput).wrap(Field, css_class="hero")
|
||||
# Check wrapped fields
|
||||
assert isinstance(form.helper.layout[0][0][0][0], Field)
|
||||
assert isinstance(form.helper.layout[0][3][0], Field)
|
||||
assert isinstance(form.helper.layout[1], Field)
|
||||
# Check others stay the same
|
||||
assert isinstance(form.helper.layout[0][3][1], HTML)
|
||||
assert isinstance(form.helper.layout[0][1][0][0], str)
|
||||
assert isinstance(form.helper.layout[0][4][0], str)
|
||||
|
||||
|
||||
def test_all_without_layout():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
with pytest.raises(FormHelpersException):
|
||||
form.helper.all().wrap(Div)
|
||||
|
||||
|
||||
def test_filter_by_widget_without_form(advanced_layout):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = advanced_layout
|
||||
with pytest.raises(FormHelpersException):
|
||||
form.helper.filter_by_widget(forms.PasswordInput)
|
||||
|
||||
|
||||
def test_formhelper__getitem__():
|
||||
helper = FormHelper()
|
||||
layout = Layout(Div("email"), "password1",)
|
||||
helper.layout = layout
|
||||
helper["email"].wrap(Field, css_class="hero")
|
||||
assert isinstance(layout[0][0], Field)
|
||||
assert layout[0][0][0] == "email"
|
||||
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout("password1")
|
||||
helper["password1"].wrap(AppendedText, "extra")
|
||||
assert isinstance(helper.layout[0], AppendedText)
|
||||
assert helper.layout[0][0] == "password1"
|
||||
assert helper.layout[0].text == "extra"
|
||||
|
||||
|
||||
def test_formhelper__setitem__():
|
||||
helper = FormHelper()
|
||||
layout = Layout("first_field", Div("email"))
|
||||
helper.layout = layout
|
||||
helper[0] = "replaced"
|
||||
assert layout[0] == "replaced"
|
||||
|
||||
|
||||
def test_formhelper__delitem__and__len__():
|
||||
helper = FormHelper()
|
||||
layout = Layout("first_field", Div("email"))
|
||||
helper.layout = layout
|
||||
del helper[0]
|
||||
assert len(helper) == 1
|
||||
|
||||
|
||||
def test__delitem__and__len__layout_object():
|
||||
layout = Layout("first_field", Div("email"))
|
||||
del layout[0]
|
||||
assert len(layout) == 1
|
||||
|
||||
|
||||
def test__getitem__layout_object():
|
||||
layout = Layout(Div(Div(Div("email")), Div("password1"), "password2"))
|
||||
assert isinstance(layout[0], Div)
|
||||
assert isinstance(layout[0][0], Div)
|
||||
assert isinstance(layout[0][0][0], Div)
|
||||
assert isinstance(layout[0][1], Div)
|
||||
assert isinstance(layout[0][1][0], str)
|
||||
assert isinstance(layout[0][2], str)
|
||||
|
||||
|
||||
def test__getattr__append_layout_object():
|
||||
layout = Layout(Div("email"))
|
||||
layout.append("password1")
|
||||
assert isinstance(layout[0], Div)
|
||||
assert isinstance(layout[0][0], str)
|
||||
assert isinstance(layout[1], str)
|
||||
|
||||
|
||||
def test__setitem__layout_object():
|
||||
layout = Layout(Div("email"))
|
||||
layout[0][0] = "password1"
|
||||
assert isinstance(layout[0], Div)
|
||||
assert layout[0][0] == "password1"
|
||||
|
||||
|
||||
@only_uni_form
|
||||
def test_filter():
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout(Div(MultiField("field_name"), "field_name2",), Div("password"), "extra_field")
|
||||
assert helper.filter(Div, MultiField).slice == [[[0], "div"], [[1], "div"]]
|
||||
assert helper.filter(Div, MultiField, max_level=1).slice == [[[0], "div"], [[0, 0], "multifield"], [[1], "div"]]
|
||||
assert helper.filter(MultiField, max_level=1).slice == [[[0, 0], "multifield"]]
|
||||
937
Lib/site-packages/crispy_forms/tests/test_form_helper.py
Normal file
937
Lib/site-packages/crispy_forms/tests/test_form_helper.py
Normal file
@@ -0,0 +1,937 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
import django
|
||||
from django import forms
|
||||
from django.forms.models import formset_factory
|
||||
from django.middleware.csrf import _get_new_csrf_string
|
||||
from django.template import Context, Template, TemplateSyntaxError
|
||||
from django.test.html import parse_html
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from crispy_forms.bootstrap import AppendedText, FieldWithButtons, PrependedAppendedText, PrependedText, StrictButton
|
||||
from crispy_forms.helper import FormHelper, FormHelpersException
|
||||
from crispy_forms.layout import Button, Field, Hidden, Layout, MultiField, Reset, Submit
|
||||
from crispy_forms.templatetags.crispy_forms_tags import CrispyFormNode
|
||||
from crispy_forms.utils import render_crispy_form
|
||||
|
||||
from .conftest import only_bootstrap, only_bootstrap3, only_bootstrap4, only_uni_form
|
||||
from .forms import SampleForm, SampleForm7, SampleForm8, SampleFormWithMedia, SampleFormWithMultiValueField
|
||||
|
||||
|
||||
def test_inputs(settings):
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_input(Submit("my-submit", "Submit", css_class="button white"))
|
||||
form_helper.add_input(Reset("my-reset", "Reset"))
|
||||
form_helper.add_input(Hidden("my-hidden", "Hidden"))
|
||||
form_helper.add_input(Button("my-button", "Button"))
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
|
||||
assert "button white" in html
|
||||
assert 'id="submit-id-my-submit"' in html
|
||||
assert 'id="reset-id-my-reset"' in html
|
||||
assert 'name="my-hidden"' in html
|
||||
assert 'id="button-id-my-button"' in html
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert "submit submitButton" in html
|
||||
assert "reset resetButton" in html
|
||||
assert 'class="button"' in html
|
||||
else:
|
||||
assert 'class="btn"' in html
|
||||
assert "btn btn-primary" in html
|
||||
assert "btn btn-inverse" in html
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert len(re.findall(r"<input[^>]+> <", html)) == 9
|
||||
else:
|
||||
assert len(re.findall(r"<input[^>]+> <", html)) == 8
|
||||
|
||||
|
||||
def test_invalid_form_method():
|
||||
form_helper = FormHelper()
|
||||
with pytest.raises(FormHelpersException):
|
||||
form_helper.form_method = "superPost"
|
||||
|
||||
|
||||
def test_form_with_helper_without_layout(settings):
|
||||
form_helper = FormHelper()
|
||||
form_helper.form_id = "this-form-rocks"
|
||||
form_helper.form_class = "forms-that-rock"
|
||||
form_helper.form_method = "GET"
|
||||
form_helper.form_action = "simpleAction"
|
||||
form_helper.form_error_title = "ERRORS"
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy testForm form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
# now we render it, with errors
|
||||
form = SampleForm({"password1": "wargame", "password2": "god"})
|
||||
form.is_valid()
|
||||
c = Context({"testForm": form, "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
|
||||
# Lets make sure everything loads right
|
||||
assert html.count("<form") == 1
|
||||
assert "forms-that-rock" in html
|
||||
assert 'method="get"' in html
|
||||
assert 'id="this-form-rocks"' in html
|
||||
assert 'action="%s"' % reverse("simpleAction") in html
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert 'class="uniForm' in html
|
||||
|
||||
assert "ERRORS" in html
|
||||
assert "<li>Passwords dont match</li>" in html
|
||||
|
||||
# now lets remove the form tag and render it again. All the True items above
|
||||
# should now be false because the form tag is removed.
|
||||
form_helper.form_tag = False
|
||||
html = template.render(c)
|
||||
assert "<form" not in html
|
||||
assert "forms-that-rock" not in html
|
||||
assert 'method="get"' not in html
|
||||
assert 'id="this-form-rocks"' not in html
|
||||
|
||||
|
||||
def test_form_show_errors_non_field_errors():
|
||||
form = SampleForm({"password1": "wargame", "password2": "god"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.form_show_errors = True
|
||||
form.is_valid()
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy testForm %}
|
||||
"""
|
||||
)
|
||||
|
||||
# First we render with errors
|
||||
c = Context({"testForm": form})
|
||||
html = template.render(c)
|
||||
|
||||
# Ensure those errors were rendered
|
||||
assert "<li>Passwords dont match</li>" in html
|
||||
assert str(_("This field is required.")) in html
|
||||
assert "error" in html
|
||||
|
||||
# Now we render without errors
|
||||
form.helper.form_show_errors = False
|
||||
c = Context({"testForm": form})
|
||||
html = template.render(c)
|
||||
|
||||
# Ensure errors were not rendered
|
||||
assert "<li>Passwords dont match</li>" not in html
|
||||
assert str(_("This field is required.")) not in html
|
||||
assert "error" not in html
|
||||
|
||||
|
||||
def test_html5_required():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.html5_required = True
|
||||
html = render_crispy_form(form)
|
||||
# 6 out of 7 fields are required and an extra one for the SplitDateTimeWidget makes 7.
|
||||
if django.VERSION < (1, 10):
|
||||
assert html.count('required="required"') == 7
|
||||
else:
|
||||
assert len(re.findall(r"\brequired\b", html)) == 7
|
||||
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.html5_required = False
|
||||
html = render_crispy_form(form)
|
||||
|
||||
|
||||
def test_media_is_included_by_default_with_uniform():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "uni_form"
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" in html
|
||||
assert "test.js" in html
|
||||
|
||||
|
||||
def test_media_is_included_by_default_with_bootstrap():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap"
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" in html
|
||||
assert "test.js" in html
|
||||
|
||||
|
||||
def test_media_is_included_by_default_with_bootstrap3():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap3"
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" in html
|
||||
assert "test.js" in html
|
||||
|
||||
|
||||
def test_media_is_included_by_default_with_bootstrap4():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap4"
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" in html
|
||||
assert "test.js" in html
|
||||
|
||||
|
||||
def test_media_removed_when_include_media_is_false_with_uniform():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "uni_form"
|
||||
form.helper.include_media = False
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" not in html
|
||||
assert "test.js" not in html
|
||||
|
||||
|
||||
def test_media_removed_when_include_media_is_false_with_bootstrap():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap"
|
||||
form.helper.include_media = False
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" not in html
|
||||
assert "test.js" not in html
|
||||
|
||||
|
||||
def test_media_removed_when_include_media_is_false_with_bootstrap3():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap3"
|
||||
form.helper.include_media = False
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" not in html
|
||||
assert "test.js" not in html
|
||||
|
||||
|
||||
def test_media_removed_when_include_media_is_false_with_bootstrap4():
|
||||
form = SampleFormWithMedia()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap4"
|
||||
form.helper.include_media = False
|
||||
html = render_crispy_form(form)
|
||||
assert "test.css" not in html
|
||||
assert "test.js" not in html
|
||||
|
||||
|
||||
def test_attrs():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.attrs = {"id": "TestIdForm", "autocomplete": "off"}
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert 'autocomplete="off"' in html
|
||||
assert 'id="TestIdForm"' in html
|
||||
|
||||
|
||||
def test_template_context():
|
||||
helper = FormHelper()
|
||||
helper.attrs = {
|
||||
"id": "test-form",
|
||||
"class": "test-forms",
|
||||
"action": "submit/test/form",
|
||||
"autocomplete": "off",
|
||||
}
|
||||
node = CrispyFormNode("form", "helper")
|
||||
context = node.get_response_dict(helper, {}, False)
|
||||
|
||||
assert context["form_id"] == "test-form"
|
||||
assert context["form_attrs"]["id"] == "test-form"
|
||||
assert "test-forms" in context["form_class"]
|
||||
assert "test-forms" in context["form_attrs"]["class"]
|
||||
assert context["form_action"] == "submit/test/form"
|
||||
assert context["form_attrs"]["action"] == "submit/test/form"
|
||||
assert context["form_attrs"]["autocomplete"] == "off"
|
||||
|
||||
|
||||
def test_template_context_using_form_attrs():
|
||||
helper = FormHelper()
|
||||
helper.form_id = "test-form"
|
||||
helper.form_class = "test-forms"
|
||||
helper.form_action = "submit/test/form"
|
||||
node = CrispyFormNode("form", "helper")
|
||||
context = node.get_response_dict(helper, {}, False)
|
||||
|
||||
assert context["form_id"] == "test-form"
|
||||
assert context["form_attrs"]["id"] == "test-form"
|
||||
assert "test-forms" in context["form_class"]
|
||||
assert "test-forms" in context["form_attrs"]["class"]
|
||||
assert context["form_action"] == "submit/test/form"
|
||||
assert context["form_attrs"]["action"] == "submit/test/form"
|
||||
|
||||
|
||||
def test_template_helper_access():
|
||||
helper = FormHelper()
|
||||
helper.form_id = "test-form"
|
||||
|
||||
assert helper["form_id"] == "test-form"
|
||||
|
||||
|
||||
def test_without_helper(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm()})
|
||||
html = template.render(c)
|
||||
|
||||
# Lets make sure everything loads right
|
||||
assert "<form" in html
|
||||
assert 'method="post"' in html
|
||||
assert "action" not in html
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert "uniForm" in html
|
||||
|
||||
|
||||
def test_template_pack_override_compact(settings):
|
||||
current_pack = settings.CRISPY_TEMPLATE_PACK
|
||||
override_pack = current_pack == "uni_form" and "bootstrap" or "uni_form"
|
||||
|
||||
# {% crispy form 'template_pack_name' %}
|
||||
template = Template(
|
||||
"""
|
||||
{%% load crispy_forms_tags %%}
|
||||
{%% crispy form "%s" %%}
|
||||
"""
|
||||
% override_pack
|
||||
)
|
||||
c = Context({"form": SampleForm()})
|
||||
html = template.render(c)
|
||||
|
||||
if current_pack == "uni_form":
|
||||
assert "control-group" in html
|
||||
else:
|
||||
assert "uniForm" in html
|
||||
|
||||
|
||||
def test_template_pack_override_verbose(settings):
|
||||
current_pack = settings.CRISPY_TEMPLATE_PACK
|
||||
override_pack = current_pack == "uni_form" and "bootstrap" or "uni_form"
|
||||
|
||||
# {% crispy form helper 'template_pack_name' %}
|
||||
template = Template(
|
||||
"""
|
||||
{%% load crispy_forms_tags %%}
|
||||
{%% crispy form form_helper "%s" %%}
|
||||
"""
|
||||
% override_pack
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": FormHelper()})
|
||||
html = template.render(c)
|
||||
|
||||
if current_pack == "uni_form":
|
||||
assert "control-group" in html
|
||||
else:
|
||||
assert "uniForm" in html
|
||||
|
||||
|
||||
def test_template_pack_override_wrong():
|
||||
with pytest.raises(TemplateSyntaxError):
|
||||
Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form 'foo' %}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_invalid_helper(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": "invalid"})
|
||||
|
||||
settings.CRISPY_FAIL_SILENTLY = settings.TEMPLATE_DEBUG = False
|
||||
with pytest.raises(TypeError):
|
||||
template.render(c)
|
||||
|
||||
|
||||
def test_formset_with_helper_without_layout(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy testFormSet formset_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
form_helper = FormHelper()
|
||||
form_helper.form_id = "thisFormsetRocks"
|
||||
form_helper.form_class = "formsets-that-rock"
|
||||
form_helper.form_method = "POST"
|
||||
form_helper.form_action = "simpleAction"
|
||||
|
||||
SampleFormSet = formset_factory(SampleForm, extra=3)
|
||||
testFormSet = SampleFormSet()
|
||||
|
||||
c = Context({"testFormSet": testFormSet, "formset_helper": form_helper, "csrf_token": _get_new_csrf_string()})
|
||||
html = template.render(c)
|
||||
|
||||
assert html.count("<form") == 1
|
||||
assert html.count("csrfmiddlewaretoken") == 1
|
||||
|
||||
# Check formset management form
|
||||
assert "form-TOTAL_FORMS" in html
|
||||
assert "form-INITIAL_FORMS" in html
|
||||
assert "form-MAX_NUM_FORMS" in html
|
||||
|
||||
assert "formsets-that-rock" in html
|
||||
assert 'method="post"' in html
|
||||
assert 'id="thisFormsetRocks"' in html
|
||||
assert 'action="%s"' % reverse("simpleAction") in html
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert 'class="uniForm' in html
|
||||
|
||||
|
||||
def test_CSRF_token_POST_form():
|
||||
form_helper = FormHelper()
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
# The middleware only initializes the CSRF token when processing a real request
|
||||
# So using RequestContext or csrf(request) here does not work.
|
||||
# Instead I set the key `csrf_token` to a CSRF token manually, which `csrf_token` tag uses
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper, "csrf_token": _get_new_csrf_string()})
|
||||
html = template.render(c)
|
||||
|
||||
assert "csrfmiddlewaretoken" in html
|
||||
|
||||
|
||||
def test_CSRF_token_GET_form():
|
||||
form_helper = FormHelper()
|
||||
form_helper.form_method = "GET"
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper, "csrf_token": _get_new_csrf_string()})
|
||||
html = template.render(c)
|
||||
|
||||
assert "csrfmiddlewaretoken" not in html
|
||||
|
||||
|
||||
def test_disable_csrf():
|
||||
form = SampleForm()
|
||||
helper = FormHelper()
|
||||
helper.disable_csrf = True
|
||||
html = render_crispy_form(form, helper, {"csrf_token": _get_new_csrf_string()})
|
||||
assert "csrf" not in html
|
||||
|
||||
|
||||
def test_render_unmentioned_fields():
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
test_form.helper.render_unmentioned_fields = True
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 8
|
||||
|
||||
|
||||
def test_render_unmentioned_fields_order():
|
||||
test_form = SampleForm7()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
test_form.helper.render_unmentioned_fields = True
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 4
|
||||
assert (
|
||||
# From layout
|
||||
html.index('id="div_id_email"')
|
||||
# From form.Meta.fields
|
||||
< html.index('id="div_id_password"')
|
||||
< html.index('id="div_id_password2"')
|
||||
# From fields
|
||||
< html.index('id="div_id_is_company"')
|
||||
)
|
||||
|
||||
test_form = SampleForm8()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
test_form.helper.render_unmentioned_fields = True
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 4
|
||||
assert (
|
||||
# From layout
|
||||
html.index('id="div_id_email"')
|
||||
# From form.Meta.fields
|
||||
< html.index('id="div_id_password2"')
|
||||
< html.index('id="div_id_password"')
|
||||
# From fields
|
||||
< html.index('id="div_id_is_company"')
|
||||
)
|
||||
|
||||
|
||||
def test_render_hidden_fields():
|
||||
from .utils import contains_partial
|
||||
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
test_form.helper.render_hidden_fields = True
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 1
|
||||
|
||||
# Now hide a couple of fields
|
||||
for field in ("password1", "password2"):
|
||||
test_form.fields[field].widget = forms.HiddenInput()
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 3
|
||||
assert html.count("hidden") == 2
|
||||
|
||||
assert contains_partial(html, '<input name="password1" type="hidden"/>')
|
||||
assert contains_partial(html, '<input name="password2" type="hidden"/>')
|
||||
|
||||
|
||||
def test_render_required_fields():
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
test_form.helper.render_required_fields = True
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count("<input") == 7
|
||||
|
||||
|
||||
def test_helper_custom_template():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template = "custom_form_template.html"
|
||||
|
||||
html = render_crispy_form(form)
|
||||
assert "<h1>Special custom form</h1>" in html
|
||||
|
||||
|
||||
def test_helper_custom_field_template():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("password1", "password2",)
|
||||
form.helper.field_template = "custom_field_template.html"
|
||||
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("<h1>Special custom field</h1>") == 2
|
||||
|
||||
|
||||
def test_helper_custom_field_template_no_layout():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.field_template = "custom_field_template.html"
|
||||
|
||||
html = render_crispy_form(form)
|
||||
for field in form.fields:
|
||||
assert html.count('id="div_id_%s"' % field) == 1
|
||||
assert html.count("<h1>Special custom field</h1>") == len(form.fields)
|
||||
|
||||
|
||||
def test_helper_std_field_template_no_layout():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
|
||||
html = render_crispy_form(form)
|
||||
for field in form.fields:
|
||||
assert html.count('id="div_id_%s"' % field) == 1
|
||||
|
||||
|
||||
@only_uni_form
|
||||
def test_form_show_errors():
|
||||
form = SampleForm(
|
||||
{
|
||||
"email": "invalidemail",
|
||||
"first_name": "first_name_too_long",
|
||||
"last_name": "last_name_too_long",
|
||||
"password1": "yes",
|
||||
"password2": "yes",
|
||||
}
|
||||
)
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
Field("email"), Field("first_name"), Field("last_name"), Field("password1"), Field("password2"),
|
||||
)
|
||||
form.is_valid()
|
||||
|
||||
form.helper.form_show_errors = True
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 9
|
||||
|
||||
form.helper.form_show_errors = False
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 0
|
||||
|
||||
|
||||
@only_uni_form
|
||||
def test_multifield_errors():
|
||||
form = SampleForm({"email": "invalidemail", "password1": "yes", "password2": "yes"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(MultiField("legend", "email"))
|
||||
form.is_valid()
|
||||
|
||||
form.helper.form_show_errors = True
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 3
|
||||
|
||||
# Reset layout for avoiding side effects
|
||||
form.helper.layout = Layout(MultiField("legend", "email"))
|
||||
form.helper.form_show_errors = False
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 0
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_bootstrap_form_show_errors_bs3():
|
||||
form = SampleForm(
|
||||
{
|
||||
"email": "invalidemail",
|
||||
"first_name": "first_name_too_long",
|
||||
"last_name": "last_name_too_long",
|
||||
"password1": "yes",
|
||||
"password2": "yes",
|
||||
}
|
||||
)
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
AppendedText("email", "whatever"),
|
||||
PrependedText("first_name", "blabla"),
|
||||
PrependedAppendedText("last_name", "foo", "bar"),
|
||||
AppendedText("password1", "whatever"),
|
||||
PrependedText("password2", "blabla"),
|
||||
)
|
||||
form.is_valid()
|
||||
|
||||
form.helper.form_show_errors = True
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 6
|
||||
|
||||
form.helper.form_show_errors = False
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 0
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_bootstrap_form_show_errors_bs4():
|
||||
form = SampleForm(
|
||||
{
|
||||
"email": "invalidemail",
|
||||
"first_name": "first_name_too_long",
|
||||
"last_name": "last_name_too_long",
|
||||
"password1": "yes",
|
||||
"password2": "yes",
|
||||
}
|
||||
)
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
AppendedText("email", "whatever"),
|
||||
PrependedText("first_name", "blabla"),
|
||||
PrependedAppendedText("last_name", "foo", "bar"),
|
||||
AppendedText("password1", "whatever"),
|
||||
PrependedText("password2", "blabla"),
|
||||
)
|
||||
form.is_valid()
|
||||
|
||||
form.helper.form_show_errors = True
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 3
|
||||
|
||||
form.helper.form_show_errors = False
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("error") == 0
|
||||
|
||||
|
||||
@only_bootstrap
|
||||
def test_error_text_inline(settings):
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
layout = Layout(
|
||||
AppendedText("first_name", "wat"), PrependedText("email", "@"), PrependedAppendedText("last_name", "@", "wat"),
|
||||
)
|
||||
form.helper.layout = layout
|
||||
form.is_valid()
|
||||
html = render_crispy_form(form)
|
||||
|
||||
help_class = "help-inline"
|
||||
help_tag_name = "p"
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
help_class = "help-block"
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
help_class = "invalid-feedback"
|
||||
help_tag_name = "div"
|
||||
|
||||
matches = re.findall(r'<span id="error_\d_\w*" class="%s"' % help_class, html, re.MULTILINE)
|
||||
assert len(matches) == 3
|
||||
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = layout
|
||||
form.helper.error_text_inline = False
|
||||
html = render_crispy_form(form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK in ["bootstrap", "bootstrap3"]:
|
||||
help_class = "help-block"
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
help_class = "invalid-feedback"
|
||||
help_tag_name = "p"
|
||||
|
||||
matches = re.findall(r'<{} id="error_\d_\w*" class="{}"'.format(help_tag_name, help_class), html, re.MULTILINE)
|
||||
assert len(matches) == 3
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_error_and_help_inline_bootstrap3():
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.error_text_inline = False
|
||||
form.helper.help_text_inline = True
|
||||
form.helper.layout = Layout("email")
|
||||
form.is_valid()
|
||||
html = render_crispy_form(form)
|
||||
|
||||
# Check that help goes before error, otherwise CSS won't work
|
||||
help_position = html.find('<span id="hint_id_email" class="help-inline">')
|
||||
error_position = html.find('<p id="error_1_id_email" class="help-block">')
|
||||
assert help_position < error_position
|
||||
|
||||
# Viceversa
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.error_text_inline = True
|
||||
form.helper.help_text_inline = False
|
||||
form.helper.layout = Layout("email")
|
||||
form.is_valid()
|
||||
html = render_crispy_form(form)
|
||||
|
||||
# Check that error goes before help, otherwise CSS won't work
|
||||
error_position = html.find('<span id="error_1_id_email" class="help-inline">')
|
||||
help_position = html.find('<div id="hint_id_email" class="help-block">')
|
||||
assert error_position < help_position
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_error_and_help_inline():
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.error_text_inline = False
|
||||
form.helper.help_text_inline = True
|
||||
form.helper.layout = Layout("email")
|
||||
form.is_valid()
|
||||
html = render_crispy_form(form)
|
||||
|
||||
# Check that help goes before error, otherwise CSS won't work
|
||||
help_position = html.find('<span id="hint_id_email" class="help-inline">')
|
||||
error_position = html.find('<p id="error_1_id_email" class="invalid-feedback">')
|
||||
assert help_position < error_position
|
||||
|
||||
# Viceversa
|
||||
form = SampleForm({"email": "invalidemail"})
|
||||
form.helper = FormHelper()
|
||||
form.helper.error_text_inline = True
|
||||
form.helper.help_text_inline = False
|
||||
form.helper.layout = Layout("email")
|
||||
form.is_valid()
|
||||
html = render_crispy_form(form)
|
||||
|
||||
# Check that error goes before help, otherwise CSS won't work
|
||||
error_position = html.find('<span id="error_1_id_email" class="help-inline">')
|
||||
help_position = html.find('<small id="hint_id_email" class="form-text text-muted">')
|
||||
assert error_position < help_position
|
||||
|
||||
|
||||
@only_bootstrap
|
||||
def test_form_show_labels():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
"password1",
|
||||
FieldWithButtons("password2", StrictButton("Confirm")),
|
||||
PrependedText("first_name", "Mr."),
|
||||
AppendedText("last_name", "@"),
|
||||
PrependedAppendedText("datetime_field", "on", "secs"),
|
||||
)
|
||||
form.helper.form_show_labels = False
|
||||
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("<label") == 0
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_label_class_and_field_class():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.label_class = "col-lg-2"
|
||||
form.helper.field_class = "col-lg-8"
|
||||
html = render_crispy_form(form)
|
||||
dom = parse_html(html)
|
||||
|
||||
snippet = parse_html(
|
||||
'<div class="form-group"> <div class="controls col-lg-offset-2 col-lg-8"> '
|
||||
'<div id="div_id_is_company" class="checkbox"> <label for="id_is_company" class=""> '
|
||||
'<input class="checkboxinput" id="id_is_company" name="is_company" type="checkbox" />company'
|
||||
)
|
||||
assert dom.count(snippet)
|
||||
assert html.count("col-lg-8") == 7
|
||||
|
||||
form.helper.label_class = "col-sm-3 col-md-4"
|
||||
form.helper.field_class = "col-sm-8 col-md-6"
|
||||
html = render_crispy_form(form)
|
||||
dom = parse_html(html)
|
||||
|
||||
snippet = parse_html(
|
||||
'<div class="form-group"> <div class="controls col-sm-offset-3 col-md-offset-4 col-sm-8 col-md-6"> '
|
||||
'<div id="div_id_is_company" class="checkbox"> <label for="id_is_company" class=""> '
|
||||
'<input class="checkboxinput" id="id_is_company" name="is_company" type="checkbox" />company'
|
||||
)
|
||||
assert dom.count(snippet)
|
||||
assert html.count("col-sm-8") == 7
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_template_pack():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "uni_form"
|
||||
html = render_crispy_form(form)
|
||||
assert "form-control" not in html
|
||||
assert "ctrlHolder" in html
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_label_class_and_field_class_bs4():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.label_class = "col-lg-2"
|
||||
form.helper.field_class = "col-lg-8"
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert '<div class="form-group">' in html
|
||||
assert '<div class="col-lg-8">' in html
|
||||
assert html.count("col-lg-8") == 7
|
||||
assert "offset" not in html
|
||||
|
||||
form.helper.label_class = "col-sm-3 col-md-4"
|
||||
form.helper.field_class = "col-sm-8 col-md-6"
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert '<div class="form-group">' in html
|
||||
assert '<div class="col-sm-8 col-md-6">' in html
|
||||
assert html.count("col-sm-8") == 7
|
||||
assert "offset" not in html
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_label_class_and_field_class_bs4_offset_when_horizontal():
|
||||
# Test col-XX-YY pattern
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.label_class = "col-lg-2"
|
||||
form.helper.field_class = "col-lg-8"
|
||||
form.helper.form_class = "form-horizontal"
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert '<div class="form-group row">' in html
|
||||
assert '<div class="offset-lg-2 col-lg-8">' in html
|
||||
assert html.count("col-lg-8") == 7
|
||||
|
||||
# Test multi col-XX-YY pattern and col-X pattern
|
||||
|
||||
form.helper.label_class = "col-sm-3 col-md-4 col-5 col-lg-4"
|
||||
form.helper.field_class = "col-sm-8 col-md-6 col-7 col-lg-8"
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert '<div class="form-group row">' in html
|
||||
assert '<div class="offset-sm-3 offset-md-4 offset-5 offset-lg-4 col-sm-8 col-md-6 col-7 col-lg-8">' in html
|
||||
assert html.count("col-sm-8") == 7
|
||||
assert html.count("col-md-6") == 7
|
||||
assert html.count("col-7") == 7
|
||||
assert html.count("col-lg-8") == 7
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_form_group_with_form_inline_bs4():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
html = render_crispy_form(form)
|
||||
assert '<div class="form-group">' in html
|
||||
|
||||
# .row class shouldn't be together with .form-group in inline forms
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.form_class = "form-inline"
|
||||
form.helper.field_template = "bootstrap4/layout/inline_field.html"
|
||||
html = render_crispy_form(form)
|
||||
assert '<div class="form-group row">' not in html
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_template_pack_bs4():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "uni_form"
|
||||
html = render_crispy_form(form)
|
||||
assert "form-control" not in html
|
||||
assert "ctrlHolder" in html
|
||||
|
||||
|
||||
def test_passthrough_context():
|
||||
"""
|
||||
Test to ensure that context is passed through implicitly from outside of
|
||||
the crispy form into the crispy form templates.
|
||||
"""
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template = "custom_form_template_with_context.html"
|
||||
|
||||
c = {"prefix": "foo", "suffix": "bar"}
|
||||
|
||||
html = render_crispy_form(form, helper=form.helper, context=c)
|
||||
assert "Got prefix: foo" in html
|
||||
assert "Got suffix: bar" in html
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_bootstrap3_does_add_form_control_class_to_non_multivaluefield():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap3"
|
||||
html = render_crispy_form(form)
|
||||
assert "form-control" in html
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_bootstrap3_does_not_add_form_control_class_to_multivaluefield():
|
||||
form = SampleFormWithMultiValueField()
|
||||
form.helper = FormHelper()
|
||||
form.helper.template_pack = "bootstrap3"
|
||||
html = render_crispy_form(form)
|
||||
assert "form-control" not in html
|
||||
630
Lib/site-packages/crispy_forms/tests/test_layout.py
Normal file
630
Lib/site-packages/crispy_forms/tests/test_layout.py
Normal file
@@ -0,0 +1,630 @@
|
||||
import pytest
|
||||
|
||||
from django import forms
|
||||
from django.forms.models import formset_factory, modelformset_factory
|
||||
from django.middleware.csrf import _get_new_csrf_string
|
||||
from django.shortcuts import render
|
||||
from django.template import Context, Template
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from crispy_forms.bootstrap import Field, InlineCheckboxes
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import HTML, ButtonHolder, Column, Div, Fieldset, Layout, MultiField, Row, Submit
|
||||
from crispy_forms.utils import render_crispy_form
|
||||
|
||||
from .conftest import only_bootstrap, only_bootstrap3, only_bootstrap4, only_uni_form
|
||||
from .forms import (
|
||||
CheckboxesSampleForm,
|
||||
CrispyEmptyChoiceTestModel,
|
||||
CrispyTestModel,
|
||||
FileForm,
|
||||
SampleForm,
|
||||
SampleForm2,
|
||||
SampleForm3,
|
||||
SampleForm4,
|
||||
SampleForm6,
|
||||
)
|
||||
from .utils import contains_partial
|
||||
|
||||
|
||||
def test_invalid_unicode_characters(settings):
|
||||
# Adds a BooleanField that uses non valid unicode characters "ñ"
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(Layout("españa"))
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper})
|
||||
settings.CRISPY_FAIL_SILENTLY = False
|
||||
with pytest.raises(Exception):
|
||||
template.render(c)
|
||||
|
||||
|
||||
def test_unicode_form_field():
|
||||
class UnicodeForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["contraseña"] = forms.CharField()
|
||||
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout("contraseña")
|
||||
|
||||
html = render_crispy_form(UnicodeForm())
|
||||
assert 'id="id_contraseña"' in html
|
||||
|
||||
|
||||
def test_meta_extra_fields_with_missing_fields():
|
||||
class FormWithMeta(SampleForm):
|
||||
class Meta:
|
||||
fields = ("email", "first_name", "last_name")
|
||||
|
||||
form = FormWithMeta()
|
||||
# We remove email field on the go
|
||||
del form.fields["email"]
|
||||
|
||||
form_helper = FormHelper()
|
||||
form_helper.layout = Layout("first_name",)
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": form, "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
assert "email" not in html
|
||||
|
||||
|
||||
def test_layout_unresolved_field(settings):
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(Layout("typo"))
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper})
|
||||
settings.CRISPY_FAIL_SILENTLY = False
|
||||
with pytest.raises(Exception):
|
||||
template.render(c)
|
||||
|
||||
|
||||
def test_double_rendered_field(settings):
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(Layout("is_company", "is_company",))
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper})
|
||||
settings.CRISPY_FAIL_SILENTLY = False
|
||||
with pytest.raises(Exception):
|
||||
template.render(c)
|
||||
|
||||
|
||||
def test_context_pollution():
|
||||
class ExampleForm(forms.Form):
|
||||
comment = forms.CharField()
|
||||
|
||||
form = ExampleForm()
|
||||
form2 = SampleForm()
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ form.as_ul }}
|
||||
{% crispy form2 %}
|
||||
{{ form.as_ul }}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": form, "form2": form2})
|
||||
html = template.render(c)
|
||||
|
||||
assert html.count('name="comment"') == 2
|
||||
assert html.count('name="is_company"') == 1
|
||||
|
||||
|
||||
def test_layout_fieldset_row_html_with_unicode_fieldnames(settings):
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
Fieldset(
|
||||
"Company Data",
|
||||
"is_company",
|
||||
css_id="fieldset_company_data",
|
||||
css_class="fieldsets",
|
||||
title="fieldset_title",
|
||||
test_fieldset="123",
|
||||
),
|
||||
Fieldset(
|
||||
"User Data",
|
||||
"email",
|
||||
Row("password1", "password2", css_id="row_passwords", css_class="rows",),
|
||||
HTML('<a href="#" id="testLink">test link</a>'),
|
||||
HTML(
|
||||
"""
|
||||
{% if flag %}{{ message }}{% endif %}
|
||||
"""
|
||||
),
|
||||
"first_name",
|
||||
"last_name",
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper, "flag": True, "message": "Hello!"})
|
||||
html = template.render(c)
|
||||
|
||||
assert 'id="fieldset_company_data"' in html
|
||||
assert 'class="fieldsets' in html
|
||||
assert 'title="fieldset_title"' in html
|
||||
assert 'test-fieldset="123"' in html
|
||||
assert 'id="row_passwords"' in html
|
||||
assert html.count("<label") == 6
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert 'class="formRow rows"' in html
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert 'class="form-row rows"' in html
|
||||
else:
|
||||
assert 'class="row rows"' in html
|
||||
assert "Hello!" in html
|
||||
assert "testLink" in html
|
||||
|
||||
|
||||
def test_change_layout_dynamically_delete_field():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
form = SampleForm()
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
Fieldset("Company Data", "is_company", "email", "password1", "password2", css_id="multifield_info",),
|
||||
Column("first_name", "last_name", css_id="column_name",),
|
||||
)
|
||||
)
|
||||
|
||||
# We remove email field on the go
|
||||
# Layout needs to be adapted for the new form fields
|
||||
del form.fields["email"]
|
||||
del form_helper.layout.fields[0].fields[1]
|
||||
|
||||
c = Context({"form": form, "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
assert "email" not in html
|
||||
|
||||
|
||||
def test_column_has_css_classes(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
form = SampleForm()
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
Fieldset("Company Data", "is_company", "email", "password1", "password2", css_id="multifield_info",),
|
||||
Column("first_name", "last_name",),
|
||||
)
|
||||
)
|
||||
|
||||
c = Context({"form": form, "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert html.count("formColumn") == 1
|
||||
assert html.count("col") == 0
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count("formColumn") == 0
|
||||
assert html.count("col-md") == 1
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_bs4_column_css_classes(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
|
||||
form = SampleForm()
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
Column("first_name", "last_name",),
|
||||
Column("first_name", "last_name", css_class="col-sm"),
|
||||
Column("first_name", "last_name", css_class="mb-4"),
|
||||
)
|
||||
)
|
||||
|
||||
c = Context({"form": form, "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
|
||||
assert html.count("col-md") == 2
|
||||
assert html.count("col-sm") == 1
|
||||
|
||||
|
||||
def test_formset_layout(settings):
|
||||
SampleFormSet = formset_factory(SampleForm, extra=3)
|
||||
formset = SampleFormSet()
|
||||
helper = FormHelper()
|
||||
helper.form_id = "thisFormsetRocks"
|
||||
helper.form_class = "formsets-that-rock"
|
||||
helper.form_method = "POST"
|
||||
helper.form_action = "simpleAction"
|
||||
helper.layout = Layout(
|
||||
Fieldset("Item {{ forloop.counter }}", "is_company", "email",),
|
||||
HTML("{% if forloop.first %}Note for first form only{% endif %}"),
|
||||
Row("password1", "password2"),
|
||||
Fieldset("", "first_name", "last_name"),
|
||||
)
|
||||
|
||||
html = render_crispy_form(form=formset, helper=helper, context={"csrf_token": _get_new_csrf_string()})
|
||||
|
||||
# Check formset fields
|
||||
assert contains_partial(html, '<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3"/>')
|
||||
assert contains_partial(
|
||||
html, '<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0"/>'
|
||||
)
|
||||
assert contains_partial(
|
||||
html, '<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000"/>'
|
||||
)
|
||||
assert contains_partial(
|
||||
html, '<input id="id_form-MIN_NUM_FORMS" name="form-MIN_NUM_FORMS" type="hidden" value="0"/>'
|
||||
)
|
||||
assert html.count("hidden") == 5
|
||||
|
||||
# Check form structure
|
||||
assert html.count("<form") == 1
|
||||
assert html.count("csrfmiddlewaretoken") == 1
|
||||
assert "formsets-that-rock" in html
|
||||
assert 'method="post"' in html
|
||||
assert 'id="thisFormsetRocks"' in html
|
||||
assert 'action="%s"' % reverse("simpleAction") in html
|
||||
|
||||
# Check form layout
|
||||
assert "Item 1" in html
|
||||
assert "Item 2" in html
|
||||
assert "Item 3" in html
|
||||
assert html.count("Note for first form only") == 1
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert html.count("formRow") == 3
|
||||
elif settings.CRISPY_TEMPLATE_PACK in ("bootstrap3", "bootstrap4"):
|
||||
assert html.count("row") == 3
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count("form-group") == 18
|
||||
|
||||
|
||||
def test_modelformset_layout():
|
||||
CrispyModelFormSet = modelformset_factory(CrispyTestModel, form=SampleForm4, extra=3)
|
||||
formset = CrispyModelFormSet(queryset=CrispyTestModel.objects.none())
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout("email")
|
||||
|
||||
html = render_crispy_form(form=formset, helper=helper)
|
||||
|
||||
assert html.count("id_form-0-id") == 1
|
||||
assert html.count("id_form-1-id") == 1
|
||||
assert html.count("id_form-2-id") == 1
|
||||
|
||||
assert contains_partial(html, '<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="3"/>')
|
||||
assert contains_partial(
|
||||
html, '<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0"/>'
|
||||
)
|
||||
assert contains_partial(
|
||||
html, '<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000"/>'
|
||||
)
|
||||
|
||||
assert html.count('name="form-0-email"') == 1
|
||||
assert html.count('name="form-1-email"') == 1
|
||||
assert html.count('name="form-2-email"') == 1
|
||||
assert html.count('name="form-3-email"') == 0
|
||||
assert html.count("password") == 0
|
||||
|
||||
|
||||
def test_i18n():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form.helper %}
|
||||
"""
|
||||
)
|
||||
form = SampleForm()
|
||||
form_helper = FormHelper()
|
||||
form_helper.layout = Layout(HTML(_("i18n text")), Fieldset(_("i18n legend"), "first_name", "last_name",))
|
||||
form.helper = form_helper
|
||||
|
||||
html = template.render(Context({"form": form}))
|
||||
assert html.count("i18n legend") == 1
|
||||
|
||||
|
||||
def test_default_layout():
|
||||
test_form = SampleForm2()
|
||||
assert test_form.helper.layout.fields == [
|
||||
"is_company",
|
||||
"email",
|
||||
"password1",
|
||||
"password2",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"datetime_field",
|
||||
]
|
||||
|
||||
|
||||
def test_default_layout_two():
|
||||
test_form = SampleForm3()
|
||||
assert test_form.helper.layout.fields == ["email"]
|
||||
|
||||
|
||||
def test_modelform_layout_without_meta():
|
||||
test_form = SampleForm4()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email")
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert "email" in html
|
||||
assert "password" not in html
|
||||
|
||||
|
||||
def test_specialspaceless_not_screwing_intended_spaces():
|
||||
# see issue #250
|
||||
test_form = SampleForm()
|
||||
test_form.fields["email"].widget = forms.Textarea()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout("email", HTML("<span>first span</span> <span>second span</span>"))
|
||||
html = render_crispy_form(test_form)
|
||||
assert "<span>first span</span> <span>second span</span>" in html
|
||||
|
||||
|
||||
def test_choice_with_none_is_selected():
|
||||
# see issue #701
|
||||
model_instance = CrispyEmptyChoiceTestModel()
|
||||
model_instance.fruit = None
|
||||
test_form = SampleForm6(instance=model_instance)
|
||||
html = render_crispy_form(test_form)
|
||||
assert "checked" in html
|
||||
|
||||
|
||||
@only_uni_form
|
||||
def test_layout_composition():
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
Layout(MultiField("Some company data", "is_company", "email", css_id="multifield_info",),),
|
||||
Column(
|
||||
"first_name",
|
||||
# 'last_name', Missing a field on purpose
|
||||
css_id="column_name",
|
||||
css_class="columns",
|
||||
),
|
||||
ButtonHolder(Submit("Save", "Save", css_class="button white"),),
|
||||
Div("password1", "password2", css_id="custom-div", css_class="customdivs",),
|
||||
)
|
||||
)
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper})
|
||||
html = template.render(c)
|
||||
|
||||
assert "multiField" in html
|
||||
assert "formColumn" in html
|
||||
assert 'id="multifield_info"' in html
|
||||
assert 'id="column_name"' in html
|
||||
assert 'class="formColumn columns"' in html
|
||||
assert 'class="buttonHolder">' in html
|
||||
assert 'input type="submit"' in html
|
||||
assert 'name="Save"' in html
|
||||
assert 'id="custom-div"' in html
|
||||
assert 'class="customdivs"' in html
|
||||
assert "last_name" not in html
|
||||
|
||||
|
||||
@only_uni_form
|
||||
def test_second_layout_multifield_column_buttonholder_submit_div():
|
||||
form_helper = FormHelper()
|
||||
form_helper.add_layout(
|
||||
Layout(
|
||||
MultiField(
|
||||
"Some company data",
|
||||
"is_company",
|
||||
"email",
|
||||
css_id="multifield_info",
|
||||
title="multifield_title",
|
||||
multifield_test="123",
|
||||
),
|
||||
Column("first_name", "last_name", css_id="column_name", css_class="columns",),
|
||||
ButtonHolder(
|
||||
Submit(
|
||||
"Save the world", "{{ value_var }}", css_class="button white", data_id="test", data_name="test"
|
||||
),
|
||||
Submit("store", "Store results"),
|
||||
),
|
||||
Div("password1", "password2", css_id="custom-div", css_class="customdivs", test_markup="123"),
|
||||
)
|
||||
)
|
||||
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form form_helper %}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm(), "form_helper": form_helper, "value_var": "Save"})
|
||||
html = template.render(c)
|
||||
|
||||
assert "multiField" in html
|
||||
assert "formColumn" in html
|
||||
assert 'id="multifield_info"' in html
|
||||
assert 'title="multifield_title"' in html
|
||||
assert 'multifield-test="123"' in html
|
||||
assert 'id="column_name"' in html
|
||||
assert 'class="formColumn columns"' in html
|
||||
assert 'class="buttonHolder">' in html
|
||||
assert 'input type="submit"' in html
|
||||
assert "button white" in html
|
||||
assert 'data-id="test"' in html
|
||||
assert 'data-name="test"' in html
|
||||
assert 'name="save-the-world"' in html
|
||||
assert 'value="Save"' in html
|
||||
assert 'name="store"' in html
|
||||
assert 'value="Store results"' in html
|
||||
assert 'id="custom-div"' in html
|
||||
assert 'class="customdivs"' in html
|
||||
assert 'test-markup="123"' in html
|
||||
|
||||
|
||||
@only_bootstrap
|
||||
def test_keepcontext_context_manager(settings):
|
||||
# Test case for issue #180
|
||||
# Apparently it only manifest when using render_to_response this exact way
|
||||
form = CheckboxesSampleForm()
|
||||
form.helper = FormHelper()
|
||||
# We use here InlineCheckboxes as it updates context in an unsafe way
|
||||
form.helper.layout = Layout("checkboxes", InlineCheckboxes("alphacheckboxes"), "numeric_multiple_checkboxes")
|
||||
context = {"form": form}
|
||||
|
||||
response = render(request=None, template_name="crispy_render_template.html", context=context)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert response.content.count(b"checkbox inline") == 3
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert response.content.count(b"checkbox-inline") == 3
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert response.content.count(b"custom-control-inline") == 3
|
||||
assert response.content.count(b"custom-checkbox") > 0
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_use_custom_control_is_used():
|
||||
form = CheckboxesSampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("checkboxes", InlineCheckboxes("alphacheckboxes"), "numeric_multiple_checkboxes")
|
||||
# form.helper.use_custom_control take default value which is True
|
||||
|
||||
response = render(request=None, template_name="crispy_render_template.html", context={"form": form})
|
||||
assert response.content.count(b"custom-control-inline") == 3
|
||||
assert response.content.count(b"custom-checkbox") == 9
|
||||
|
||||
form.helper.use_custom_control = True
|
||||
|
||||
response = render(request=None, template_name="crispy_render_template.html", context={"form": form})
|
||||
assert response.content.count(b"custom-control-inline") == 3
|
||||
assert response.content.count(b"custom-checkbox") == 9
|
||||
|
||||
form.helper.use_custom_control = False
|
||||
|
||||
response = render(request=None, template_name="crispy_render_template.html", context={"form": form})
|
||||
|
||||
assert response.content.count(b"custom-control-inline") == 0
|
||||
assert response.content.count(b"form-check-inline") == 3
|
||||
assert response.content.count(b"form-check") > 0
|
||||
assert response.content.count(b"custom-checkbox") == 0
|
||||
|
||||
|
||||
@only_bootstrap3
|
||||
def test_form_inline():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.form_class = "form-inline"
|
||||
form.helper.field_template = "bootstrap3/layout/inline_field.html"
|
||||
form.helper.layout = Layout("email", "password1", "last_name",)
|
||||
|
||||
html = render_crispy_form(form)
|
||||
assert html.count('class="form-inline"') == 1
|
||||
assert html.count('class="form-group"') == 3
|
||||
assert html.count('<label for="id_email" class="sr-only') == 1
|
||||
assert html.count('id="div_id_email" class="form-group"') == 1
|
||||
assert html.count('placeholder="email"') == 1
|
||||
assert html.count("</label> <input") == 3
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_bootstrap4_form_inline():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.form_class = "form-inline"
|
||||
form.helper.field_template = "bootstrap4/layout/inline_field.html"
|
||||
form.helper.layout = Layout("email", "password1", "last_name",)
|
||||
|
||||
html = render_crispy_form(form)
|
||||
assert html.count('class="form-inline"') == 1
|
||||
assert html.count('class="input-group"') == 3
|
||||
assert html.count('<label for="id_email" class="sr-only') == 1
|
||||
assert html.count('id="div_id_email" class="input-group"') == 1
|
||||
assert html.count('placeholder="email"') == 1
|
||||
assert html.count("</label> <input") == 3
|
||||
|
||||
|
||||
def test_update_attributes_class():
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("email", Field("password1"), "password2",)
|
||||
form.helper["password1"].update_attributes(css_class="hello")
|
||||
html = render_crispy_form(form)
|
||||
assert html.count(' class="hello textinput') == 1
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("email", Field("password1", css_class="hello"), "password2",)
|
||||
form.helper["password1"].update_attributes(css_class="hello2")
|
||||
html = render_crispy_form(form)
|
||||
assert html.count(' class="hello hello2 textinput') == 1
|
||||
|
||||
|
||||
@only_bootstrap4
|
||||
def test_file_field():
|
||||
form = FileForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("clearable_file")
|
||||
html = render_crispy_form(form)
|
||||
assert '<span class="custom-control custom-checkbox">' in html
|
||||
assert '<input type="file" name="clearable_file" class="custom-file-input" >' in html
|
||||
|
||||
form.helper.use_custom_control = False
|
||||
html = render_crispy_form(form)
|
||||
assert '<input type="checkbox" name="clearable_file-clear" id="clearable_file-clear_id">' in html
|
||||
assert '<input type="file" name="clearable_file" class="custom-file-input" >' not in html
|
||||
|
||||
form.helper.use_custom_control = True
|
||||
form.helper.layout = Layout("file_field")
|
||||
html = render_crispy_form(form)
|
||||
assert '<div class="form-control custom-file"' in html
|
||||
assert '<input type="file" name="file_field" class="custom-file-input"' in html
|
||||
assert '<label class="custom-file-label' in html
|
||||
assert 'for="id_file_field">---</label>' in html
|
||||
|
||||
form.helper.use_custom_control = False
|
||||
html = render_crispy_form(form)
|
||||
assert "custom-file" not in html
|
||||
assert "custom-file-input" not in html
|
||||
assert "custom-file-label" not in html
|
||||
484
Lib/site-packages/crispy_forms/tests/test_layout_objects.py
Normal file
484
Lib/site-packages/crispy_forms/tests/test_layout_objects.py
Normal file
@@ -0,0 +1,484 @@
|
||||
from django import forms
|
||||
from django.template import Context, Template
|
||||
from django.test.html import parse_html
|
||||
from django.utils.translation import activate, deactivate
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from crispy_forms.bootstrap import (
|
||||
Accordion,
|
||||
AccordionGroup,
|
||||
Alert,
|
||||
AppendedText,
|
||||
FieldWithButtons,
|
||||
InlineCheckboxes,
|
||||
InlineRadios,
|
||||
PrependedAppendedText,
|
||||
PrependedText,
|
||||
StrictButton,
|
||||
Tab,
|
||||
TabHolder,
|
||||
)
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import HTML, Field, Layout, MultiWidgetField
|
||||
from crispy_forms.tests.utils import contains_partial
|
||||
from crispy_forms.utils import render_crispy_form
|
||||
|
||||
from .conftest import only_bootstrap
|
||||
from .forms import CheckboxesSampleForm, SampleForm
|
||||
|
||||
|
||||
def test_field_with_custom_template():
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(Field("email", template="custom_field_template.html"))
|
||||
|
||||
html = render_crispy_form(test_form)
|
||||
assert "<h1>Special custom field</h1>" in html
|
||||
|
||||
|
||||
def test_multiwidget_field():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy form %}
|
||||
"""
|
||||
)
|
||||
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
MultiWidgetField(
|
||||
"datetime_field",
|
||||
attrs=({"rel": "test_dateinput"}, {"rel": "test_timeinput", "style": "width: 30px;", "type": "hidden"}),
|
||||
)
|
||||
)
|
||||
|
||||
c = Context({"form": test_form})
|
||||
|
||||
html = template.render(c)
|
||||
|
||||
assert html.count('class="dateinput') == 1
|
||||
assert html.count('rel="test_dateinput"') == 1
|
||||
assert html.count('rel="test_timeinput"') == 2
|
||||
assert html.count('style="width: 30px;"') == 2
|
||||
assert html.count('type="hidden"') == 2
|
||||
|
||||
|
||||
def test_field_type_hidden():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{% crispy test_form %}
|
||||
"""
|
||||
)
|
||||
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(Field("email", type="hidden", data_test=12), Field("datetime_field"),)
|
||||
|
||||
c = Context({"test_form": test_form})
|
||||
html = template.render(c)
|
||||
|
||||
# Check form parameters
|
||||
assert html.count('data-test="12"') == 1
|
||||
assert html.count('name="email"') == 1
|
||||
assert html.count('class="dateinput') == 1
|
||||
assert html.count('class="timeinput') == 1
|
||||
|
||||
|
||||
def test_field_wrapper_class(settings):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(Field("email", wrapper_class="testing"))
|
||||
|
||||
html = render_crispy_form(form)
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count('class="control-group testing"') == 1
|
||||
elif settings.CRISPY_TEMPLATE_PACK in ("bootstrap3", "bootstrap4"):
|
||||
assert html.count('class="form-group testing"') == 1
|
||||
|
||||
|
||||
def test_html_with_carriage_returns(settings):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
HTML(
|
||||
"""
|
||||
if (a==b){
|
||||
// some comment
|
||||
a+1;
|
||||
foo();
|
||||
}
|
||||
"""
|
||||
)
|
||||
)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "uni_form":
|
||||
assert html.count("\n") == 23
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count("\n") == 25
|
||||
else:
|
||||
assert html.count("\n") == 27
|
||||
|
||||
|
||||
def test_i18n():
|
||||
activate("es")
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(HTML(_("Enter a valid value.")))
|
||||
html = render_crispy_form(form)
|
||||
assert "Introduzca un valor válido" in html
|
||||
|
||||
deactivate()
|
||||
|
||||
|
||||
def test_remove_labels():
|
||||
form = SampleForm()
|
||||
# remove boolean field as label is still printed in boostrap
|
||||
del form.fields["is_company"]
|
||||
|
||||
for fields in form:
|
||||
fields.label = False
|
||||
|
||||
html = render_crispy_form(form)
|
||||
|
||||
assert "<label" not in html
|
||||
|
||||
|
||||
@only_bootstrap
|
||||
class TestBootstrapLayoutObjects:
|
||||
def test_custom_django_widget(self, settings):
|
||||
class CustomRadioSelect(forms.RadioSelect):
|
||||
pass
|
||||
|
||||
class CustomCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
||||
pass
|
||||
|
||||
# Make sure an inherited RadioSelect gets rendered as it
|
||||
form = CheckboxesSampleForm()
|
||||
form.fields["inline_radios"].widget = CustomRadioSelect()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout("inline_radios")
|
||||
|
||||
html = render_crispy_form(form)
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert 'class="custom-control-input"' in html
|
||||
else:
|
||||
assert 'class="radio"' in html
|
||||
|
||||
# Make sure an inherited CheckboxSelectMultiple gets rendered as it
|
||||
form.fields["checkboxes"].widget = CustomCheckboxSelectMultiple()
|
||||
form.helper.layout = Layout("checkboxes")
|
||||
html = render_crispy_form(form)
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert 'class="custom-control-input"' in html
|
||||
else:
|
||||
assert 'class="checkbox"' in html
|
||||
|
||||
def test_prepended_appended_text(self, settings):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
PrependedAppendedText("email", "@", "gmail.com"),
|
||||
AppendedText("password1", "#"),
|
||||
PrependedText("password2", "$"),
|
||||
)
|
||||
html = render_crispy_form(test_form)
|
||||
dom = parse_html(html)
|
||||
|
||||
# Check form parameters
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert dom.count(parse_html('<span class="add-on">@</span>')) == 1
|
||||
assert dom.count(parse_html('<span class="add-on">gmail.com</span>')) == 1
|
||||
assert dom.count(parse_html('<span class="add-on">#</span>')) == 1
|
||||
assert dom.count(parse_html('<span class="add-on">$</span>')) == 1
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert html.count('<span class="input-group-addon">@</span>') == 1
|
||||
assert html.count('<span class="input-group-addon">gmail.com</span>') == 1
|
||||
assert html.count('<span class="input-group-addon">#</span>') == 1
|
||||
assert html.count('<span class="input-group-addon">$</span>') == 1
|
||||
test_form.helper.layout = Layout(PrependedAppendedText("email", "@", "gmail.com", css_class="input-lg"),)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert 'class="input-lg' in html
|
||||
assert contains_partial(html, '<span class="input-group-addon input-lg"/>')
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count('<span class="input-group-text">@</span>') == 1
|
||||
assert html.count('<span class="input-group-text">gmail.com</span>') == 1
|
||||
assert html.count('<span class="input-group-text">#</span>') == 1
|
||||
assert html.count('<span class="input-group-text">$</span>') == 1
|
||||
test_form.helper.layout = Layout(
|
||||
PrependedAppendedText("email", "@", "gmail.com", css_class="form-control-lg"),
|
||||
)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert 'class="form-control-lg' in html
|
||||
assert contains_partial(html, '<span class="input-group-text"/>')
|
||||
|
||||
def test_inline_radios(self, settings):
|
||||
test_form = CheckboxesSampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(InlineRadios("inline_radios"))
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count('radio inline"') == 2
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert html.count('radio-inline"') == 2
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count('custom-control-inline"') == 2
|
||||
|
||||
def test_accordion_and_accordiongroup(self, settings):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
Accordion(AccordionGroup("one", "first_name"), AccordionGroup("two", "password1", "password2"))
|
||||
)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count('<div class="accordion"') == 1
|
||||
assert html.count('<div class="accordion-group">') == 2
|
||||
assert html.count('<div class="accordion-heading">') == 2
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert html.count('<div class="panel panel-default"') == 2
|
||||
assert html.count('<div class="panel-group"') == 1
|
||||
assert html.count('<div class="panel-heading">') == 2
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count('<div id="accordion"') == 1
|
||||
assert html.count('<div class="card mb-2"') == 2
|
||||
assert html.count('<div class="card-header"') == 2
|
||||
|
||||
assert html.count('<div id="one"') == 1
|
||||
assert html.count('<div id="two"') == 1
|
||||
assert html.count('name="first_name"') == 1
|
||||
assert html.count('name="password1"') == 1
|
||||
assert html.count('name="password2"') == 1
|
||||
|
||||
def test_accordion_active_false_not_rendered(self, settings):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
Accordion(
|
||||
AccordionGroup("one", "first_name",),
|
||||
# there is no ``active`` kwarg here.
|
||||
)
|
||||
)
|
||||
|
||||
# The first time, there should be one of them there.
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
accordion_class = "accordion-body collapse in"
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
accordion_class = "panel-collapse collapse in"
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
accordion_class = "collapse show"
|
||||
|
||||
assert html.count('<div id="one" class="%s"' % accordion_class) == 1
|
||||
|
||||
test_form.helper.layout = Layout(
|
||||
Accordion(AccordionGroup("one", "first_name", active=False,),) # now ``active`` manually set as False
|
||||
)
|
||||
|
||||
# This time, it shouldn't be there at all.
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count('<div id="one" class="%s collapse in"' % accordion_class) == 0
|
||||
|
||||
def test_alert(self):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(Alert(content="Testing..."))
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert html.count('<div class="alert"') == 1
|
||||
assert html.count('<button type="button" class="close"') == 1
|
||||
assert html.count("Testing...") == 1
|
||||
|
||||
def test_alert_block(self):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(Alert(content="Testing...", block=True))
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert html.count('<div class="alert alert-block"') == 1
|
||||
assert html.count("Testing...") == 1
|
||||
|
||||
def test_tab_and_tab_holder(self, settings):
|
||||
test_form = SampleForm()
|
||||
test_form.helper = FormHelper()
|
||||
test_form.helper.layout = Layout(
|
||||
TabHolder(
|
||||
Tab("one", "first_name", css_id="custom-name", css_class="first-tab-class active"),
|
||||
Tab("two", "password1", "password2"),
|
||||
)
|
||||
)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert (
|
||||
html.count(
|
||||
'<ul class="nav nav-tabs"> <li class="nav-item">'
|
||||
'<a class="nav-link active" href="#custom-name" data-toggle="tab">One</a></li>'
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert html.count("tab-pane") == 2
|
||||
else:
|
||||
assert (
|
||||
html.count(
|
||||
'<ul class="nav nav-tabs"> <li class="tab-pane active">'
|
||||
'<a href="#custom-name" data-toggle="tab">One</a></li>'
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert html.count('<li class="tab-pane') == 2
|
||||
assert html.count("tab-pane") == 4
|
||||
|
||||
assert html.count('class="tab-pane first-tab-class active"') == 1
|
||||
|
||||
assert html.count('<div id="custom-name"') == 1
|
||||
assert html.count('<div id="two"') == 1
|
||||
assert html.count('name="first_name"') == 1
|
||||
assert html.count('name="password1"') == 1
|
||||
assert html.count('name="password2"') == 1
|
||||
|
||||
def test_tab_helper_reuse(self):
|
||||
# this is a proper form, according to the docs.
|
||||
# note that the helper is a class property here,
|
||||
# shared between all instances
|
||||
class SampleForm(forms.Form):
|
||||
val1 = forms.CharField(required=False)
|
||||
val2 = forms.CharField(required=True)
|
||||
helper = FormHelper()
|
||||
helper.layout = Layout(TabHolder(Tab("one", "val1",), Tab("two", "val2",)))
|
||||
|
||||
# first render of form => everything is fine
|
||||
test_form = SampleForm()
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
# second render of form => first tab should be active,
|
||||
# but not duplicate class
|
||||
test_form = SampleForm()
|
||||
html = render_crispy_form(test_form)
|
||||
assert html.count('class="nav-item active active"') == 0
|
||||
|
||||
# render a new form, now with errors
|
||||
test_form = SampleForm(data={"val1": "foo"})
|
||||
html = render_crispy_form(test_form)
|
||||
tab_class = "tab-pane"
|
||||
# if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
|
||||
# tab_class = 'nav-link'
|
||||
# else:
|
||||
# tab_class = 'tab-pane'
|
||||
# tab 1 should not be active
|
||||
assert html.count('<div id="one" \n class="{} active'.format(tab_class)) == 0
|
||||
# tab 2 should be active
|
||||
assert html.count('<div id="two" \n class="{} active'.format(tab_class)) == 1
|
||||
|
||||
def test_radio_attrs(self):
|
||||
form = CheckboxesSampleForm()
|
||||
form.fields["inline_radios"].widget.attrs = {"class": "first"}
|
||||
form.fields["checkboxes"].widget.attrs = {"class": "second"}
|
||||
html = render_crispy_form(form)
|
||||
assert 'class="first"' in html
|
||||
assert 'class="second"' in html
|
||||
|
||||
def test_field_with_buttons(self, settings):
|
||||
form = SampleForm()
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
FieldWithButtons(
|
||||
Field("password1", css_class="span4"),
|
||||
StrictButton("Go!", css_id="go-button"),
|
||||
StrictButton("No!", css_class="extra"),
|
||||
StrictButton("Test", type="submit", name="whatever", value="something"),
|
||||
css_class="extra",
|
||||
autocomplete="off",
|
||||
)
|
||||
)
|
||||
html = render_crispy_form(form)
|
||||
|
||||
form_group_class = "control-group"
|
||||
if settings.CRISPY_TEMPLATE_PACK in ("bootstrap3", "bootstrap4"):
|
||||
form_group_class = "form-group"
|
||||
|
||||
assert html.count('class="%s extra"' % form_group_class) == 1
|
||||
assert html.count('autocomplete="off"') == 1
|
||||
assert html.count('class="span4') == 1
|
||||
assert html.count('id="go-button"') == 1
|
||||
assert html.count("Go!") == 1
|
||||
assert html.count("No!") == 1
|
||||
assert html.count('class="btn"') == 2
|
||||
assert html.count('class="btn extra"') == 1
|
||||
assert html.count('type="submit"') == 1
|
||||
assert html.count('name="whatever"') == 1
|
||||
assert html.count('value="something"') == 1
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count('class="input-append"') == 1
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert html.count('class="input-group-btn') == 1
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count('class="input-group-append') == 1
|
||||
|
||||
def test_hidden_fields(self):
|
||||
form = SampleForm()
|
||||
# All fields hidden
|
||||
for field in form.fields:
|
||||
form.fields[field].widget = forms.HiddenInput()
|
||||
|
||||
form.helper = FormHelper()
|
||||
form.helper.layout = Layout(
|
||||
AppendedText("password1", "foo"),
|
||||
PrependedText("password2", "bar"),
|
||||
PrependedAppendedText("email", "bar"),
|
||||
InlineCheckboxes("first_name"),
|
||||
InlineRadios("last_name"),
|
||||
)
|
||||
html = render_crispy_form(form)
|
||||
assert html.count("<input") == 5
|
||||
assert html.count('type="hidden"') == 5
|
||||
assert html.count("<label") == 0
|
||||
|
||||
def test_multiplecheckboxes(self, settings):
|
||||
test_form = CheckboxesSampleForm()
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
assert html.count('checked="checked"') == 6
|
||||
|
||||
test_form.helper = FormHelper(test_form)
|
||||
test_form.helper[1].wrap(InlineCheckboxes, inline=True)
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
assert html.count('checkbox inline"') == 3
|
||||
assert html.count('inline"') == 3
|
||||
elif settings.CRISPY_TEMPLATE_PACK in ["bootstrap3", "bootstrap4"]:
|
||||
assert html.count('inline="True"') == 4
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert html.count('checkbox-inline"') == 3
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert html.count('custom-control-inline"') == 3
|
||||
|
||||
def test_multiple_checkboxes_unique_ids(self):
|
||||
test_form = CheckboxesSampleForm()
|
||||
html = render_crispy_form(test_form)
|
||||
|
||||
expected_ids = [
|
||||
"checkboxes_1",
|
||||
"checkboxes_2",
|
||||
"checkboxes_3",
|
||||
"alphacheckboxes_1",
|
||||
"alphacheckboxes_2",
|
||||
"alphacheckboxes_3",
|
||||
"numeric_multiple_checkboxes_1",
|
||||
"numeric_multiple_checkboxes_2",
|
||||
"numeric_multiple_checkboxes_3",
|
||||
]
|
||||
for id_suffix in expected_ids:
|
||||
expected_str = 'id="id_{id_suffix}"'.format(id_suffix=id_suffix)
|
||||
assert html.count(expected_str) == 1
|
||||
49
Lib/site-packages/crispy_forms/tests/test_settings.py
Normal file
49
Lib/site-packages/crispy_forms/tests/test_settings.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import os
|
||||
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
"django.contrib.auth",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.admin",
|
||||
"crispy_forms",
|
||||
)
|
||||
|
||||
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
)
|
||||
|
||||
ROOT_URLCONF = "crispy_forms.tests.urls"
|
||||
CRISPY_CLASS_CONVERTERS = {"textinput": "textinput textInput inputtext"}
|
||||
SECRET_KEY = "secretkey"
|
||||
SITE_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
TEMPLATE_DEBUG = True
|
||||
TEMPLATE_DIRS = (os.path.join(BASE_DIR, "templates"),)
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": TEMPLATE_DIRS,
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
# Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this
|
||||
# list if you haven't customized them:
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.i18n",
|
||||
"django.template.context_processors.media",
|
||||
"django.template.context_processors.static",
|
||||
"django.template.context_processors.tz",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
"debug": TEMPLATE_DEBUG,
|
||||
},
|
||||
},
|
||||
]
|
||||
235
Lib/site-packages/crispy_forms/tests/test_tags.py
Normal file
235
Lib/site-packages/crispy_forms/tests/test_tags.py
Normal file
@@ -0,0 +1,235 @@
|
||||
import pytest
|
||||
|
||||
from django.forms.boundfield import BoundField
|
||||
from django.forms.formsets import formset_factory
|
||||
from django.template import Context, Template
|
||||
|
||||
from crispy_forms.exceptions import CrispyError
|
||||
from crispy_forms.templatetags.crispy_forms_field import crispy_addon
|
||||
|
||||
from .conftest import only_bootstrap
|
||||
from .forms import SampleForm
|
||||
|
||||
|
||||
def test_crispy_field():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_field %}
|
||||
{% for field in form %}
|
||||
{% crispy_field field %}
|
||||
{% endfor %}
|
||||
"""
|
||||
)
|
||||
html = template.render(Context({"form": SampleForm()}))
|
||||
assert html.count("<input") == 8
|
||||
|
||||
|
||||
def test_as_crispy_errors_form_without_non_field_errors():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ form|as_crispy_errors }}
|
||||
"""
|
||||
)
|
||||
form = SampleForm({"password1": "god", "password2": "god"})
|
||||
form.is_valid()
|
||||
|
||||
c = Context({"form": form})
|
||||
html = template.render(c)
|
||||
assert not ("errorMsg" in html or "alert" in html)
|
||||
|
||||
|
||||
def test_as_crispy_errors_form_with_non_field_errors():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ form|as_crispy_errors }}
|
||||
"""
|
||||
)
|
||||
form = SampleForm({"password1": "god", "password2": "wargame"})
|
||||
form.is_valid()
|
||||
|
||||
c = Context({"form": form})
|
||||
html = template.render(c)
|
||||
assert "errorMsg" in html or "alert" in html
|
||||
assert "<li>Passwords dont match</li>" in html
|
||||
assert "<h3>" not in html
|
||||
|
||||
|
||||
def test_as_crispy_errors_formset_without_non_form_errors():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ formset|as_crispy_errors }}
|
||||
"""
|
||||
)
|
||||
|
||||
SampleFormset = formset_factory(SampleForm, max_num=1, validate_max=True)
|
||||
formset = SampleFormset()
|
||||
formset.is_valid()
|
||||
|
||||
c = Context({"formset": formset})
|
||||
html = template.render(c)
|
||||
assert not ("errorMsg" in html or "alert" in html)
|
||||
|
||||
|
||||
def test_as_crispy_errors_formset_with_non_form_errors():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ formset|as_crispy_errors }}
|
||||
"""
|
||||
)
|
||||
|
||||
SampleFormset = formset_factory(SampleForm, max_num=1, validate_max=True)
|
||||
formset = SampleFormset(
|
||||
{
|
||||
"form-TOTAL_FORMS": "2",
|
||||
"form-INITIAL_FORMS": "0",
|
||||
"form-MAX_NUM_FORMS": "",
|
||||
"form-0-password1": "god",
|
||||
"form-0-password2": "wargame",
|
||||
}
|
||||
)
|
||||
formset.is_valid()
|
||||
|
||||
c = Context({"formset": formset})
|
||||
html = template.render(c)
|
||||
assert "errorMsg" in html or "alert" in html
|
||||
assert "<li>Please submit 1 or fewer forms.</li>" in html
|
||||
assert "<h3>" not in html
|
||||
|
||||
|
||||
def test_as_crispy_field_non_field(settings):
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ field|as_crispy_field }}
|
||||
"""
|
||||
)
|
||||
|
||||
c = Context({"field": "notafield"})
|
||||
|
||||
# Raises an AttributeError when trying to figure out how to render it
|
||||
# Not sure if this is expected behavior -- @kavdev
|
||||
error_class = CrispyError if settings.DEBUG else AttributeError
|
||||
|
||||
with pytest.raises(error_class):
|
||||
template.render(c)
|
||||
|
||||
|
||||
def test_as_crispy_field_bound_field():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ field|as_crispy_field }}
|
||||
"""
|
||||
)
|
||||
|
||||
form = SampleForm({"password1": "god", "password2": "god"})
|
||||
form.is_valid()
|
||||
|
||||
c = Context({"field": form["password1"]})
|
||||
|
||||
# Would raise exception if not a field
|
||||
html = template.render(c)
|
||||
assert "id_password1" in html
|
||||
assert "id_password2" not in html
|
||||
|
||||
|
||||
def test_crispy_filter_with_form():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ form|crispy }}
|
||||
"""
|
||||
)
|
||||
c = Context({"form": SampleForm()})
|
||||
html = template.render(c)
|
||||
|
||||
assert "<td>" not in html
|
||||
assert "id_is_company" in html
|
||||
assert html.count("<label") == 7
|
||||
|
||||
|
||||
def test_crispy_filter_with_formset():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_tags %}
|
||||
{{ testFormset|crispy }}
|
||||
"""
|
||||
)
|
||||
|
||||
SampleFormset = formset_factory(SampleForm, extra=4)
|
||||
testFormset = SampleFormset()
|
||||
|
||||
c = Context({"testFormset": testFormset})
|
||||
html = template.render(c)
|
||||
|
||||
assert html.count("<form") == 0
|
||||
# Check formset management form
|
||||
assert "form-TOTAL_FORMS" in html
|
||||
assert "form-INITIAL_FORMS" in html
|
||||
assert "form-MAX_NUM_FORMS" in html
|
||||
|
||||
|
||||
def test_classes_filter():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_field %}
|
||||
{{ testField|classes }}
|
||||
"""
|
||||
)
|
||||
|
||||
test_form = SampleForm()
|
||||
test_form.fields["email"].widget.attrs.update({"class": "email-fields"})
|
||||
c = Context({"testField": test_form.fields["email"]})
|
||||
html = template.render(c)
|
||||
assert "email-fields" in html
|
||||
|
||||
|
||||
def test_crispy_field_and_class_converters():
|
||||
template = Template(
|
||||
"""
|
||||
{% load crispy_forms_field %}
|
||||
{% crispy_field testField 'class' 'error' %}
|
||||
"""
|
||||
)
|
||||
test_form = SampleForm()
|
||||
field_instance = test_form.fields["email"]
|
||||
bound_field = BoundField(test_form, field_instance, "email")
|
||||
|
||||
c = Context({"testField": bound_field})
|
||||
html = template.render(c)
|
||||
assert "error" in html
|
||||
assert "inputtext" in html
|
||||
|
||||
|
||||
@only_bootstrap
|
||||
def test_crispy_addon(settings):
|
||||
test_form = SampleForm()
|
||||
field_instance = test_form.fields["email"]
|
||||
bound_field = BoundField(test_form, field_instance, "email")
|
||||
|
||||
if settings.CRISPY_TEMPLATE_PACK == "bootstrap":
|
||||
# prepend tests
|
||||
assert "input-prepend" in crispy_addon(bound_field, prepend="Work")
|
||||
assert "input-append" not in crispy_addon(bound_field, prepend="Work")
|
||||
# append tests
|
||||
assert "input-prepend" not in crispy_addon(bound_field, append="Primary")
|
||||
assert "input-append" in crispy_addon(bound_field, append="Secondary")
|
||||
# prepend and append tests
|
||||
assert "input-append" in crispy_addon(bound_field, prepend="Work", append="Primary")
|
||||
assert "input-prepend" in crispy_addon(bound_field, prepend="Work", append="Secondary")
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap3":
|
||||
assert "input-group-addon" in crispy_addon(bound_field, prepend="Work", append="Primary")
|
||||
assert "input-group-addon" in crispy_addon(bound_field, prepend="Work", append="Secondary")
|
||||
elif settings.CRISPY_TEMPLATE_PACK == "bootstrap4":
|
||||
assert "input-group-text" in crispy_addon(bound_field, prepend="Work", append="Primary")
|
||||
assert "input-group-text" in crispy_addon(bound_field, prepend="Work", append="Secondary")
|
||||
|
||||
# errors
|
||||
with pytest.raises(TypeError):
|
||||
crispy_addon()
|
||||
with pytest.raises(TypeError):
|
||||
crispy_addon(bound_field)
|
||||
81
Lib/site-packages/crispy_forms/tests/test_utils.py
Normal file
81
Lib/site-packages/crispy_forms/tests/test_utils.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from django import forms
|
||||
from django.template.base import Template
|
||||
from django.template.context import Context
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout
|
||||
from crispy_forms.tests.utils import contains_partial
|
||||
from crispy_forms.utils import list_difference, list_intersection, render_field
|
||||
|
||||
|
||||
def test_list_intersection():
|
||||
assert list_intersection([1, 3], [2, 3]) == [3]
|
||||
|
||||
|
||||
def test_list_difference():
|
||||
assert list_difference([3, 1, 2, 3], [4, 1]) == [3, 2]
|
||||
|
||||
|
||||
def test_render_field_with_none_field():
|
||||
rendered = render_field(field=None, form=None, form_style=None, context=None)
|
||||
assert rendered == ""
|
||||
|
||||
|
||||
def test_custom_bound_field():
|
||||
from django.forms.boundfield import BoundField
|
||||
|
||||
extra = "xyxyxyxyxyx"
|
||||
|
||||
class CustomBoundField(BoundField):
|
||||
@property
|
||||
def auto_id(self):
|
||||
return extra
|
||||
|
||||
class MyCharField(forms.CharField):
|
||||
def get_bound_field(self, form, field_name):
|
||||
return CustomBoundField(form, self, field_name)
|
||||
|
||||
class MyForm(forms.Form):
|
||||
f = MyCharField()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.layout = Layout("f")
|
||||
|
||||
template = Template('{% load crispy_forms_tags %}\n{% crispy form "bootstrap3" %}')
|
||||
rendered = template.render(Context({"form": MyForm(data={"f": "something"})}))
|
||||
|
||||
assert extra in rendered
|
||||
|
||||
|
||||
def test_contains_partial():
|
||||
c = SimpleTestCase()
|
||||
needle = "<span></span>"
|
||||
html = "<form>%s</form>"
|
||||
c.assertTrue(contains_partial(html % needle, needle))
|
||||
|
||||
needle = "<span></span><b></b>"
|
||||
c.assertRaises(NotImplementedError, contains_partial, html % needle, needle)
|
||||
|
||||
needle = "<span>a</span>"
|
||||
c.assertRaises(NotImplementedError, contains_partial, html % needle, needle)
|
||||
|
||||
needle = '<span id="e"></span>'
|
||||
html = '<form id="tt"><span id="f"></span>%s</form>'
|
||||
c.assertTrue(contains_partial(html % needle, needle))
|
||||
|
||||
missing = "<script></script>"
|
||||
c.assertFalse(contains_partial(html % missing, needle))
|
||||
|
||||
needle = '<span id="e"></span>'
|
||||
html = '<form id="tt"><span id="f"></span>%s</form>'
|
||||
missing = '<span id="g"></span>'
|
||||
c.assertFalse(contains_partial(html % missing, needle))
|
||||
|
||||
needle = '<div id="r"><span>toto</span></div>'
|
||||
html = '<form><div id="r"></div></form>'
|
||||
c.assertRaises(NotImplementedError, contains_partial, html, needle)
|
||||
# as we do not look at the children, needle is equivalent to <div id="r"></div> which IS in html
|
||||
c.assertTrue(contains_partial(html, needle, ignore_needle_children=True))
|
||||
6
Lib/site-packages/crispy_forms/tests/urls.py
Normal file
6
Lib/site-packages/crispy_forms/tests/urls.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.urls import path
|
||||
from django.views.generic import View
|
||||
|
||||
urlpatterns = [
|
||||
path("simple/action/", View.as_view(), name="simpleAction"),
|
||||
]
|
||||
22
Lib/site-packages/crispy_forms/tests/utils.py
Normal file
22
Lib/site-packages/crispy_forms/tests/utils.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.test.html import Element, parse_html
|
||||
|
||||
|
||||
def contains_partial(haystack, needle, ignore_needle_children=False):
|
||||
"""Search for a html element with at least the corresponding elements
|
||||
(other elements may be present in the matched element from the haystack)
|
||||
"""
|
||||
if not isinstance(haystack, Element):
|
||||
haystack = parse_html(haystack)
|
||||
if not isinstance(needle, Element):
|
||||
needle = parse_html(needle)
|
||||
|
||||
if len(needle.children) > 0 and not ignore_needle_children:
|
||||
raise NotImplementedError("contains_partial does not check needle's children:%s" % str(needle.children))
|
||||
|
||||
if needle.name == haystack.name and set(needle.attributes).issubset(haystack.attributes):
|
||||
return True
|
||||
return any(
|
||||
contains_partial(child, needle, ignore_needle_children=ignore_needle_children)
|
||||
for child in haystack.children
|
||||
if isinstance(child, Element)
|
||||
)
|
||||
Reference in New Issue
Block a user