1
0
mirror of https://github.com/django/django.git synced 2025-05-01 04:34:40 +00:00

Fixed #32820 -- Added aria-invalid="true" to fields with errors.

Co-authored-by: Demetris Stavrou <demestav@gmail.com>
Co-authored-by: David Smith <smithdc@gmail.com>
This commit is contained in:
Gregor Jerše 2023-06-02 16:27:24 +02:00 committed by Mariusz Felisiak
parent fff14736f1
commit 10725a3187
7 changed files with 156 additions and 95 deletions

View File

@ -287,6 +287,8 @@ class BoundField(RenderableFieldMixin):
attrs["required"] = True
if self.field.disabled:
attrs["disabled"] = True
if not widget.is_hidden and self.errors:
attrs["aria-invalid"] = "true"
# If a custom aria-describedby attribute is given (either via the attrs
# argument or widget.attrs) and help_text is used, the custom
# aria-described by is preserved so user can set the desired order.

View File

@ -992,10 +992,20 @@ method you're using:
... }
>>> f = ContactForm(data, auto_id=False)
>>> print(f)
<div>Subject:<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required>Hi there</textarea></div>
<div>Sender:<ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself" checked></div>
<div>Subject:
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="subject" maxlength="100" required aria-invalid="true">
</div>
<div>Message:
<textarea name="message" cols="40" rows="10" required>Hi there</textarea>
</div>
<div>Sender:
<ul class="errorlist"><li>Enter a valid email address.</li></ul>
<input type="email" name="sender" value="invalid email address" required aria-invalid="true">
</div>
<div>Cc myself:
<input type="checkbox" name="cc_myself" checked>
</div>
.. _ref-forms-error-list-format:
@ -1154,7 +1164,7 @@ Attributes of ``BoundField``
>>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""}
>>> f = ContactForm(data, auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required>
<input type="text" name="message" required aria-invalid="true">
>>> f["message"].errors
['This field is required.']
>>> print(f["message"].errors)
@ -1166,6 +1176,13 @@ Attributes of ``BoundField``
>>> str(f["subject"].errors)
''
When rendering a field with errors, ``aria-invalid="true"`` will be set on
the field's widget to indicate there is an error to screen reader users.
.. versionchanged:: 5.0
The ``aria-invalid="true"`` was added when a field has errors.
.. attribute:: BoundField.field
The form :class:`~django.forms.Field` instance from the form class that

View File

@ -196,9 +196,17 @@ and the HTML output will include any validation errors:
>>> default_data = {"name": "Your name", "url": "http://"}
>>> f = CommentForm(default_data, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="Your name" required></div>
<div>Url:<ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" required></div>
<div>Comment:<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" required></div>
<div>Name:
<input type="text" name="name" value="Your name" required>
</div>
<div>Url:
<ul class="errorlist"><li>Enter a valid URL.</li></ul>
<input type="url" name="url" value="http://" required aria-invalid="true">
</div>
<div>Comment:
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="comment" required aria-invalid="true">
</div>
This is why ``initial`` values are only displayed for unbound forms. For bound
forms, the HTML output will use the bound data.

View File

@ -310,6 +310,9 @@ Forms
fields with their help text, the form field now includes the
``aria-describedby`` HTML attribute.
* In order to improve accessibility, the invalid form field now includes the
``aria-invalid="true"`` HTML attribute.
Generic Views
~~~~~~~~~~~~~

View File

@ -182,61 +182,70 @@ class FormsTestCase(SimpleTestCase):
str(p),
'<div><label for="id_first_name">First name:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="first_name" required id="id_first_name"></div>'
'<input type="text" name="first_name" aria-invalid="true" required '
'id="id_first_name"></div>'
'<div><label for="id_last_name">Last name:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="last_name" required id="id_last_name"></div><div>'
'<input type="text" name="last_name" aria-invalid="true" required '
'id="id_last_name"></div><div>'
'<label for="id_birthday">Birthday:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="birthday" required id="id_birthday"></div>',
'<input type="text" name="birthday" aria-invalid="true" required '
'id="id_birthday"></div>',
)
self.assertHTMLEqual(
p.as_table(),
"""<tr><th><label for="id_first_name">First name:</label></th><td>
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="first_name" id="id_first_name" required></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th>
<input type="text" name="first_name" id="id_first_name" aria-invalid="true" required>
</td></tr><tr><th><label for="id_last_name">Last name:</label></th>
<td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="last_name" id="id_last_name" required></td></tr>
<tr><th><label for="id_birthday">Birthday:</label></th>
<input type="text" name="last_name" id="id_last_name" aria-invalid="true" required>
</td></tr><tr><th><label for="id_birthday">Birthday:</label></th>
<td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="birthday" id="id_birthday" required></td></tr>""",
<input type="text" name="birthday" id="id_birthday" aria-invalid="true" required>
</td></tr>""",
)
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
<label for="id_first_name">First name:</label>
<input type="text" name="first_name" id="id_first_name" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="first_name" id="id_first_name" aria-invalid="true" required>
</li><li><ul class="errorlist"><li>This field is required.</li></ul>
<label for="id_last_name">Last name:</label>
<input type="text" name="last_name" id="id_last_name" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="last_name" id="id_last_name" aria-invalid="true" required>
</li><li><ul class="errorlist"><li>This field is required.</li></ul>
<label for="id_birthday">Birthday:</label>
<input type="text" name="birthday" id="id_birthday" required></li>""",
<input type="text" name="birthday" id="id_birthday" aria-invalid="true" required>
</li>""",
)
self.assertHTMLEqual(
p.as_p(),
"""<ul class="errorlist"><li>This field is required.</li></ul>
<p><label for="id_first_name">First name:</label>
<input type="text" name="first_name" id="id_first_name" required></p>
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="first_name" id="id_first_name" aria-invalid="true" required>
</p><ul class="errorlist"><li>This field is required.</li></ul>
<p><label for="id_last_name">Last name:</label>
<input type="text" name="last_name" id="id_last_name" required></p>
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="last_name" id="id_last_name" aria-invalid="true" required>
</p><ul class="errorlist"><li>This field is required.</li></ul>
<p><label for="id_birthday">Birthday:</label>
<input type="text" name="birthday" id="id_birthday" required></p>""",
<input type="text" name="birthday" id="id_birthday" aria-invalid="true" required>
</p>""",
)
self.assertHTMLEqual(
p.as_div(),
'<div><label for="id_first_name">First name:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="first_name" required id="id_first_name"></div>'
'<input type="text" name="first_name" aria-invalid="true" required '
'id="id_first_name"></div>'
'<div><label for="id_last_name">Last name:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="last_name" required id="id_last_name"></div><div>'
'<input type="text" name="last_name" aria-invalid="true" required '
'id="id_last_name"></div><div>'
'<label for="id_birthday">Birthday:</label>'
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="birthday" required id="id_birthday"></div>',
'<input type="text" name="birthday" aria-invalid="true" required '
'id="id_birthday"></div>',
)
def test_empty_querydict_args(self):
@ -582,14 +591,16 @@ class FormsTestCase(SimpleTestCase):
{"email": "test@example.com", "get_spam": "False"}, auto_id=False
)
self.assertHTMLEqual(
str(f["get_spam"]), '<input type="checkbox" name="get_spam" required>'
str(f["get_spam"]),
'<input type="checkbox" name="get_spam" aria-invalid="true" required>',
)
f = SignupForm(
{"email": "test@example.com", "get_spam": "false"}, auto_id=False
)
self.assertHTMLEqual(
str(f["get_spam"]), '<input type="checkbox" name="get_spam" required>'
str(f["get_spam"]),
'<input type="checkbox" name="get_spam" aria-invalid="true" required>',
)
# A value of '0' should be interpreted as a True value (#16820)
@ -1406,13 +1417,13 @@ class FormsTestCase(SimpleTestCase):
<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td>
<ul class="errorlist">
<li>Something&#x27;s wrong with &#x27;Nothing to escape&#x27;</li></ul>
<input type="text" name="special_name" value="Nothing to escape" required>
</td></tr>
<input type="text" name="special_name" value="Nothing to escape"
aria-invalid="true" required></td></tr>
<tr><th><em>Special</em> Field:</th><td>
<ul class="errorlist">
<li>'<b>Nothing to escape</b>' is a safe string</li></ul>
<input type="text" name="special_safe_name" value="Nothing to escape"
required></td></tr>
aria-invalid="true" required></td></tr>
""",
)
f = EscapingForm(
@ -1429,13 +1440,14 @@ class FormsTestCase(SimpleTestCase):
"Something&#x27;s wrong with &#x27;Should escape &lt; &amp; &gt; and "
"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;&#x27;</li></ul>"
'<input type="text" name="special_name" value="Should escape &lt; &amp; '
'&gt; and &lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;" required>'
"</td></tr>"
'&gt; and &lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;" '
'aria-invalid="true" required></td></tr>'
"<tr><th><em>Special</em> Field:</th><td>"
'<ul class="errorlist">'
"<li>'<b><i>Do not escape</i></b>' is a safe string</li></ul>"
'<input type="text" name="special_safe_name" '
'value="&lt;i&gt;Do not escape&lt;/i&gt;" required></td></tr>',
'value="&lt;i&gt;Do not escape&lt;/i&gt;" aria-invalid="true" required>'
"</td></tr>",
)
def test_validating_multiple_fields(self):
@ -1537,11 +1549,12 @@ class FormsTestCase(SimpleTestCase):
f.as_table(),
"""<tr><th>Username:</th><td>
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="username" maxlength="10" required></td></tr>
<input type="text" name="username" maxlength="10" aria-invalid="true" required>
</td></tr>
<tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="password" name="password1" required></td></tr>
<input type="password" name="password1" aria-invalid="true" required></td></tr>
<tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="password" name="password2" required></td></tr>""",
<input type="password" name="password2" aria-invalid="true" required></td></tr>""",
)
self.assertEqual(f.errors["username"], ["This field is required."])
self.assertEqual(f.errors["password1"], ["This field is required."])
@ -2412,17 +2425,17 @@ class FormsTestCase(SimpleTestCase):
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>""",
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true" required></li>""",
)
p = UserRegistration({"username": ""}, auto_id=False)
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>""",
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true" required></li>""",
)
p = UserRegistration({"username": "foo"}, auto_id=False)
self.assertHTMLEqual(
@ -2431,7 +2444,8 @@ Password: <input type="password" name="password" required></li>""",
<li>Username: <input type="text" name="username" value="foo" maxlength="10"
required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>
Password: <input type="password" name="password" aria-invalid="true"
required></li>
""",
)
@ -2478,9 +2492,9 @@ Password: <input type="password" name="password" required></li>""",
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>""",
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true" required></li>""",
)
p = UserRegistration(
{"username": ""}, initial={"username": "django"}, auto_id=False
@ -2488,9 +2502,9 @@ Password: <input type="password" name="password" required></li>""",
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>""",
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true" required></li>""",
)
p = UserRegistration(
{"username": "foo"}, initial={"username": "django"}, auto_id=False
@ -2501,7 +2515,8 @@ Password: <input type="password" name="password" required></li>""",
<li>Username: <input type="text" name="username" value="foo" maxlength="10"
required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>
Password: <input type="password" name="password" aria-invalid="true"
required></li>
""",
)
@ -2580,11 +2595,11 @@ Password: <input type="password" name="password" required></li>""",
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Options: <select multiple name="options" required>
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Options: <select multiple name="options" aria-invalid="true" required>
<option value="f">foo</option>
<option value="b">bar</option>
<option value="w">whiz</option>
@ -2596,11 +2611,11 @@ Options: <select multiple name="options" required>
self.assertHTMLEqual(
p.as_ul(),
"""<li><ul class="errorlist"><li>This field is required.</li></ul>
Username: <input type="text" name="username" maxlength="10" required></li>
Username: <input type="text" name="username" maxlength="10" aria-invalid="true"
required></li><li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" aria-invalid="true" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Options: <select multiple name="options" required>
Options: <select multiple name="options" aria-invalid="true" required>
<option value="f">foo</option>
<option value="b">bar</option>
<option value="w">whiz</option>
@ -2617,8 +2632,8 @@ Options: <select multiple name="options" required>
<li>Username: <input type="text" name="username" value="foo" maxlength="10"
required></li>
<li><ul class="errorlist"><li>This field is required.</li></ul>
Password: <input type="password" name="password" required></li>
<li>Options: <select multiple name="options" required>
Password: <input type="password" name="password" aria-invalid="true"
required></li><li>Options: <select multiple name="options" required>
<option value="f" selected>foo</option>
<option value="b" selected>bar</option>
<option value="w">whiz</option>
@ -2958,8 +2973,8 @@ Options: <select multiple name="options" required>
'maxlength="10" required>'
'<span class="helptext">e.g., user@example.com</span></li>'
'<li><ul class="errorlist"><li>This field is required.</li></ul>'
'Password: <input type="password" name="password" required>'
'<span class="helptext">Wählen Sie mit Bedacht.</span></li>',
'Password: <input type="password" name="password" aria-invalid="true" '
'required><span class="helptext">Wählen Sie mit Bedacht.</span></li>',
)
# help_text is not displayed for hidden fields. It can be used for documentation
@ -3405,7 +3420,7 @@ Options: <select multiple name="options" required>
f.as_table(),
"<tr><th>File1:</th><td>"
'<ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="file" name="file1" required></td></tr>',
'<input type="file" name="file1" aria-invalid="true" required></td></tr>',
)
f = FileForm(
@ -3415,7 +3430,7 @@ Options: <select multiple name="options" required>
f.as_table(),
"<tr><th>File1:</th><td>"
'<ul class="errorlist"><li>The submitted file is empty.</li></ul>'
'<input type="file" name="file1" required></td></tr>',
'<input type="file" name="file1" aria-invalid="true" required></td></tr>',
)
f = FileForm(
@ -3426,7 +3441,7 @@ Options: <select multiple name="options" required>
"<tr><th>File1:</th><td>"
'<ul class="errorlist"><li>No file was submitted. Check the '
"encoding type on the form.</li></ul>"
'<input type="file" name="file1" required></td></tr>',
'<input type="file" name="file1" aria-invalid="true" required></td></tr>',
)
f = FileForm(
@ -3591,8 +3606,8 @@ Options: <select multiple name="options" required>
<li class="required error"><ul class="errorlist">
<li>This field is required.</li></ul>
<label class="required" for="id_name">Name:</label>
<input type="text" name="name" id="id_name" required></li>
<li class="required">
<input type="text" name="name" id="id_name" aria-invalid="true" required>
</li><li class="required">
<label class="required" for="id_is_cool">Is cool:</label>
<select name="is_cool" id="id_is_cool">
<option value="unknown" selected>Unknown</option>
@ -3604,7 +3619,8 @@ Options: <select multiple name="options" required>
<li class="required error"><ul class="errorlist">
<li>This field is required.</li></ul>
<label class="required" for="id_age">Age:</label>
<input type="number" name="age" id="id_age" required></li>""",
<input type="number" name="age" id="id_age" aria-invalid="true" required>
</li>""",
)
self.assertHTMLEqual(
@ -3613,8 +3629,8 @@ Options: <select multiple name="options" required>
<ul class="errorlist"><li>This field is required.</li></ul>
<p class="required error">
<label class="required" for="id_name">Name:</label>
<input type="text" name="name" id="id_name" required></p>
<p class="required">
<input type="text" name="name" id="id_name" aria-invalid="true" required>
</p><p class="required">
<label class="required" for="id_is_cool">Is cool:</label>
<select name="is_cool" id="id_is_cool">
<option value="unknown" selected>Unknown</option>
@ -3625,8 +3641,8 @@ Options: <select multiple name="options" required>
<input type="email" name="email" id="id_email" maxlength="320"></p>
<ul class="errorlist"><li>This field is required.</li></ul>
<p class="required error"><label class="required" for="id_age">Age:</label>
<input type="number" name="age" id="id_age" required></p>
""",
<input type="number" name="age" id="id_age" aria-invalid="true" required>
</p>""",
)
self.assertHTMLEqual(
@ -3634,7 +3650,7 @@ Options: <select multiple name="options" required>
"""<tr class="required error">
<th><label class="required" for="id_name">Name:</label></th>
<td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="name" id="id_name" required></td></tr>
<input type="text" name="name" id="id_name" aria-invalid="true" required></td></tr>
<tr class="required"><th><label class="required" for="id_is_cool">Is cool:</label></th>
<td><select name="is_cool" id="id_is_cool">
<option value="unknown" selected>Unknown</option>
@ -3645,13 +3661,14 @@ Options: <select multiple name="options" required>
<input type="email" name="email" id="id_email" maxlength="320"></td></tr>
<tr class="required error"><th><label class="required" for="id_age">Age:</label></th>
<td><ul class="errorlist"><li>This field is required.</li></ul>
<input type="number" name="age" id="id_age" required></td></tr>""",
<input type="number" name="age" id="id_age" aria-invalid="true" required></td></tr>""",
)
self.assertHTMLEqual(
p.as_div(),
'<div class="required error"><label for="id_name" class="required">Name:'
'</label><ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="text" name="name" required id="id_name" /></div>'
'<input type="text" name="name" required id="id_name" '
'aria-invalid="true" /></div>'
'<div class="required"><label for="id_is_cool" class="required">Is cool:'
'</label><select name="is_cool" id="id_is_cool">'
'<option value="unknown" selected>Unknown</option>'
@ -3660,7 +3677,8 @@ Options: <select multiple name="options" required>
'<input type="email" name="email" id="id_email" maxlength="320"/></div>'
'<div class="required error"><label for="id_age" class="required">Age:'
'</label><ul class="errorlist"><li>This field is required.</li></ul>'
'<input type="number" name="age" required id="id_age" /></div>',
'<input type="number" name="age" required id="id_age" '
'aria-invalid="true" /></div>',
)
def test_label_has_required_css_class(self):
@ -4342,7 +4360,8 @@ Options: <select multiple name="options" required>
"<li>(Hidden field hidden) Foo &amp; &quot;bar&quot;!</li></ul></li>"
'<li><ul class="errorlist"><li>Foo &amp; &quot;bar&quot;!</li></ul>'
'<label for="id_visible">Visible:</label> '
'<input type="text" name="visible" value="b" id="id_visible" required>'
'<input type="text" name="visible" aria-invalid="true" value="b" '
'id="id_visible" required>'
'<input type="hidden" name="hidden" value="a" id="id_hidden"></li>',
)
@ -4813,10 +4832,12 @@ class TemplateTests(SimpleTestCase):
"</label></p>"
'<ul class="errorlist"><li>This field is required.</li></ul><p>'
"<label>Password: "
'<input type="password" name="password1" required></label></p>'
'<input type="password" name="password1" aria-invalid="true" required>'
"</label></p>"
'<ul class="errorlist"><li>This field is required.</li></ul>'
"<p><label>Password (again): "
'<input type="password" name="password2" required></label></p>'
'<input type="password" name="password2" aria-invalid="true" required>'
"</label></p>"
'<input type="submit" required>'
"</form>",
)
@ -4851,7 +4872,10 @@ class TemplateTests(SimpleTestCase):
# Form gives each field an "id" attribute.
t = Template(
"<form>"
"<p>{{ form.username.label_tag }} {{ form.username }}</p>"
"<p>{{ form.username.label_tag }} {{ form.username }}"
'<span {% if form.username.id_for_label %}id="'
'{{ form.username.id_for_label }}_helptext"{% endif %}>'
"{{ form.username.help_text}}</span></p>"
"<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>"
"<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>"
'<input type="submit" required>'
@ -4861,7 +4885,8 @@ class TemplateTests(SimpleTestCase):
t.render(Context({"form": f})),
"<form>"
"<p>Username: "
'<input type="text" name="username" maxlength="10" required></p>'
'<input type="text" name="username" maxlength="10" required>'
"<span>Good luck picking a username that doesn't already exist.</span></p>"
'<p>Password1: <input type="password" name="password1" required></p>'
'<p>Password2: <input type="password" name="password2" required></p>'
'<input type="submit" required>'
@ -4873,7 +4898,9 @@ class TemplateTests(SimpleTestCase):
"<form>"
'<p><label for="id_username">Username:</label>'
'<input id="id_username" type="text" name="username" maxlength="10" '
'aria-describedby="id_username_helptext" required></p>'
'aria-describedby="id_username_helptext" required>'
'<span id="id_username_helptext">'
"Good luck picking a username that doesn't already exist.</span></p>"
'<p><label for="id_password1">Password1:</label>'
'<input type="password" name="password1" id="id_password1" required></p>'
'<p><label for="id_password2">Password2:</label>'
@ -5066,7 +5093,7 @@ class TemplateTests(SimpleTestCase):
"<li>Please make sure your passwords match.</li></ul>"
'<div>Username:<ul class="errorlist">'
"<li>Ensure this value has at most 10 characters (it has 23).</li></ul>"
'<input type="text" name="username" '
'<input type="text" name="username" aria-invalid="true" '
'value="this-is-a-long-username" maxlength="10" required></div>'
"<div>Password1:"
'<input type="password" name="password1" required></div>'
@ -5174,10 +5201,11 @@ class OverrideTests(SimpleTestCase):
'<div class="errorlist">'
'<div class="error">Enter a valid email address.</div></div>'
"<p>Email: "
'<input type="email" name="email" value="invalid" maxlength="320" required>'
'</p><div class="errorlist">'
'<input type="email" name="email" value="invalid" maxlength="320" '
'aria-invalid="true" required></p><div class="errorlist">'
'<div class="error">This field is required.</div></div>'
'<p>Comment: <input type="text" name="comment" required></p>',
'<p>Comment: <input type="text" name="comment" aria-invalid="true" '
"required></p>",
)
def test_cyclic_context_boundfield_render(self):

View File

@ -103,13 +103,16 @@ class FormsI18nTests(SimpleTestCase):
"<p><label>\xc5\xf8\xdf:</label>"
' <div id="id_somechoice">\n<div><label for="id_somechoice_0">'
'<input type="radio" id="id_somechoice_0" value="\xc5" '
'name="somechoice" required> En tied\xe4</label></div>\n'
'name="somechoice" aria-invalid="true" required>'
"En tied\xe4</label></div>\n"
'<div><label for="id_somechoice_1">'
'<input type="radio" id="id_somechoice_1" value="\xf8" '
'name="somechoice" required> Mies</label></div>\n<div>'
'name="somechoice" aria-invalid="true" required>'
"Mies</label></div>\n<div>"
'<label for="id_somechoice_2">'
'<input type="radio" id="id_somechoice_2" value="\xdf" '
'name="somechoice" required> Nainen</label></div>\n</div></p>',
'name="somechoice" aria-invalid="true" required>'
"Nainen</label></div>\n</div></p>",
)
def test_select_translated_text(self):

View File

@ -30,7 +30,7 @@ class GeoAdminTest(SimpleTestCase):
' rows="10" name="point" hidden></textarea>',
output,
)
self.assertEqual(len(cm.records), 1)
self.assertEqual(len(cm.records), 2)
self.assertEqual(
cm.records[0].getMessage(),
"Error creating geometry from value 'INVALID()' (String input "