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.
This commit is contained in:
Baptiste Mispelon 2021-12-10 12:22:23 +01:00 committed by Mariusz Felisiak
parent 1a7d75cf77
commit 50e1e7ef8e
8 changed files with 563 additions and 290 deletions

View File

@ -441,9 +441,8 @@ class InlineAdminFormSet:
def forms(self): def forms(self):
return self.formset.forms return self.formset.forms
@property
def non_form_errors(self): def non_form_errors(self):
return self.formset.non_form_errors return self.formset.non_form_errors()
@property @property
def is_bound(self): def is_bound(self):

View File

@ -1,5 +1,6 @@
import asyncio import asyncio
import difflib import difflib
import inspect
import json import json
import logging import logging
import posixpath import posixpath
@ -42,6 +43,7 @@ from django.db import DEFAULT_DB_ALIAS, connection, connections, transaction
from django.forms.fields import CharField from django.forms.fields import CharField
from django.http import QueryDict from django.http import QueryDict
from django.http.request import split_domain_port, validate_host 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.client import AsyncClient, Client
from django.test.html import HTMLParseError, parse_html from django.test.html import HTMLParseError, parse_html
from django.test.signals import template_rendered from django.test.signals import template_rendered
@ -165,6 +167,127 @@ class _DatabaseFailure:
raise DatabaseOperationForbidden(self.message) 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): class SimpleTestCase(unittest.TestCase):
# The class we'll use for the test client self.client. # 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) self.assertEqual(field_errors, errors, msg_prefix + failure_message)
def assertFormError(self, response, form, field, errors, msg_prefix=""): # RemovedInDjango50Warning: When the deprecation ends, remove the
# decorator.
@_AssertFormErrorDeprecationHelper.patch_signature
def assertFormError(self, form, field, errors, msg_prefix=""):
""" """
Assert that a form used to render the response has a specific field Assert that a field named "field" on the given form object has specific
error. errors.
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.
""" """
self._check_test_client_response(response, "context", "assertFormError")
if msg_prefix:
msg_prefix += ": "
# 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"
)
if errors is None: if errors is None:
warnings.warn( warnings.warn(
"Passing errors=None to assertFormError() is deprecated, use " "Passing errors=None to assertFormError() is deprecated, use "
@ -609,47 +729,25 @@ class SimpleTestCase(unittest.TestCase):
stacklevel=2, stacklevel=2,
) )
errors = [] 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: if msg_prefix:
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. # RemovedInDjango50Warning: When the deprecation ends, remove the
contexts = [] if response.context is None else to_list(response.context) # decorator.
if not contexts: @_AssertFormErrorDeprecationHelper.patch_signature
self.fail( def assertFormsetError(self, formset, form_index, field, errors, msg_prefix=""):
msg_prefix + "Response did not use any contexts to " """
"render the response" 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: if errors is None:
warnings.warn( warnings.warn(
"Passing errors=None to assertFormsetError() is deprecated, " "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: if form_index is None and field is not None:
raise ValueError("You must use field=None with form_index=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) errors = to_list(errors)
# Search all contexts for the error. if not formset.is_bound:
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:
self.fail( self.fail(
msg_prefix f"{msg_prefix}The formset {formset!r} is not bound, it will never have "
+ "The formset '%s' was not used to render the response" % formset 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): def _get_template_used(self, response, template_name, msg_prefix, method_name):

View File

@ -97,6 +97,10 @@ details on these changes.
* The ``django.utils.timezone.utc`` alias to ``datetime.timezone.utc`` will be * The ``django.utils.timezone.utc`` alias to ``datetime.timezone.utc`` will be
removed. 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: .. _deprecation-removed-in-4.1:
4.1 4.1

View File

@ -327,6 +327,10 @@ Tests
* A nested atomic block marked as durable in :class:`django.test.TestCase` now * A nested atomic block marked as durable in :class:`django.test.TestCase` now
raises a ``RuntimeError``, the same as outside of tests. 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 URLs
~~~~ ~~~~
@ -449,6 +453,9 @@ Miscellaneous
* The admin log out UI now uses ``POST`` requests. * 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: .. _deprecated-features-4.1:
Features deprecated in 4.1 Features deprecated in 4.1
@ -552,6 +559,15 @@ Miscellaneous
* The :data:`django.utils.timezone.utc` alias to :attr:`datetime.timezone.utc` * The :data:`django.utils.timezone.utc` alias to :attr:`datetime.timezone.utc`
is deprecated. Use :attr:`datetime.timezone.utc` directly. 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 Features removed in 4.1
======================= =======================

View File

@ -1473,47 +1473,65 @@ your test suite.
self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': ['Enter a valid email address.']}) 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 Asserts that a field on a form raises the provided list of errors.
rendered on the form.
``response`` must be a response instance returned by the ``form`` is a ``Form`` instance. The form must be
:class:`test client <django.test.Response>`. :ref:`bound <ref-forms-api-bound-unbound>` but not necessarily
validated (``assertFormError()`` will automatically call ``full_clean()``
on the form).
``form`` is the name the ``Form`` instance was given in the template ``field`` is the name of the field on the form to check. To check the form's
context of the response. :meth:`non-field errors <django.forms.Form.non_field_errors>`, use
``field=None``.
``field`` is the name of the field on the form to check. If ``field`` ``errors`` is a list of all the error strings that the field is expected to
has a value of ``None``, non-field errors (errors you can access via have. You can also pass a single error string if you only expect one error
:meth:`form.non_field_errors() <django.forms.Form.non_field_errors>`) will which means that ``errors='error message'`` is the same as
be checked. ``errors=['error message']``.
``errors`` is an error string, or a list of error strings, that are .. versionchanged:: 4.1
expected as a result of form validation.
.. method:: SimpleTestCase.assertFormsetError(response, formset, form_index, field, errors, msg_prefix='') 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.
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.
.. 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 Asserts that the ``formset`` raises the provided list of errors when
rendered. rendered.
``response`` must be a response instance returned by the ``formset`` is a ``Formset`` instance. The formset must be bound but not
:class:`test client <django.test.Response>`. necessarily validated (``assertFormsetError()`` will automatically call the
``full_clean()`` on the formset).
``formset`` is the name the ``Formset`` instance was given in the template ``form_index`` is the number of the form within the ``Formset`` (starting
context of the response. 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 ``field`` and ``errors`` have the same meaning as the parameters to
``form_index`` has a value of ``None``, non-form errors (errors you can ``assertFormError()``.
access via ``formset.non_form_errors()``) will be checked.
``field`` is the name of the field on the form to check. If ``field`` .. deprecated:: 4.1
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.
``errors`` is an error string, or a list of error strings, that are Support for passing a response object and a formset name to
expected as a result of form validation. ``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) .. method:: SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)

View File

@ -2128,7 +2128,9 @@ class AdminViewPermissionsTest(TestCase):
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
login = self.client.post(login_url, self.no_username_login) login = self.client.post(login_url, self.no_username_login)
self.assertEqual(login.status_code, 200) 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): def test_login_redirect_for_direct_get(self):
""" """
@ -6711,10 +6713,9 @@ class UserAdminTest(TestCase):
}, },
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertFormError(response, "adminform", "password1", []) self.assertFormError(response.context["adminform"], "password1", [])
self.assertFormError( self.assertFormError(
response, response.context["adminform"],
"adminform",
"password2", "password2",
["The two password fields didnt match."], ["The two password fields didnt match."],
) )
@ -7836,12 +7837,13 @@ class AdminViewOnSiteTests(TestCase):
reverse("admin:admin_views_parentwithdependentchildren_add"), post_data reverse("admin:admin_views_parentwithdependentchildren_add"), post_data
) )
self.assertFormError( 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( self.assertFormsetError(
response, response.context["inline_admin_formset"],
"inline_admin_formset",
0, 0,
None, None,
[ [
@ -7849,7 +7851,9 @@ class AdminViewOnSiteTests(TestCase):
"contrived test case" "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): def test_change_view_form_and_formsets_run_validation(self):
""" """
@ -7879,11 +7883,12 @@ class AdminViewOnSiteTests(TestCase):
post_data, post_data,
) )
self.assertFormError( self.assertFormError(
response, "adminform", "some_required_info", ["This field is required."] response.context["adminform"],
"some_required_info",
["This field is required."],
) )
self.assertFormsetError( self.assertFormsetError(
response, response.context["inline_admin_formset"],
"inline_admin_formset",
0, 0,
None, None,
[ [

View File

@ -437,10 +437,10 @@ class ClientTest(TestCase):
response = self.client.post("/form_view/", post_data) response = self.client.post("/form_view/", post_data)
self.assertContains(response, "This field is required.", 3) self.assertContains(response, "This field is required.", 3)
self.assertTemplateUsed(response, "Invalid POST Template") self.assertTemplateUsed(response, "Invalid POST Template")
form = response.context["form"]
self.assertFormError(response, "form", "email", "This field is required.") self.assertFormError(form, "email", "This field is required.")
self.assertFormError(response, "form", "single", "This field is required.") self.assertFormError(form, "single", "This field is required.")
self.assertFormError(response, "form", "multi", "This field is required.") self.assertFormError(form, "multi", "This field is required.")
def test_form_error(self): def test_form_error(self):
"POST erroneous data to a form" "POST erroneous data to a form"
@ -455,7 +455,9 @@ class ClientTest(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "Invalid POST Template") 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): def test_valid_form_with_template(self):
"POST valid data to a form using multiple templates" "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, "form_view.html")
self.assertTemplateUsed(response, "base.html") self.assertTemplateUsed(response, "base.html")
self.assertTemplateNotUsed(response, "Invalid POST Template") self.assertTemplateNotUsed(response, "Invalid POST Template")
form = response.context["form"]
self.assertFormError(response, "form", "email", "This field is required.") self.assertFormError(form, "email", "This field is required.")
self.assertFormError(response, "form", "single", "This field is required.") self.assertFormError(form, "single", "This field is required.")
self.assertFormError(response, "form", "multi", "This field is required.") self.assertFormError(form, "multi", "This field is required.")
def test_form_error_with_template(self): def test_form_error_with_template(self):
"POST erroneous data to a form using multiple templates" "POST erroneous data to a form using multiple templates"
@ -500,7 +502,9 @@ class ClientTest(TestCase):
self.assertTemplateUsed(response, "base.html") self.assertTemplateUsed(response, "base.html")
self.assertTemplateNotUsed(response, "Invalid POST Template") 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): def test_unknown_page(self):
"GET an invalid URL" "GET an invalid URL"

View File

@ -1373,6 +1373,7 @@ class TestFormset(formset_factory(TestForm)):
class AssertFormErrorTests(SimpleTestCase): class AssertFormErrorTests(SimpleTestCase):
@ignore_warnings(category=RemovedInDjango50Warning)
def test_non_client_response(self): def test_non_client_response(self):
msg = ( msg = (
"assertFormError() is only usable on responses fetched using the " "assertFormError() is only usable on responses fetched using the "
@ -1380,8 +1381,9 @@ class AssertFormErrorTests(SimpleTestCase):
) )
response = HttpResponse() response = HttpResponse()
with self.assertRaisesMessage(ValueError, msg): 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): def test_response_with_no_context(self):
msg = "Response did not use any contexts to render the response" msg = "Response did not use any contexts to render the response"
response = mock.Mock(context=[]) response = mock.Mock(context=[])
@ -1397,6 +1399,7 @@ class AssertFormErrorTests(SimpleTestCase):
msg_prefix=msg_prefix, msg_prefix=msg_prefix,
) )
@ignore_warnings(category=RemovedInDjango50Warning)
def test_form_not_in_context(self): def test_form_not_in_context(self):
msg = "The form 'form' was not used to render the response" msg = "The form 'form' was not used to render the response"
response = mock.Mock(context=[{}]) response = mock.Mock(context=[{}])
@ -1408,18 +1411,32 @@ class AssertFormErrorTests(SimpleTestCase):
response, "form", "field", "invalid value", msg_prefix=msg_prefix 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): def test_field_not_in_form(self):
msg = ( msg = (
"The form <TestForm bound=True, valid=False, fields=(field)> does not " "The form <TestForm bound=True, valid=False, fields=(field)> does not "
"contain the field 'other_field'." "contain the field 'other_field'."
) )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg): 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" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError( 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): 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, " "The errors of field 'field' on form <TestForm bound=True, valid=True, "
"fields=(field)> don't match." "fields=(field)> don't match."
) )
response = mock.Mock(context=[{"form": TestForm.valid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("[] != ['invalid value']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError( 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): 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, " "The errors of field 'field' on form <TestForm bound=True, valid=False, "
"fields=(field)> don't match." "fields=(field)> don't match."
) )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError( 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): def test_unbound_form(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):
msg = ( msg = (
"The form <TestForm bound=False, valid=Unknown, fields=(field)> is not " "The form <TestForm bound=False, valid=Unknown, fields=(field)> is not "
"bound, it will never have any errors." "bound, it will never have any errors."
) )
response = mock.Mock(context=[{"form": TestForm()}])
with self.assertRaisesMessage(AssertionError, msg): with self.assertRaisesMessage(AssertionError, msg):
self.assertFormError(response, "form", "field", []) self.assertFormError(TestForm(), "field", [])
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError(response, "form", "field", [], msg_prefix=msg_prefix) self.assertFormError(TestForm(), "field", [], msg_prefix=msg_prefix)
def test_empty_errors_valid_form(self):
response = mock.Mock(context=[{"form": TestForm.valid()}])
self.assertFormError(response, "form", "field", [])
def test_empty_errors_invalid_form(self): def test_empty_errors_invalid_form(self):
msg = ( msg = (
"The errors of field 'field' on form <TestForm bound=True, valid=False, " "The errors of field 'field' on form <TestForm bound=True, valid=False, "
"fields=(field)> don't match." "fields=(field)> don't match."
) )
response = mock.Mock(context=[{"form": TestForm.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormError(response, "form", "field", []) self.assertFormError(TestForm.invalid(), "field", [])
self.assertIn("['invalid value'] != []", str(ctx.exception)) self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self): def test_non_field_errors(self):
response = mock.Mock(context=[{"form": TestForm.invalid(nonfield=True)}]) self.assertFormError(TestForm.invalid(nonfield=True), None, "non-field error")
self.assertFormError(response, "form", None, "non-field error")
def test_different_non_field_errors(self): def test_different_non_field_errors(self):
response = mock.Mock(context=[{"form": TestForm.invalid(nonfield=True)}])
msg = ( msg = (
"The non-field errors of form <TestForm bound=True, valid=False, " "The non-field errors of form <TestForm bound=True, valid=False, "
"fields=(field)> don't match." "fields=(field)> don't match."
) )
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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( self.assertIn(
"['non-field error'] != ['other non-field error']", str(ctx.exception) "['non-field error'] != ['other non-field error']", str(ctx.exception)
) )
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormError( 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): class AssertFormsetErrorTests(SimpleTestCase):
def _get_formset_data(self, field_value): @ignore_warnings(category=RemovedInDjango50Warning)
return {
"form-TOTAL_FORMS": "1",
"form-INITIAL_FORMS": "0",
"form-0-field": field_value,
}
def test_non_client_response(self): def test_non_client_response(self):
msg = ( msg = (
"assertFormsetError() is only usable on responses fetched using " "assertFormsetError() is only usable on responses fetched using "
@ -1544,12 +1523,14 @@ class AssertFormsetErrorTests(SimpleTestCase):
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(ValueError, msg):
self.assertFormsetError(response, "formset", 0, "field", "invalid value") self.assertFormsetError(response, "formset", 0, "field", "invalid value")
@ignore_warnings(category=RemovedInDjango50Warning)
def test_response_with_no_context(self): def test_response_with_no_context(self):
msg = "Response did not use any contexts to render the response" msg = "Response did not use any contexts to render the response"
response = mock.Mock(context=[]) response = mock.Mock(context=[])
with self.assertRaisesMessage(AssertionError, msg): with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(response, "formset", 0, "field", "invalid value") self.assertFormsetError(response, "formset", 0, "field", "invalid value")
@ignore_warnings(category=RemovedInDjango50Warning)
def test_formset_not_in_context(self): def test_formset_not_in_context(self):
msg = "The formset 'formset' was not used to render the response" msg = "The formset 'formset' was not used to render the response"
response = mock.Mock(context=[{}]) response = mock.Mock(context=[{}])
@ -1561,25 +1542,41 @@ class AssertFormsetErrorTests(SimpleTestCase):
response, "formset", 0, "field", "invalid value", msg_prefix=msg_prefix 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): def test_field_not_in_form(self):
msg = ( msg = (
"The form 0 of formset <TestFormset: bound=True valid=False total_forms=1> " "The form 0 of formset <TestFormset: bound=True valid=False total_forms=1> "
"does not contain the field 'other_field'." "does not contain the field 'other_field'."
) )
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg): with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError( self.assertFormsetError(
response, TestFormset.invalid(), 0, "other_field", "invalid value"
"formset",
0,
"other_field",
"invalid value",
) )
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( self.assertFormsetError(
response, TestFormset.invalid(),
"formset",
0, 0,
"other_field", "other_field",
"invalid value", "invalid value",
@ -1591,14 +1588,13 @@ class AssertFormsetErrorTests(SimpleTestCase):
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True " "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=True total_forms=1> don't match." "valid=True total_forms=1> don't match."
) )
response = mock.Mock(context=[{"formset": TestFormset.valid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("[] != ['invalid value']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( 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): 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 " "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match." "valid=False total_forms=1> don't match."
) )
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("['invalid value'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( 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): def test_unbound_formset(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):
msg = ( msg = (
"The formset <TestFormset: bound=False valid=Unknown total_forms=1> is not " "The formset <TestFormset: bound=False valid=Unknown total_forms=1> is not "
"bound, it will never have any errors." "bound, it will never have any errors."
) )
response = mock.Mock(context=[{"formset": TestFormset()}])
with self.assertRaisesMessage(AssertionError, msg): with self.assertRaisesMessage(AssertionError, msg):
self.assertFormsetError(response, "formset", 0, "field", []) self.assertFormsetError(TestFormset(), 0, "field", [])
def test_empty_errors_valid_formset(self):
response = mock.Mock(context=[{}, {"formset": TestFormset.valid()}])
self.assertFormsetError(response, "formset", 0, "field", [])
def test_empty_errors_invalid_formset(self): def test_empty_errors_invalid_formset(self):
msg = ( msg = (
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True " "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match." "valid=False total_forms=1> don't match."
) )
response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("['invalid value'] != []", str(ctx.exception))
def test_non_field_errors(self): def test_non_field_errors(self):
response = mock.Mock( self.assertFormsetError(
context=[ TestFormset.invalid(nonfield=True), 0, None, "non-field error"
{},
{"formset": TestFormset.invalid(nonfield=True)},
]
) )
self.assertFormsetError(response, "formset", 0, None, "non-field error")
def test_different_non_field_errors(self): def test_different_non_field_errors(self):
response = mock.Mock(
context=[{}, {"formset": TestFormset.invalid(nonfield=True)}],
)
msg = ( msg = (
"The non-field errors of form 0 of formset <TestFormset: bound=True " "The non-field errors of form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match." "valid=False total_forms=1> don't match."
) )
with self.assertRaisesMessage(AssertionError, msg) as ctx: with self.assertRaisesMessage(AssertionError, msg) as ctx:
self.assertFormsetError( self.assertFormsetError(
response, "formset", 0, None, "other non-field error" TestFormset.invalid(nonfield=True), 0, None, "other non-field error"
) )
self.assertIn( self.assertIn(
"['non-field error'] != ['other non-field error']", str(ctx.exception) "['non-field error'] != ['other non-field error']", str(ctx.exception)
@ -1674,8 +1648,7 @@ class AssertFormsetErrorTests(SimpleTestCase):
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( self.assertFormsetError(
response, TestFormset.invalid(nonfield=True),
"formset",
0, 0,
None, None,
"other non-field error", "other non-field error",
@ -1683,80 +1656,74 @@ class AssertFormsetErrorTests(SimpleTestCase):
) )
def test_no_non_field_errors(self): def test_no_non_field_errors(self):
response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
msg = ( msg = (
"The non-field errors of form 0 of formset <TestFormset: bound=True " "The non-field errors of form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match." "valid=False total_forms=1> don't match."
) )
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("[] != ['non-field error']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( 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): def test_non_form_errors(self):
response = mock.Mock( self.assertFormsetError(TestFormset.invalid(nonform=True), None, None, "error")
context=[
{},
{"formset": TestFormset.invalid(nonform=True)},
]
)
self.assertFormsetError(response, "formset", None, None, "error")
def test_different_non_form_errors(self): def test_different_non_form_errors(self):
response = mock.Mock(
context=[{}, {"formset": TestFormset.invalid(nonform=True)}],
)
msg = ( msg = (
"The non-form errors of formset <TestFormset: bound=True valid=False " "The non-form errors of formset <TestFormset: bound=True valid=False "
"total_forms=0> don't match." "total_forms=0> don't match."
) )
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("['error'] != ['other error']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( 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): def test_no_non_form_errors(self):
response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
msg = ( msg = (
"The non-form errors of formset <TestFormset: bound=True valid=False " "The non-form errors of formset <TestFormset: bound=True valid=False "
"total_forms=1> don't match." "total_forms=1> don't match."
) )
with self.assertRaisesMessage(AssertionError, msg) as ctx: 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)) self.assertIn("[] != ['error']", str(ctx.exception))
msg_prefix = "Custom prefix" msg_prefix = "Custom prefix"
with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"): with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
self.assertFormsetError( 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): 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." msg = "You must use field=None with form_index=None."
with self.assertRaisesMessage(ValueError, msg): 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): def test_form_index_too_big(self):
msg = ( msg = (
"The formset <TestFormset: bound=True valid=False total_forms=1> only has " "The formset <TestFormset: bound=True valid=False total_forms=1> only has "
"1 form." "1 form."
) )
response = mock.Mock(context=[{}, {"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg): 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): def test_form_index_too_big_plural(self):
formset = TestFormset( formset = TestFormset(
@ -1772,40 +1739,221 @@ class AssertFormsetErrorTests(SimpleTestCase):
"The formset <TestFormset: bound=True valid=True total_forms=2> only has 2 " "The formset <TestFormset: bound=True valid=True total_forms=2> only has 2 "
"forms." "forms."
) )
response = mock.Mock(context=[{}, {"formset": formset}])
with self.assertRaisesMessage(AssertionError, msg): 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() # RemovedInDjango50Warning
# The mocked context emulates the template-based rendering of the class AssertFormErrorDeprecationTests(SimpleTestCase):
# formset. """
response = mock.Mock( Exhaustively test all possible combinations of args/kwargs for the old
context=[ signature.
{"form": formset}, """
{"form": formset.management_form},
]
)
self.assertFormsetError(response, "form", 0, "field", "invalid value")
@ignore_warnings(category=RemovedInDjango50Warning) @ignore_warnings(category=RemovedInDjango50Warning)
def test_errors_none(self): 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."
)
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_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 = ( msg = (
"The errors of field 'field' on form 0 of formset <TestFormset: bound=True " "The errors of field 'field' on form 0 of formset <TestFormset: bound=True "
"valid=False total_forms=1> don't match." "valid=False total_forms=1> don't match."
) )
response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
with self.assertRaisesMessage(AssertionError, msg): 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): def test_assert_formset_error_errors_none_warning(self):
response = mock.Mock(context=[{"formset": TestFormset.valid()}])
msg = ( msg = (
"Passing errors=None to assertFormsetError() is deprecated, use " "Passing errors=None to assertFormsetError() is deprecated, use "
"errors=[] instead." "errors=[] instead."
) )
with self.assertWarnsMessage(RemovedInDjango50Warning, msg): 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: class FirstUrls: