summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Mispelon <bmispelon@gmail.com>2021-12-10 12:22:23 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-04-06 07:58:52 +0200
commit50e1e7ef8ef63271717f8bcab76d7151ccf4bb18 (patch)
tree888beb2bff18679025536e574a0bc02a53f9d552
parent1a7d75cf77639e450854d9bcf9518664f755eb04 (diff)
Fixed #33348 -- Changed SimpleTestCase.assertFormError()/assertFormsetErrors() to take form/formset.
Instead of taking a response object and a context name for the form/formset, the two methods now take the object directly.
-rw-r--r--django/contrib/admin/helpers.py3
-rw-r--r--django/test/testcases.py259
-rw-r--r--docs/internals/deprecation.txt4
-rw-r--r--docs/releases/4.1.txt16
-rw-r--r--docs/topics/testing/tools.txt72
-rw-r--r--tests/admin_views/tests.py29
-rw-r--r--tests/test_client/tests.py24
-rw-r--r--tests/test_utils/tests.py442
8 files changed, 561 insertions, 288 deletions
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index cc5317199d..9068ce57da 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -441,9 +441,8 @@ class InlineAdminFormSet:
def forms(self):
return self.formset.forms
- @property
def non_form_errors(self):
- return self.formset.non_form_errors
+ return self.formset.non_form_errors()
@property
def is_bound(self):
diff --git a/django/test/testcases.py b/django/test/testcases.py
index bfcfef58cb..53d3838bb8 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -1,5 +1,6 @@
import asyncio
import difflib
+import inspect
import json
import logging
import posixpath
@@ -42,6 +43,7 @@ from django.db import DEFAULT_DB_ALIAS, connection, connections, transaction
from django.forms.fields import CharField
from django.http import QueryDict
from django.http.request import split_domain_port, validate_host
+from django.http.response import HttpResponseBase
from django.test.client import AsyncClient, Client
from django.test.html import HTMLParseError, parse_html
from django.test.signals import template_rendered
@@ -165,6 +167,127 @@ class _DatabaseFailure:
raise DatabaseOperationForbidden(self.message)
+# RemovedInDjango50Warning
+class _AssertFormErrorDeprecationHelper:
+ @staticmethod
+ def assertFormError(self, response, form, field, errors, msg_prefix=""):
+ """
+ Search through all the rendered contexts of the `response` for a form named
+ `form` then dispatch to the new assertFormError() using that instance.
+ If multiple contexts contain the form, they're all checked in order and any
+ failure will abort (this matches the old behavior).
+ """
+ warning_msg = (
+ f"Passing response to assertFormError() is deprecated. Use the form object "
+ f"directly: assertFormError(response.context[{form!r}], {field!r}, ...)"
+ )
+ warnings.warn(warning_msg, RemovedInDjango50Warning, stacklevel=2)
+
+ full_msg_prefix = f"{msg_prefix}: " if msg_prefix else ""
+ contexts = to_list(response.context) if response.context is not None else []
+ if not contexts:
+ self.fail(
+ f"{full_msg_prefix}Response did not use any contexts to render the "
+ f"response"
+ )
+ # Search all contexts for the error.
+ found_form = False
+ for i, context in enumerate(contexts):
+ if form not in context:
+ continue
+ found_form = True
+ self.assertFormError(context[form], field, errors, msg_prefix=msg_prefix)
+ if not found_form:
+ self.fail(
+ f"{full_msg_prefix}The form '{form}' was not used to render the "
+ f"response"
+ )
+
+ @staticmethod
+ def assertFormsetError(
+ self, response, formset, form_index, field, errors, msg_prefix=""
+ ):
+ """
+ Search for a formset named "formset" in the "response" and dispatch to
+ the new assertFormsetError() using that instance. If the name is found
+ in multiple contexts they're all checked in order and any failure will
+ abort the test.
+ """
+ warning_msg = (
+ f"Passing response to assertFormsetError() is deprecated. Use the formset "
+ f"object directly: assertFormsetError(response.context[{formset!r}], "
+ f"{form_index!r}, ...)"
+ )
+ warnings.warn(warning_msg, RemovedInDjango50Warning, stacklevel=2)
+
+ full_msg_prefix = f"{msg_prefix}: " if msg_prefix else ""
+ contexts = to_list(response.context) if response.context is not None else []
+ if not contexts:
+ self.fail(
+ f"{full_msg_prefix}Response did not use any contexts to render the "
+ f"response"
+ )
+ found_formset = False
+ for i, context in enumerate(contexts):
+ if formset not in context or not hasattr(context[formset], "forms"):
+ continue
+ found_formset = True
+ self.assertFormsetError(
+ context[formset], form_index, field, errors, msg_prefix
+ )
+ if not found_formset:
+ self.fail(
+ f"{full_msg_prefix}The formset '{formset}' was not used to render the "
+ f"response"
+ )
+
+ @classmethod
+ def patch_signature(cls, new_method):
+ """
+ Replace the decorated method with a new one that inspects the passed
+ args/kwargs and dispatch to the old implementation (with deprecation
+ warning) when it detects the old signature.
+ """
+
+ @wraps(new_method)
+ def patched_method(self, *args, **kwargs):
+ old_method = getattr(cls, new_method.__name__)
+ old_signature = inspect.signature(old_method)
+ try:
+ old_bound_args = old_signature.bind(self, *args, **kwargs)
+ except TypeError:
+ # If old signature doesn't match then either:
+ # 1) new signature will match
+ # 2) or a TypeError will be raised showing the user information
+ # about the new signature.
+ return new_method(self, *args, **kwargs)
+
+ new_signature = inspect.signature(new_method)
+ try:
+ new_bound_args = new_signature.bind(self, *args, **kwargs)
+ except TypeError:
+ # Old signature matches but not the new one (because of
+ # previous try/except).
+ return old_method(self, *args, **kwargs)
+
+ # If both signatures match, decide on which method to call by
+ # inspecting the first arg (arg[0] = self).
+ assert old_bound_args.args[1] == new_bound_args.args[1]
+ if hasattr(
+ old_bound_args.args[1], "context"
+ ): # Looks like a response object => old method.
+ return old_method(self, *args, **kwargs)
+ elif isinstance(old_bound_args.args[1], HttpResponseBase):
+ raise ValueError(
+ f"{old_method.__name__}() is only usable on responses fetched "
+ f"using the Django test Client."
+ )
+ else:
+ return new_method(self, *args, **kwargs)
+
+ return patched_method
+
+
class SimpleTestCase(unittest.TestCase):
# The class we'll use for the test client self.client.
@@ -585,22 +708,19 @@ class SimpleTestCase(unittest.TestCase):
self.assertEqual(field_errors, errors, msg_prefix + failure_message)
- def assertFormError(self, response, form, field, errors, msg_prefix=""):
- """
- Assert that a form used to render the response has a specific field
- error.
+ # RemovedInDjango50Warning: When the deprecation ends, remove the
+ # decorator.
+ @_AssertFormErrorDeprecationHelper.patch_signature
+ def assertFormError(self, form, field, errors, msg_prefix=""):
"""
- self._check_test_client_response(response, "context", "assertFormError")
- if msg_prefix:
- msg_prefix += ": "
+ Assert that a field named "field" on the given form object has specific
+ errors.
- # Put context(s) into a list to simplify processing.
- contexts = [] if response.context is None else to_list(response.context)
- if not contexts:
- self.fail(
- msg_prefix + "Response did not use any contexts to render the response"
- )
+ errors can be either a single error message or a list of errors
+ messages. Using errors=[] test that the field has no errors.
+ You can pass field=None to check the form's non-field errors.
+ """
if errors is None:
warnings.warn(
"Passing errors=None to assertFormError() is deprecated, use "
@@ -609,47 +729,25 @@ class SimpleTestCase(unittest.TestCase):
stacklevel=2,
)
errors = []
- # Put error(s) into a list to simplify processing.
- errors = to_list(errors)
-
- # Search all contexts for the error.
- found_form = False
- for i, context in enumerate(contexts):
- if form in context:
- found_form = True
- self._assert_form_error(
- context[form], field, errors, msg_prefix, "form %r" % context[form]
- )
- if not found_form:
- self.fail(
- msg_prefix + "The form '%s' was not used to render the response" % form
- )
-
- def assertFormsetError(
- self, response, formset, form_index, field, errors, msg_prefix=""
- ):
- """
- Assert that a formset used to render the response has a specific error.
- For field errors, specify the ``form_index`` and the ``field``.
- For non-field errors, specify the ``form_index`` and the ``field`` as
- None.
- For non-form errors, specify ``form_index`` as None and the ``field``
- as None.
- """
- self._check_test_client_response(response, "context", "assertFormsetError")
- # Add punctuation to msg_prefix
if msg_prefix:
msg_prefix += ": "
+ errors = to_list(errors)
+ self._assert_form_error(form, field, errors, msg_prefix, f"form {form!r}")
- # Put context(s) into a list to simplify processing.
- contexts = [] if response.context is None else to_list(response.context)
- if not contexts:
- self.fail(
- msg_prefix + "Response did not use any contexts to "
- "render the response"
- )
+ # RemovedInDjango50Warning: When the deprecation ends, remove the
+ # decorator.
+ @_AssertFormErrorDeprecationHelper.patch_signature
+ def assertFormsetError(self, formset, form_index, field, errors, msg_prefix=""):
+ """
+ Similar to assertFormError() but for formsets.
+ Use form_index=None to check the formset's non-form errors (in that
+ case, you must also use field=None).
+ Otherwise use an integer to check the formset's n-th form for errors.
+
+ Other parameters are the same as assertFormError().
+ """
if errors is None:
warnings.warn(
"Passing errors=None to assertFormsetError() is deprecated, "
@@ -662,50 +760,31 @@ class SimpleTestCase(unittest.TestCase):
if form_index is None and field is not None:
raise ValueError("You must use field=None with form_index=None.")
- # Put error(s) into a list to simplify processing.
+ if msg_prefix:
+ msg_prefix += ": "
errors = to_list(errors)
- # Search all contexts for the error.
- found_formset = False
- for i, context in enumerate(contexts):
- if formset not in context or not hasattr(context[formset], "forms"):
- continue
- formset_repr = repr(context[formset])
- if not context[formset].is_bound:
- self.fail(
- f"{msg_prefix}The formset {formset_repr} is not bound, it will "
- f"never have any errors."
- )
- found_formset = True
- if form_index is not None:
- form_count = context[formset].total_form_count()
- if form_index >= form_count:
- form_or_forms = "forms" if form_count > 1 else "form"
- self.fail(
- f"{msg_prefix}The formset {formset_repr} only has "
- f"{form_count} {form_or_forms}."
- )
- if form_index is not None:
- form_repr = f"form {form_index} of formset {formset_repr}"
- self._assert_form_error(
- context[formset].forms[form_index],
- field,
- errors,
- msg_prefix,
- form_repr,
- )
- else:
- failure_message = (
- f"{msg_prefix}The non-form errors of formset {formset_repr} don't "
- f"match."
- )
- self.assertEqual(
- context[formset].non_form_errors(), errors, failure_message
- )
- if not found_formset:
+ if not formset.is_bound:
self.fail(
- msg_prefix
- + "The formset '%s' was not used to render the response" % formset
+ f"{msg_prefix}The formset {formset!r} is not bound, it will never have "
+ f"any errors."
+ )
+ if form_index is not None and form_index >= formset.total_form_count():
+ form_count = formset.total_form_count()
+ form_or_forms = "forms" if form_count > 1 else "form"
+ self.fail(
+ f"{msg_prefix}The formset {formset!r} only has {form_count} "
+ f"{form_or_forms}."
+ )
+ if form_index is not None:
+ form_repr = f"form {form_index} of formset {formset!r}"
+ self._assert_form_error(
+ formset.forms[form_index], field, errors, msg_prefix, form_repr
+ )
+ else:
+ failure_message = f"The non-form errors of formset {formset!r} don't match."
+ self.assertEqual(
+ formset.non_form_errors(), errors, msg_prefix + failure_message
)
def _get_template_used(self, response, template_name, msg_prefix, method_name):
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index ab147725c1..eb6d7f7b2f 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -97,6 +97,10 @@ details on these changes.
* The ``django.utils.timezone.utc`` alias to ``datetime.timezone.utc`` will be
removed.
+* Passing a response object and a form/formset name to
+ ``SimpleTestCase.assertFormError()`` and ``assertFormsetError()`` will no
+ longer be allowed.
+
.. _deprecation-removed-in-4.1:
4.1
diff --git a/docs/releases/4.1.txt b/docs/releases/4.1.txt
index 7660780ae5..4413fdfc9a 100644
--- a/docs/releases/4.1.txt
+++ b/docs/releases/4.1.txt
@@ -327,6 +327,10 @@ Tests
* A nested atomic block marked as durable in :class:`django.test.TestCase` now
raises a ``RuntimeError``, the same as outside of tests.
+* :meth:`.SimpleTestCase.assertFormError` and
+ :meth:`~.SimpleTestCase.assertFormsetError` now support passing a
+ form/formset object directly.
+
URLs
~~~~
@@ -449,6 +453,9 @@ Miscellaneous
* The admin log out UI now uses ``POST`` requests.
+* The undocumented ``InlineAdminFormSet.non_form_errors`` property is replaced
+ by the ``non_form_errors()`` method. This is consistent with ``BaseFormSet``.
+
.. _deprecated-features-4.1:
Features deprecated in 4.1
@@ -552,6 +559,15 @@ Miscellaneous
* The :data:`django.utils.timezone.utc` alias to :attr:`datetime.timezone.utc`
is deprecated. Use :attr:`datetime.timezone.utc` directly.
+* Passing a response object and a form/formset name to
+ ``SimpleTestCase.assertFormError()`` and ``assertFormsetError()`` is
+ deprecated. Use::
+
+ assertFormError(response.context['form_name'], …)
+ assertFormsetError(response.context['formset_name'], …)
+
+ or pass the form/formset object directly instead.
+
Features removed in 4.1
=======================
diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt
index c6923c6c87..836dab54e4 100644
--- a/docs/topics/testing/tools.txt
+++ b/docs/topics/testing/tools.txt
@@ -1473,47 +1473,65 @@ your test suite.
self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': ['Enter a valid email address.']})
-.. method:: SimpleTestCase.assertFormError(response, form, field, errors, msg_prefix='')
+.. method:: SimpleTestCase.assertFormError(form, field, errors, msg_prefix='')
- Asserts that a field on a form raises the provided list of errors when
- rendered on the form.
+ Asserts that a field on a form raises the provided list of errors.
- ``response`` must be a response instance returned by the
- :class:`test client <django.test.Response>`.
+ ``form`` is a ``Form`` instance. The form must be
+ :ref:`bound <ref-forms-api-bound-unbound>` but not necessarily
+ validated (``assertFormError()`` will automatically call ``full_clean()``
+ on the form).
+
+ ``field`` is the name of the field on the form to check. To check the form's
+ :meth:`non-field errors <django.forms.Form.non_field_errors>`, use
+ ``field=None``.
+
+ ``errors`` is a list of all the error strings that the field is expected to
+ have. You can also pass a single error string if you only expect one error
+ which means that ``errors='error message'`` is the same as
+ ``errors=['error message']``.
- ``form`` is the name the ``Form`` instance was given in the template
- context of the response.
+ .. versionchanged:: 4.1
- ``field`` is the name of the field on the form to check. If ``field``
- has a value of ``None``, non-field errors (errors you can access via
- :meth:`form.non_field_errors() <django.forms.Form.non_field_errors>`) will
- be checked.
+ In older versions, using an empty error list with ``assertFormError()``
+ would always pass, regardless of whether the field had any errors or
+ not. Starting from Django 4.1, using ``errors=[]`` will only pass if
+ the field actually has no errors.
- ``errors`` is an error string, or a list of error strings, that are
- expected as a result of form validation.
+ Django 4.1 also changed the behavior of ``assertFormError()`` when a
+ field has multiple errors. In older versions, if a field had multiple
+ errors and you checked for only some of them, the test would pass.
+ Starting from Django 4.1, the error list must be an exact match to the
+ field's actual errors.
-.. method:: SimpleTestCase.assertFormsetError(response, formset, form_index, field, errors, msg_prefix='')
+ .. deprecated:: 4.1
+
+ Support for passing a response object and a form name to
+ ``assertFormError()`` is deprecated and will be removed in Django 5.0.
+ Use the form instance directly instead.
+
+.. method:: SimpleTestCase.assertFormsetError(formset, form_index, field, errors, msg_prefix='')
Asserts that the ``formset`` raises the provided list of errors when
rendered.
- ``response`` must be a response instance returned by the
- :class:`test client <django.test.Response>`.
+ ``formset`` is a ``Formset`` instance. The formset must be bound but not
+ necessarily validated (``assertFormsetError()`` will automatically call the
+ ``full_clean()`` on the formset).
- ``formset`` is the name the ``Formset`` instance was given in the template
- context of the response.
+ ``form_index`` is the number of the form within the ``Formset`` (starting
+ from 0). Use ``form_index=None`` to check the formset's non-form errors,
+ i.e. the errors you get when calling ``formset.non_form_errors()``. In that
+ case you must also use ``field=None``.
- ``form_index`` is the number of the form within the ``Formset``. If
- ``form_index`` has a value of ``None``, non-form errors (errors you can
- access via ``formset.non_form_errors()``) will be checked.
+ ``field`` and ``errors`` have the same meaning as the parameters to
+ ``assertFormError()``.
- ``field`` is the name of the field on the form to check. If ``field``
- has a value of ``None``, non-field errors (errors you can access via
- :meth:`form.non_field_errors() <django.forms.Form.non_field_errors>`) will
- be checked.
+ .. deprecated:: 4.1
- ``errors`` is an error string, or a list of error strings, that are
- expected as a result of form validation.
+ Support for passing a response object and a formset name to
+ ``assertFormsetError()`` is deprecated and will be removed in Django
+ 5.0. Use the formset instance directly instead.
.. method:: SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 185c1bff26..94d9d80289 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -2128,7 +2128,9 @@ class AdminViewPermissionsTest(TestCase):
self.assertEqual(response.status_code, 302)
login = self.client.post(login_url, self.no_username_login)
self.assertEqual(login.status_code, 200)
- self.assertFormError(login, "form", "username", ["This field is required."])
+ self.assertFormError(
+ login.context["form"], "username", ["This field is required."]
+ )
def test_login_redirect_for_direct_get(self):
"""
@@ -6711,10 +6713,9 @@ class UserAdminTest(TestCase):
},
)
self.assertEqual(response.status_code, 200)
- self.assertFormError(response, "adminform", "password1", [])
+ self.assertFormError(response.context["adminform"], "password1", [])
self.assertFormError(
- response,
- "adminform",
+ response.context["adminform"],
"password2",
["The two password fields didn’t match."],
)
@@ -7836,12 +7837,13 @@ class AdminViewOnSiteTests(TestCase):
reverse("admin:admin_views_parentwithdependentchildren_add"), post_data
)
self.assertFormError(
- response, "adminform", "some_required_info", ["This field is required."]
+ response.context["adminform"],
+ "some_required_info",
+ ["This field is required."],
)
- self.assertFormError(response, "adminform", None, [])
+ self.assertFormError(response.context["adminform"], None, [])
self.assertFormsetError(
- response,
- "inline_admin_formset",
+ response.context["inline_admin_formset"],
0,
None,
[
@@ -7849,7 +7851,9 @@ class AdminViewOnSiteTests(TestCase):
"contrived test case"
],
)
- self.assertFormsetError(response, "inline_admin_formset", None, None, [])
+ self.assertFormsetError(
+ response.context["inline_admin_formset"], None, None, []
+ )
def test_change_view_form_and_formsets_run_validation(self):
"""
@@ -7879,11 +7883,12 @@ class AdminViewOnSiteTests(TestCase):
post_data,
)
self.assertFormError(
- response, "adminform", "some_required_info", ["This field is required."]
+ response.context["adminform"],
+ "some_required_info",
+ ["This field is required."],
)
self.assertFormsetError(
- response,
- "inline_admin_formset",
+ response.context["inline_admin_formset"],
0,
None,
[
diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
index 8fcf3e046d..f13b05f25b 100644
--- a/tests/test_client/tests.py
+++ b/tests/test_client/tests.py
@@ -437,10 +437,10 @@ class ClientTest(TestCase):
response = self.client.post("/form_view/", post_data)
self.assertContains(response, "This field is required.", 3)
self.assertTemplateUsed(response, "Invalid POST Template")
-
- self.assertFormError(response, "form", "email", "This field is required.")
- self.assertFormError(response, "form", "single", "This field is required.")
- self.assertFormError(response, "form", "multi", "This field is required.")
+ form = response.context["form"]
+ self.assertFormError(form, "email", "This field is required.")
+ self.assertFormError(form, "single", "This field is required.")
+ self.assertFormError(form, "multi", "This field is required.")
def test_form_error(self):
"POST erroneous data to a form"
@@ -455,7 +455,9 @@ class ClientTest(TestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "Invalid POST Template")
- self.assertFormError(response, "form", "email", "Enter a valid email address.")
+ self.assertFormError(
+ response.context["form"], "email", "Enter a valid email address."
+ )
def test_valid_form_with_template(self):
"POST valid data to a form using multiple templates"
@@ -480,10 +482,10 @@ class ClientTest(TestCase):
self.assertTemplateUsed(response, "form_view.html")
self.assertTemplateUsed(response, "base.html")
self.assertTemplateNotUsed(response, "Invalid POST Template")
-
- self.assertFormError(response, "form", "email", "This field is required.")
- self.assertFormError(response, "form", "single", "This field is required.")
- self.assertFormError(response, "form", "multi", "This field is required.")
+ form = response.context["form"]
+ self.assertFormError(form, "email", "This field is required.")
+ self.assertFormError(form, "single", "This field is required.")
+ self.assertFormError(form, "multi", "This field is required.")
def test_form_error_with_template(self):
"POST erroneous data to a form using multiple templates"
@@ -500,7 +502,9 @@ class ClientTest(TestCase):
self.assertTemplateUsed(response, "base.html")
self.assertTemplateNotUsed(response, "Invalid POST Template")
- self.assertFormError(response, "form", "email", "Enter a valid email address.")
+ self.assertFormError(
+ response.context["form"], "email", "Enter a valid email address."
+ )
def test_unknown_page(self):
"GET an invalid URL"
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index e0204e7083..e704ed5dc1 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -1373,6 +1373,7 @@ class TestFormset(formset_factory(TestForm)):
class AssertFormErrorTests(SimpleTestCase):
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_non_client_response(self):
msg = (
"assertFormError() is only usable on responses fetched using the "
@@ -1380,8 +1381,9 @@ class AssertFormErrorTests(SimpleTestCase):
)
response = HttpResponse()
with self.assertRaisesMessage(ValueError, msg):
- self.assertFormError(response, "formset", 0, "field", "invalid value")
+ self.assertFormError(response, "form", "field", "invalid value")
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_response_with_no_context(self):
msg = "Response did not use any contexts to render the response"
response = mock.Mock(context=[])
@@ -1397,6 +1399,7 @@ class AssertFormErrorTests(SimpleTestCase):
msg_prefix=msg_prefix,
)
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_form_not_in_context(self):
msg = "The form 'form' was not used to render the response"
response = mock.Mock(context=[{}])
@@ -1408,18 +1411,32 @@ class AssertFormErrorTests(SimpleTestCase):
response, "form", "field", "invalid value", msg_prefix=msg_prefix
)
+ def test_single_error(self):
+ self.assertFormError(TestForm.invalid(), "field", "invalid value")
+
+ def test_error_list(self):
+ self.assertFormError(TestForm.invalid(), "field", ["invalid value"])
+
+ def test_empty_errors_valid_form(self):
+ self.assertFormError(TestForm.valid(), "field", [])
+
+ def test_empty_errors_valid_form_non_field_errors(self):
+ self.assertFormError(TestForm.valid(), None, [])
+
def test_field_not_in_form(self):
msg = (
"The form <TestForm bound=True, valid=False, fields=(field)> does not "
"contain the field 'other_field'."
)
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "other_field", "invalid value")
+ self.assertFormError(TestForm.invalid(), "other_field", "invalid value")
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError(
- response, "form", "other_field", "invalid value", msg_prefix=msg_prefix
+ TestForm.invalid(),
+ "other_field",
+ "invalid value",
+ msg_prefix=msg_prefix,
)
def test_field_with_no_errors(self):
@@ -1427,14 +1444,13 @@ class AssertFormErrorTests(SimpleTestCase):
"The errors of field 'field' on form <TestForm bound=True, valid=True, "
"fields=(field)> don't match."
)
- response = mock.Mock(context=[{"form": TestForm.valid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormError(response, "form", "field", "invalid value")
+ self.assertFormError(TestForm.valid(), "field", "invalid value")
self.assertIn("[] != ['invalid value']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError(
- response, "form", "field", "invalid value", msg_prefix=msg_prefix
+ TestForm.valid(), "field", "invalid value", msg_prefix=msg_prefix
)
def test_field_with_different_error(self):
@@ -1442,99 +1458,62 @@ class AssertFormErrorTests(SimpleTestCase):
"The errors of field 'field' on form <TestForm bound=True, valid=False, "
"fields=(field)> don't match."
)
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormError(response, "form", "field", "other error")
+ self.assertFormError(TestForm.invalid(), "field", "other error")
self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError(
- response, "form", "field", "other error", msg_prefix=msg_prefix
+ TestForm.invalid(), "field", "other error", msg_prefix=msg_prefix
)
- def test_basic_positive_assertion(self):
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
- self.assertFormError(response, "form", "field", "invalid value")
-
- def test_basic_positive_assertion_multicontext(self):
- response = mock.Mock(context=[{}, {"form": TestForm.invalid()}])
- self.assertFormError(response, "form", "field", "invalid value")
-
- def test_empty_errors_unbound_form(self):
+ def test_unbound_form(self):
msg = (
"The form <TestForm bound=False, valid=Unknown, fields=(field)> is not "
"bound, it will never have any errors."
)
- response = mock.Mock(context=[{"form": TestForm()}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "field", [])
+ self.assertFormError(TestForm(), "field", [])
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
- self.assertFormError(response, "form", "field", [], msg_prefix=msg_prefix)
-
- def test_empty_errors_valid_form(self):
- response = mock.Mock(context=[{"form": TestForm.valid()}])
- self.assertFormError(response, "form", "field", [])
+ self.assertFormError(TestForm(), "field", [], msg_prefix=msg_prefix)
def test_empty_errors_invalid_form(self):
msg = (
"The errors of field 'field' on form <TestForm bound=True, valid=False, "
"fields=(field)> don't match."
)
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormError(response, "form", "field", [])
+ self.assertFormError(TestForm.invalid(), "field", [])
self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self):
- response = mock.Mock(context=[{"form": TestForm.invalid(nonfield=True)}])
- self.assertFormError(response, "form", None, "non-field error")
+ self.assertFormError(TestForm.invalid(nonfield=True), None, "non-field error")
def test_different_non_field_errors(self):
- response = mock.Mock(context=[{"form": TestForm.invalid(nonfield=True)}])
msg = (
"The non-field errors of form <TestForm bound=True, valid=False, "
"fields=(field)> don't match."
)
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormError(response, "form", None, "other non-field error")
+ self.assertFormError(
+ TestForm.invalid(nonfield=True), None, "other non-field error"
+ )
self.assertIn(
"['non-field error'] != ['other non-field error']", str(ctx.exception)
)
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError(
- response, "form", None, "other non-field error", msg_prefix=msg_prefix
+ TestForm.invalid(nonfield=True),
+ None,
+ "other non-field error",
+ msg_prefix=msg_prefix,
)
- @ignore_warnings(category=RemovedInDjango50Warning)
- def test_errors_none(self):
- msg = (
- "The errors of field 'field' on form <TestForm bound=True, valid=False, "
- "fields=(field)> don't match."
- )
- response = mock.Mock(context=[{"form": TestForm.invalid()}])
- with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormError(response, "form", "field", None)
-
- def test_errors_none_warning(self):
- response = mock.Mock(context=[{"form": TestForm.valid()}])
- msg = (
- "Passing errors=None to assertFormError() is deprecated, use "
- "errors=[] instead."
- )
- with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
- self.assertFormError(response, "form", "field", None)
-
class AssertFormsetErrorTests(SimpleTestCase):
- def _get_formset_data(self, field_value):
- return {
- "form-TOTAL_FORMS": "1",
- "form-INITIAL_FORMS": "0",
- "form-0-field": field_value,
- }
-
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_non_client_response(self):
msg = (
"assertFormsetError() is only usable on responses fetched using "
@@ -1544,12 +1523,14 @@ class AssertFormsetErrorTests(SimpleTestCase):
with self.assertRaisesMessage(ValueError, msg):
self.assertFormsetError(response, "formset", 0, "field", "invalid value")
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_response_with_no_context(self):
msg = "Response did not use any contexts to render the response"
response = mock.Mock(context=[])
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(response, "formset", 0, "field", "invalid value")
+ @ignore_warnings(category=RemovedInDjango50Warning)
def test_formset_not_in_context(self):
msg = "The formset 'formset' was not used to render the response"
response = mock.Mock(context=[{}])
@@ -1561,25 +1542,41 @@ class AssertFormsetErrorTests(SimpleTestCase):
response, "formset", 0, "field", "invalid value", msg_prefix=msg_prefix
)
+ def test_single_error(self):
+ self.assertFormsetError(TestFormset.invalid(), 0, "field", "invalid value")
+
+ def test_error_list(self):
+ self.assertFormsetError(TestFormset.invalid(), 0, "field", ["invalid value"])
+
+ def test_empty_errors_valid_formset(self):
+ self.assertFormsetError(TestFormset.valid(), 0, "field", [])
+
+ def test_multiple_forms(self):
+ formset = TestFormset(
+ {
+ "form-TOTAL_FORMS": "2",
+ "form-INITIAL_FORMS": "0",
+ "form-0-field": "valid",
+ "form-1-field": "invalid",
+ }
+ )
+ formset.full_clean()
+ self.assertFormsetError(formset, 0, "field", [])
+ self.assertFormsetError(formset, 1, "field", ["invalid value"])
+
def test_field_not_in_form(self):
msg = (
"The form 0 of formset <TestFormset: bound=True valid=False total_forms=1> "
"does not contain the field 'other_field'."
)
- response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(
- response,
- "formset",
- 0,
- "other_field",
- "invalid value",
+ TestFormset.invalid(), 0, "other_field", "invalid value"
)
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response,
- "formset",
+ TestFormset.invalid(),
0,
"other_field",
"invalid value",
@@ -1591,14 +1588,13 @@ class AssertFormsetErrorTests(SimpleTestCase):
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=True total_forms=1> don't match."
)
- response = mock.Mock(context=[{"formset": TestFormset.valid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", 0, "field", "invalid value")
+ self.assertFormsetError(TestFormset.valid(), 0, "field", "invalid value")
self.assertIn("[] != ['invalid value']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response, "formset", 0, "field", "invalid value", msg_prefix=msg_prefix
+ TestFormset.valid(), 0, "field", "invalid value", msg_prefix=msg_prefix
)
def test_field_with_different_error(self):
@@ -1606,67 +1602,45 @@ class AssertFormsetErrorTests(SimpleTestCase):
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match."
)
- response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", 0, "field", "other error")
+ self.assertFormsetError(TestFormset.invalid(), 0, "field", "other error")
self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response, "formset", 0, "field", "other error", msg_prefix=msg_prefix
+ TestFormset.invalid(), 0, "field", "other error", msg_prefix=msg_prefix
)
- def test_basic_positive_assertion(self):
- response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
- self.assertFormsetError(response, "formset", 0, "field", "invalid value")
-
- def test_basic_positive_assertion_multicontext(self):
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
- self.assertFormsetError(response, "formset", 0, "field", "invalid value")
-
- def test_empty_errors_unbound_formset(self):
+ def test_unbound_formset(self):
msg = (
"The formset <TestFormset: bound=False valid=Unknown total_forms=1> is not "
"bound, it will never have any errors."
)
- response = mock.Mock(context=[{"formset": TestFormset()}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 0, "field", [])
-
- def test_empty_errors_valid_formset(self):
- response = mock.Mock(context=[{}, {"formset": TestFormset.valid()}])
- self.assertFormsetError(response, "formset", 0, "field", [])
+ self.assertFormsetError(TestFormset(), 0, "field", [])
def test_empty_errors_invalid_formset(self):
msg = (
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match."
)
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", 0, "field", [])
+ self.assertFormsetError(TestFormset.invalid(), 0, "field", [])
self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self):
- response = mock.Mock(
- context=[
- {},
- {"formset": TestFormset.invalid(nonfield=True)},
- ]
+ self.assertFormsetError(
+ TestFormset.invalid(nonfield=True), 0, None, "non-field error"
)
- self.assertFormsetError(response, "formset", 0, None, "non-field error")
def test_different_non_field_errors(self):
- response = mock.Mock(
- context=[{}, {"formset": TestFormset.invalid(nonfield=True)}],
- )
msg = (
"The non-field errors of form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match."
)
with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormsetError(
- response, "formset", 0, None, "other non-field error"
+ TestFormset.invalid(nonfield=True), 0, None, "other non-field error"
)
self.assertIn(
"['non-field error'] != ['other non-field error']", str(ctx.exception)
@@ -1674,8 +1648,7 @@ class AssertFormsetErrorTests(SimpleTestCase):
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response,
- "formset",
+ TestFormset.invalid(nonfield=True),
0,
None,
"other non-field error",
@@ -1683,80 +1656,74 @@ class AssertFormsetErrorTests(SimpleTestCase):
)
def test_no_non_field_errors(self):
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
msg = (
"The non-field errors of form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match."
)
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", 0, None, "non-field error")
+ self.assertFormsetError(TestFormset.invalid(), 0, None, "non-field error")
self.assertIn("[] != ['non-field error']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response, "formset", 0, None, "non-field error", msg_prefix=msg_prefix
+ TestFormset.invalid(), 0, None, "non-field error", msg_prefix=msg_prefix
)
def test_non_form_errors(self):
- response = mock.Mock(
- context=[
- {},
- {"formset": TestFormset.invalid(nonform=True)},
- ]
- )
- self.assertFormsetError(response, "formset", None, None, "error")
+ self.assertFormsetError(TestFormset.invalid(nonform=True), None, None, "error")
def test_different_non_form_errors(self):
- response = mock.Mock(
- context=[{}, {"formset": TestFormset.invalid(nonform=True)}],
- )
msg = (
"The non-form errors of formset <TestFormset: bound=True valid=False "
"total_forms=0> don't match."
)
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", None, None, "other error")
+ self.assertFormsetError(
+ TestFormset.invalid(nonform=True), None, None, "other error"
+ )
self.assertIn("['error'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response, "formset", None, None, "other error", msg_prefix=msg_prefix
+ TestFormset.invalid(nonform=True),
+ None,
+ None,
+ "other error",
+ msg_prefix=msg_prefix,
)
def test_no_non_form_errors(self):
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
msg = (
"The non-form errors of formset <TestFormset: bound=True valid=False "
"total_forms=1> don't match."
)
with self.assertRaisesMessage(AssertionError, msg) as ctx:
- self.assertFormsetError(response, "formset", None, None, "error")
+ self.assertFormsetError(TestFormset.invalid(), None, None, "error")
self.assertIn("[] != ['error']", str(ctx.exception))
msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError(
- response, "formset", None, None, "error", msg_prefix=msg_prefix
+ TestFormset.invalid(),
+ None,
+ None,
+ "error",
+ msg_prefix=msg_prefix,
)
def test_non_form_errors_with_field(self):
- response = mock.Mock(
- context=[
- {},
- {"formset": TestFormset.invalid(nonform=True)},
- ]
- )
msg = "You must use field=None with form_index=None."
with self.assertRaisesMessage(ValueError, msg):
- self.assertFormsetError(response, "formset", None, "field", "error")
+ self.assertFormsetError(
+ TestFormset.invalid(nonform=True), None, "field", "error"
+ )
def test_form_index_too_big(self):
msg = (
"The formset <TestFormset: bound=True valid=False total_forms=1> only has "
"1 form."
)
- response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 2, "field", "error")
+ self.assertFormsetError(TestFormset.invalid(), 2, "field", "error")
def test_form_index_too_big_plural(self):
formset = TestFormset(
@@ -1772,40 +1739,221 @@ class AssertFormsetErrorTests(SimpleTestCase):
"The formset <TestFormset: bound=True valid=True total_forms=2> only has 2 "
"forms."
)
- response = mock.Mock(context=[{}, {"formset": formset}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 2, "field", "error")
+ self.assertFormsetError(formset, 2, "field", "error")
- 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},
- ]
+
+# RemovedInDjango50Warning
+class AssertFormErrorDeprecationTests(SimpleTestCase):
+ """
+ Exhaustively test all possible combinations of args/kwargs for the old
+ signature.
+ """
+
+ @ignore_warnings(category=RemovedInDjango50Warning)
+ def test_assert_form_error_errors_none(self):
+ msg = (
+ "The errors of field 'field' on form <TestForm bound=True, valid=False, "
+ "fields=(field)> don't match."
)
- self.assertFormsetError(response, "form", 0, "field", "invalid value")
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertFormError(TestForm.invalid(), "field", None)
+
+ def test_assert_form_error_errors_none_warning(self):
+ msg = (
+ "Passing errors=None to assertFormError() is deprecated, use "
+ "errors=[] instead."
+ )
+ with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
+ self.assertFormError(TestForm.valid(), "field", None)
+
+ def _assert_form_error_old_api_cases(self, form, field, errors, msg_prefix):
+ response = mock.Mock(context=[{"form": TestForm.invalid()}])
+ return (
+ ((response, form, field, errors), {}),
+ ((response, form, field, errors, msg_prefix), {}),
+ ((response, form, field, errors), {"msg_prefix": msg_prefix}),
+ ((response, form, field), {"errors": errors}),
+ ((response, form, field), {"errors": errors, "msg_prefix": msg_prefix}),
+ ((response, form), {"field": field, "errors": errors}),
+ (
+ (response, form),
+ {"field": field, "errors": errors, "msg_prefix": msg_prefix},
+ ),
+ ((response,), {"form": form, "field": field, "errors": errors}),
+ (
+ (response,),
+ {
+ "form": form,
+ "field": field,
+ "errors": errors,
+ "msg_prefix": msg_prefix,
+ },
+ ),
+ (
+ (),
+ {"response": response, "form": form, "field": field, "errors": errors},
+ ),
+ (
+ (),
+ {
+ "response": response,
+ "form": form,
+ "field": field,
+ "errors": errors,
+ "msg_prefix": msg_prefix,
+ },
+ ),
+ )
+
+ def test_assert_form_error_old_api(self):
+ deprecation_msg = (
+ "Passing response to assertFormError() is deprecated. Use the form object "
+ "directly: assertFormError(response.context['form'], 'field', ...)"
+ )
+ for args, kwargs in self._assert_form_error_old_api_cases(
+ form="form",
+ field="field",
+ errors=["invalid value"],
+ msg_prefix="Custom prefix",
+ ):
+ with self.subTest(args=args, kwargs=kwargs):
+ with self.assertWarnsMessage(RemovedInDjango50Warning, deprecation_msg):
+ self.assertFormError(*args, **kwargs)
@ignore_warnings(category=RemovedInDjango50Warning)
- def test_errors_none(self):
+ def test_assert_form_error_old_api_assertion_error(self):
+ for args, kwargs in self._assert_form_error_old_api_cases(
+ form="form",
+ field="field",
+ errors=["other error"],
+ msg_prefix="Custom prefix",
+ ):
+ with self.subTest(args=args, kwargs=kwargs):
+ with self.assertRaises(AssertionError):
+ self.assertFormError(*args, **kwargs)
+
+ @ignore_warnings(category=RemovedInDjango50Warning)
+ def test_assert_formset_error_errors_none(self):
msg = (
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match."
)
- response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg):
- self.assertFormsetError(response, "formset", 0, "field", None)
+ self.assertFormsetError(TestFormset.invalid(), 0, "field", None)
- def test_errors_none_warning(self):
- response = mock.Mock(context=[{"formset": TestFormset.valid()}])
+ def test_assert_formset_error_errors_none_warning(self):
msg = (
"Passing errors=None to assertFormsetError() is deprecated, use "
"errors=[] instead."
)
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
- self.assertFormsetError(response, "formset", 0, "field", None)
+ self.assertFormsetError(TestFormset.valid(), 0, "field", None)
+
+ def _assert_formset_error_old_api_cases(
+ self, formset, form_index, field, errors, msg_prefix
+ ):
+ response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
+ return (
+ ((response, formset, form_index, field, errors), {}),
+ ((response, formset, form_index, field, errors, msg_prefix), {}),
+ (
+ (response, formset, form_index, field, errors),
+ {"msg_prefix": msg_prefix},
+ ),
+ ((response, formset, form_index, field), {"errors": errors}),
+ (
+ (response, formset, form_index, field),
+ {"errors": errors, "msg_prefix": msg_prefix},
+ ),
+ ((response, formset, form_index), {"field": field, "errors": errors}),
+ (
+ (response, formset, form_index),
+ {"field": field, "errors": errors, "msg_prefix": msg_prefix},
+ ),
+ (
+ (response, formset),
+ {"form_index": form_index, "field": field, "errors": errors},
+ ),
+ (
+ (response, formset),
+ {
+ "form_index": form_index,
+ "field": field,
+ "errors": errors,
+ "msg_prefix": msg_prefix,
+ },
+ ),
+ (
+ (response,),
+ {
+ "formset": formset,
+ "form_index": form_index,
+ "field": field,
+ "errors": errors,
+ },
+ ),
+ (
+ (response,),
+ {
+ "formset": formset,
+ "form_index": form_index,
+ "field": field,
+ "errors": errors,
+ "msg_prefix": msg_prefix,
+ },
+ ),
+ (
+ (),
+ {
+ "response": response,
+ "formset": formset,
+ "form_index": form_index,
+ "field": field,
+ "errors": errors,
+ },
+ ),
+ (
+ (),
+ {
+ "response": response,
+ "formset": formset,
+ "form_index": form_index,
+ "field": field,
+ "errors": errors,
+ "msg_prefix": msg_prefix,
+ },
+ ),
+ )
+
+ def test_assert_formset_error_old_api(self):
+ deprecation_msg = (
+ "Passing response to assertFormsetError() is deprecated. Use the formset "
+ "object directly: assertFormsetError(response.context['formset'], 0, ...)"
+ )
+ for args, kwargs in self._assert_formset_error_old_api_cases(
+ formset="formset",
+ form_index=0,
+ field="field",
+ errors=["invalid value"],
+ msg_prefix="Custom prefix",
+ ):
+ with self.subTest(args=args, kwargs=kwargs):
+ with self.assertWarnsMessage(RemovedInDjango50Warning, deprecation_msg):
+ self.assertFormsetError(*args, **kwargs)
+
+ @ignore_warnings(category=RemovedInDjango50Warning)
+ def test_assert_formset_error_old_api_assertion_error(self):
+ for args, kwargs in self._assert_formset_error_old_api_cases(
+ formset="formset",
+ form_index=0,
+ field="field",
+ errors=["other error"],
+ msg_prefix="Custom prefix",
+ ):
+ with self.subTest(args=args, kwargs=kwargs):
+ with self.assertRaises(AssertionError):
+ self.assertFormsetError(*args, **kwargs)
class FirstUrls: