summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Mispelon <bmispelon@gmail.com>2021-12-08 14:46:22 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-12-08 21:13:00 +0100
commit15031852c5ef6b3713bb9766d918460ea46e254e (patch)
treeed57a5793d8235f377be0794e28c23df6f1d2ae3
parentb7f2afa8de3cef4a4d5d5e413e502b09ea01163d (diff)
[4.0.x] Fixed #33346 -- Fixed SimpleTestCase.assertFormsetError() crash on a formset named "form".
Thanks OutOfFocus4 for the report. Regression in 456466d932830b096d39806e291fe23ec5ed38d5. Backport of cb383753c0e0eb52306e1024d32a782549c27e61 from main.
-rw-r--r--django/test/testcases.py2
-rw-r--r--docs/releases/4.0.1.txt4
-rw-r--r--tests/test_utils/tests.py43
3 files changed, 46 insertions, 3 deletions
diff --git a/django/test/testcases.py b/django/test/testcases.py
index b56e8f5edf..28cf45e8ba 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -557,7 +557,7 @@ class SimpleTestCase(unittest.TestCase):
# Search all contexts for the error.
found_formset = False
for i, context in enumerate(contexts):
- if formset not in context:
+ if formset not in context or not hasattr(context[formset], 'forms'):
continue
found_formset = True
for err in errors:
diff --git a/docs/releases/4.0.1.txt b/docs/releases/4.0.1.txt
index d5a674778e..fa4ebe826f 100644
--- a/docs/releases/4.0.1.txt
+++ b/docs/releases/4.0.1.txt
@@ -9,4 +9,6 @@ Django 4.0.1 fixes several bugs in 4.0.
Bugfixes
========
-* ...
+* Fixed a regression in Django 4.0 that caused a crash of
+ :meth:`~django.test.SimpleTestCase.assertFormsetError` on a formset named
+ ``form`` (:ticket:`33346`).
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 82ec36ab38..f7a964bfa0 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -13,7 +13,10 @@ from django.core.files.storage import default_storage
from django.db import (
IntegrityError, connection, connections, models, router, transaction,
)
-from django.forms import EmailField, IntegerField
+from django.forms import (
+ CharField, EmailField, Form, IntegerField, ValidationError,
+ formset_factory,
+)
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.test import (
@@ -1241,6 +1244,44 @@ class AssertURLEqualTests(SimpleTestCase):
)
+class TestForm(Form):
+ field = CharField()
+
+ def clean_field(self):
+ value = self.cleaned_data.get('field', '')
+ if value == 'invalid':
+ raise ValidationError('invalid value')
+ return value
+
+
+class TestFormset(formset_factory(TestForm)):
+ @classmethod
+ def _get_cleaned_formset(cls, field_value):
+ formset = cls({
+ 'form-TOTAL_FORMS': '1',
+ 'form-INITIAL_FORMS': '0',
+ 'form-0-field': field_value,
+ })
+ formset.full_clean()
+ return formset
+
+ @classmethod
+ def invalid(cls):
+ return cls._get_cleaned_formset('invalid')
+
+
+class AssertFormsetErrorTests(SimpleTestCase):
+ def test_formset_named_form(self):
+ formset = TestFormset.invalid()
+ # The mocked context emulates the template-based rendering of the
+ # formset.
+ response = mock.Mock(context=[
+ {'form': formset},
+ {'form': formset.management_form},
+ ])
+ self.assertFormsetError(response, 'form', 0, 'field', 'invalid value')
+
+
class FirstUrls:
urlpatterns = [path('first/', empty_response, name='first')]