mirror of https://github.com/django/django.git
Fixed #32556 -- Fixed handling empty string as non-boolean attributes value by assertHTMLEqual().
This commit is contained in:
parent
98abf80cde
commit
41e6b2a3c5
|
@ -9,6 +9,16 @@ from django.utils.regex_helper import _lazy_re_compile
|
|||
# https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
ASCII_WHITESPACE = _lazy_re_compile(r'[\t\n\f\r ]+')
|
||||
|
||||
# https://html.spec.whatwg.org/#attributes-3
|
||||
BOOLEAN_ATTRIBUTES = {
|
||||
'allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'controls',
|
||||
'default', 'defer ', 'disabled', 'formnovalidate', 'hidden', 'ismap',
|
||||
'itemscope', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open',
|
||||
'playsinline', 'readonly', 'required', 'reversed', 'selected',
|
||||
# Attributes for deprecated tags.
|
||||
'truespeed',
|
||||
}
|
||||
|
||||
|
||||
def normalize_whitespace(string):
|
||||
return ASCII_WHITESPACE.sub(' ', string)
|
||||
|
@ -23,11 +33,14 @@ def normalize_attributes(attributes):
|
|||
value = ' '.join(sorted(
|
||||
value for value in ASCII_WHITESPACE.split(value) if value
|
||||
))
|
||||
# Attributes without a value is same as attribute with value that
|
||||
# equals the attributes name:
|
||||
# <input checked> == <input checked="checked">
|
||||
if not value or value == name:
|
||||
value = None
|
||||
# Boolean attributes without a value is same as attribute with value
|
||||
# that equals the attributes name. For example:
|
||||
# <input checked> == <input checked="checked">
|
||||
if name in BOOLEAN_ATTRIBUTES:
|
||||
if not value or value == name:
|
||||
value = None
|
||||
elif value is None:
|
||||
value = ''
|
||||
normalized.append((name, value))
|
||||
return normalized
|
||||
|
||||
|
@ -131,7 +144,7 @@ class Element:
|
|||
def __str__(self):
|
||||
output = '<%s' % self.name
|
||||
for key, value in self.attributes:
|
||||
if value:
|
||||
if value is not None:
|
||||
output += ' %s="%s"' % (key, value)
|
||||
else:
|
||||
output += ' %s' % key
|
||||
|
|
|
@ -362,6 +362,10 @@ Miscellaneous
|
|||
``EmailMessage.attach()`` with an invalid ``content`` or ``mimetype``
|
||||
arguments now raise ``ValueError`` instead of ``AssertionError``.
|
||||
|
||||
* :meth:`~django.test.SimpleTestCase.assertHTMLEqual` no longer considers a
|
||||
non-boolean attribute without a value equal to an attribute with the same
|
||||
name and value.
|
||||
|
||||
.. _deprecated-features-4.0:
|
||||
|
||||
Features deprecated in 4.0
|
||||
|
|
|
@ -1596,8 +1596,8 @@ your test suite.
|
|||
closed or the HTML document ends.
|
||||
* Empty tags are equivalent to their self-closing version.
|
||||
* The ordering of attributes of an HTML element is not significant.
|
||||
* Attributes without an argument are equal to attributes that equal in
|
||||
name and value (see the examples).
|
||||
* Boolean attributes (like ``checked``) without an argument are equal to
|
||||
attributes that equal in name and value (see the examples).
|
||||
* Text, character references, and entity references that refer to the same
|
||||
character are equivalent.
|
||||
|
||||
|
@ -1620,6 +1620,12 @@ your test suite.
|
|||
|
||||
Output in case of error can be customized with the ``msg`` argument.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
In older versions, any attribute (not only boolean attributes) without
|
||||
a value was considered equal to an attribute with the same name and
|
||||
value.
|
||||
|
||||
.. method:: SimpleTestCase.assertHTMLNotEqual(html1, html2, msg=None)
|
||||
|
||||
Asserts that the strings ``html1`` and ``html2`` are *not* equal. The
|
||||
|
|
|
@ -715,10 +715,25 @@ class HTMLEqualTests(SimpleTestCase):
|
|||
self.assertHTMLEqual(html1, html2)
|
||||
|
||||
def test_boolean_attribute(self):
|
||||
html1 = '<input attr>'
|
||||
html2 = '<input attr="">'
|
||||
html1 = '<input checked>'
|
||||
html2 = '<input checked="">'
|
||||
html3 = '<input checked="checked">'
|
||||
self.assertHTMLEqual(html1, html2)
|
||||
self.assertEqual(parse_html(html1), parse_html(html2))
|
||||
self.assertHTMLEqual(html1, html3)
|
||||
self.assertHTMLEqual(html2, html3)
|
||||
self.assertHTMLNotEqual(html1, '<input checked="invalid">')
|
||||
self.assertEqual(str(parse_html(html1)), '<input checked>')
|
||||
self.assertEqual(str(parse_html(html2)), '<input checked>')
|
||||
self.assertEqual(str(parse_html(html3)), '<input checked>')
|
||||
|
||||
def test_non_boolean_attibutes(self):
|
||||
html1 = '<input value>'
|
||||
html2 = '<input value="">'
|
||||
html3 = '<input value="value">'
|
||||
self.assertHTMLEqual(html1, html2)
|
||||
self.assertHTMLNotEqual(html1, html3)
|
||||
self.assertEqual(str(parse_html(html1)), '<input value="">')
|
||||
self.assertEqual(str(parse_html(html2)), '<input value="">')
|
||||
|
||||
def test_normalize_refs(self):
|
||||
pairs = [
|
||||
|
|
Loading…
Reference in New Issue