summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChinmoy Chakraborty <chinmoy12c@gmail.com>2023-10-02 23:16:21 +0530
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-10-03 10:44:36 +0200
commit1dae65dc63ae84be5002c37b4ddae0b9220e8808 (patch)
tree7f541e24d9b7816e8f6edf6fcb5a676ffb56d345
parent54d9d26ebfc90711430a79219d6547141ce1717f (diff)
Fixed #34657 -- Made assert(Not)Contains/assertInHTML display haystacks in error messages.
-rw-r--r--django/test/testcases.py41
-rw-r--r--docs/releases/5.1.txt5
-rw-r--r--docs/topics/testing/tools.txt12
-rw-r--r--tests/test_client_regress/tests.py83
-rw-r--r--tests/test_utils/tests.py47
5 files changed, 157 insertions, 31 deletions
diff --git a/django/test/testcases.py b/django/test/testcases.py
index bdb64b3a15..9855c318be 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -495,6 +495,7 @@ class SimpleTestCase(unittest.TestCase):
content = b"".join(response.streaming_content)
else:
content = response.content
+ content_repr = safe_repr(content)
if not isinstance(text, bytes) or html:
text = str(text)
content = content.decode(response.charset)
@@ -509,7 +510,7 @@ class SimpleTestCase(unittest.TestCase):
self, text, None, "Second argument is not valid HTML:"
)
real_count = content.count(text)
- return (text_repr, real_count, msg_prefix)
+ return text_repr, real_count, msg_prefix, content_repr
def assertContains(
self, response, text, count=None, status_code=200, msg_prefix="", html=False
@@ -521,7 +522,7 @@ class SimpleTestCase(unittest.TestCase):
If ``count`` is None, the count doesn't matter - the assertion is true
if the text occurs at least once in the response.
"""
- text_repr, real_count, msg_prefix = self._assert_contains(
+ text_repr, real_count, msg_prefix, content_repr = self._assert_contains(
response, text, status_code, msg_prefix, html
)
@@ -529,13 +530,18 @@ class SimpleTestCase(unittest.TestCase):
self.assertEqual(
real_count,
count,
- msg_prefix
- + "Found %d instances of %s in response (expected %d)"
- % (real_count, text_repr, count),
+ (
+ f"{msg_prefix}Found {real_count} instances of {text_repr} "
+ f"(expected {count}) in the following response\n{content_repr}"
+ ),
)
else:
self.assertTrue(
- real_count != 0, msg_prefix + "Couldn't find %s in response" % text_repr
+ real_count != 0,
+ (
+ f"{msg_prefix}Couldn't find {text_repr} in the following response\n"
+ f"{content_repr}"
+ ),
)
def assertNotContains(
@@ -546,12 +552,17 @@ class SimpleTestCase(unittest.TestCase):
successfully, (i.e., the HTTP status code was as expected) and that
``text`` doesn't occur in the content of the response.
"""
- text_repr, real_count, msg_prefix = self._assert_contains(
+ text_repr, real_count, msg_prefix, content_repr = self._assert_contains(
response, text, status_code, msg_prefix, html
)
self.assertEqual(
- real_count, 0, msg_prefix + "Response should not contain %s" % text_repr
+ real_count,
+ 0,
+ (
+ f"{msg_prefix}{text_repr} unexpectedly found in the following response"
+ f"\n{content_repr}"
+ ),
)
def _check_test_client_response(self, response, attribute, method_name):
@@ -884,17 +895,23 @@ class SimpleTestCase(unittest.TestCase):
real_count = parsed_haystack.count(parsed_needle)
if msg_prefix:
msg_prefix += ": "
+ haystack_repr = safe_repr(haystack)
if count is not None:
self.assertEqual(
real_count,
count,
- msg_prefix
- + "Found %d instances of '%s' in response (expected %d)"
- % (real_count, needle, count),
+ (
+ f"{msg_prefix}Found {real_count} instances of {needle!r} (expected "
+ f"{count}) in the following response\n{haystack_repr}"
+ ),
)
else:
self.assertTrue(
- real_count != 0, msg_prefix + "Couldn't find '%s' in response" % needle
+ real_count != 0,
+ (
+ f"{msg_prefix}Couldn't find {needle!r} in the following response\n"
+ f"{haystack_repr}"
+ ),
)
def assertJSONEqual(self, raw, expected_data, msg=None):
diff --git a/docs/releases/5.1.txt b/docs/releases/5.1.txt
index a8f0c32f9b..aa8fe80aac 100644
--- a/docs/releases/5.1.txt
+++ b/docs/releases/5.1.txt
@@ -201,7 +201,10 @@ Templates
Tests
~~~~~
-* ...
+* :meth:`~django.test.SimpleTestCase.assertContains`,
+ :meth:`~django.test.SimpleTestCase.assertNotContains`, and
+ :meth:`~django.test.SimpleTestCase.assertInHTML` assertions now add haystacks
+ to assertion error messages.
URLs
~~~~
diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt
index 16cc7759b3..a171941a85 100644
--- a/docs/topics/testing/tools.txt
+++ b/docs/topics/testing/tools.txt
@@ -1700,6 +1700,10 @@ your test suite.
attribute ordering is not significant. See
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
+ .. versionchanged:: 5.1
+
+ In older versions, error messages didn't contain the response content.
+
.. method:: SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False)
Asserts that a :class:`response <django.http.HttpResponse>` produced the
@@ -1712,6 +1716,10 @@ your test suite.
attribute ordering is not significant. See
:meth:`~SimpleTestCase.assertHTMLEqual` for more details.
+ .. versionchanged:: 5.1
+
+ In older versions, error messages didn't contain the response content.
+
.. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='', count=None)
Asserts that the template with the given name was used in rendering the
@@ -1848,6 +1856,10 @@ your test suite.
Whitespace in most cases is ignored, and attribute ordering is not
significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details.
+ .. versionchanged:: 5.1
+
+ In older versions, error messages didn't contain the ``haystack``.
+
.. method:: SimpleTestCase.assertJSONEqual(raw, expected_data, msg=None)
Asserts that the JSON fragments ``raw`` and ``expected_data`` are equal.
diff --git a/tests/test_client_regress/tests.py b/tests/test_client_regress/tests.py
index 726d1dcf8f..d5b9807f4d 100644
--- a/tests/test_client_regress/tests.py
+++ b/tests/test_client_regress/tests.py
@@ -80,86 +80,141 @@ class AssertContainsTests(SimpleTestCase):
try:
self.assertNotContains(response, "once")
except AssertionError as e:
- self.assertIn("Response should not contain 'once'", str(e))
+ self.assertIn(
+ "'once' unexpectedly found in the following response\n"
+ f"{response.content}",
+ str(e),
+ )
try:
self.assertNotContains(response, "once", msg_prefix="abc")
except AssertionError as e:
- self.assertIn("abc: Response should not contain 'once'", str(e))
+ self.assertIn(
+ "abc: 'once' unexpectedly found in the following response\n"
+ f"{response.content}",
+ str(e),
+ )
try:
self.assertContains(response, "never", 1)
except AssertionError as e:
self.assertIn(
- "Found 0 instances of 'never' in response (expected 1)", str(e)
+ "Found 0 instances of 'never' (expected 1) in the following response\n"
+ f"{response.content}",
+ str(e),
)
try:
self.assertContains(response, "never", 1, msg_prefix="abc")
except AssertionError as e:
self.assertIn(
- "abc: Found 0 instances of 'never' in response (expected 1)", str(e)
+ "abc: Found 0 instances of 'never' (expected 1) in the following "
+ f"response\n{response.content}",
+ str(e),
)
try:
self.assertContains(response, "once", 0)
except AssertionError as e:
self.assertIn(
- "Found 1 instances of 'once' in response (expected 0)", str(e)
+ "Found 1 instances of 'once' (expected 0) in the following response\n"
+ f"{response.content}",
+ str(e),
)
try:
self.assertContains(response, "once", 0, msg_prefix="abc")
except AssertionError as e:
self.assertIn(
- "abc: Found 1 instances of 'once' in response (expected 0)", str(e)
+ "abc: Found 1 instances of 'once' (expected 0) in the following "
+ f"response\n{response.content}",
+ str(e),
)
try:
self.assertContains(response, "once", 2)
except AssertionError as e:
self.assertIn(
- "Found 1 instances of 'once' in response (expected 2)", str(e)
+ "Found 1 instances of 'once' (expected 2) in the following response\n"
+ f"{response.content}",
+ str(e),
)
try:
self.assertContains(response, "once", 2, msg_prefix="abc")
except AssertionError as e:
self.assertIn(
- "abc: Found 1 instances of 'once' in response (expected 2)", str(e)
+ "abc: Found 1 instances of 'once' (expected 2) in the following "
+ f"response\n{response.content}",
+ str(e),
)
try:
self.assertContains(response, "twice", 1)
except AssertionError as e:
self.assertIn(
- "Found 2 instances of 'twice' in response (expected 1)", str(e)
+ "Found 2 instances of 'twice' (expected 1) in the following response\n"
+ f"{response.content}",
+ str(e),
)
try:
self.assertContains(response, "twice", 1, msg_prefix="abc")
except AssertionError as e:
self.assertIn(
- "abc: Found 2 instances of 'twice' in response (expected 1)", str(e)
+ "abc: Found 2 instances of 'twice' (expected 1) in the following "
+ f"response\n{response.content}",
+ str(e),
)
try:
self.assertContains(response, "thrice")
except AssertionError as e:
- self.assertIn("Couldn't find 'thrice' in response", str(e))
+ self.assertIn(
+ f"Couldn't find 'thrice' in the following response\n{response.content}",
+ str(e),
+ )
try:
self.assertContains(response, "thrice", msg_prefix="abc")
except AssertionError as e:
- self.assertIn("abc: Couldn't find 'thrice' in response", str(e))
+ self.assertIn(
+ "abc: Couldn't find 'thrice' in the following response\n"
+ f"{response.content}",
+ str(e),
+ )
try:
self.assertContains(response, "thrice", 3)
except AssertionError as e:
self.assertIn(
- "Found 0 instances of 'thrice' in response (expected 3)", str(e)
+ "Found 0 instances of 'thrice' (expected 3) in the following response\n"
+ f"{response.content}",
+ str(e),
)
try:
self.assertContains(response, "thrice", 3, msg_prefix="abc")
except AssertionError as e:
self.assertIn(
- "abc: Found 0 instances of 'thrice' in response (expected 3)", str(e)
+ "abc: Found 0 instances of 'thrice' (expected 3) in the following "
+ f"response\n{response.content}",
+ str(e),
)
+ long_content = (
+ b"This is a very very very very very very very very long message which "
+ b"exceedes the max limit of truncation."
+ )
+ response = HttpResponse(long_content)
+ msg = f"Couldn't find 'thrice' in the following response\n{long_content}"
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertContains(response, "thrice")
+
+ msg = (
+ "Found 1 instances of 'This' (expected 3) in the following response\n"
+ f"{long_content}"
+ )
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertContains(response, "This", 3)
+
+ msg = f"'very' unexpectedly found in the following response\n{long_content}"
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertNotContains(response, "very")
+
def test_unicode_contains(self):
"Unicode characters can be found in template context"
# Regression test for #10183
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index 95526f768f..7df81650d5 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -985,12 +985,18 @@ class HTMLEqualTests(SimpleTestCase):
class InHTMLTests(SimpleTestCase):
def test_needle_msg(self):
- msg = "False is not true : Couldn't find '<b>Hello</b>' in response"
+ msg = (
+ "False is not true : Couldn't find '<b>Hello</b>' in the following "
+ "response\n'<p>Test</p>'"
+ )
with self.assertRaisesMessage(AssertionError, msg):
self.assertInHTML("<b>Hello</b>", "<p>Test</p>")
def test_msg_prefix(self):
- msg = "False is not true : Prefix: Couldn't find '<b>Hello</b>' in response"
+ msg = (
+ "False is not true : Prefix: Couldn't find '<b>Hello</b>' in the following "
+ 'response\n\'<input type="text" name="Hello" />\''
+ )
with self.assertRaisesMessage(AssertionError, msg):
self.assertInHTML(
"<b>Hello</b>",
@@ -1000,8 +1006,9 @@ class InHTMLTests(SimpleTestCase):
def test_count_msg_prefix(self):
msg = (
- "2 != 1 : Prefix: Found 2 instances of '<b>Hello</b>' in response "
- "(expected 1)"
+ "2 != 1 : Prefix: Found 2 instances of '<b>Hello</b>' (expected 1) in the "
+ "following response\n'<b>Hello</b><b>Hello</b>'"
+ ""
)
with self.assertRaisesMessage(AssertionError, msg):
self.assertInHTML(
@@ -1011,6 +1018,38 @@ class InHTMLTests(SimpleTestCase):
msg_prefix="Prefix",
)
+ def test_base(self):
+ haystack = "<p><b>Hello</b> <span>there</span>! Hi <span>there</span>!</p>"
+
+ self.assertInHTML("<b>Hello</b>", haystack=haystack)
+ msg = f"Couldn't find '<p>Howdy</p>' in the following response\n{haystack!r}"
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertInHTML("<p>Howdy</p>", haystack)
+
+ self.assertInHTML("<span>there</span>", haystack=haystack, count=2)
+ msg = (
+ "Found 1 instances of '<b>Hello</b>' (expected 2) in the following response"
+ f"\n{haystack!r}"
+ )
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertInHTML("<b>Hello</b>", haystack=haystack, count=2)
+
+ def test_long_haystack(self):
+ haystack = (
+ "<p>This is a very very very very very very very very long message which "
+ "exceedes the max limit of truncation.</p>"
+ )
+ msg = f"Couldn't find '<b>Hello</b>' in the following response\n{haystack!r}"
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertInHTML("<b>Hello</b>", haystack)
+
+ msg = (
+ "Found 0 instances of '<b>This</b>' (expected 3) in the following response"
+ f"\n{haystack!r}"
+ )
+ with self.assertRaisesMessage(AssertionError, msg):
+ self.assertInHTML("<b>This</b>", haystack, 3)
+
class JSONEqualTests(SimpleTestCase):
def test_simple_equal(self):