From 5c62c6bc0a6f57fa77ce6f06d023c9a93caf62e9 Mon Sep 17 00:00:00 2001
From: Brandon Rodriguez <brodriguez8774@gmail.com>
Date: Sat, 4 Nov 2023 10:20:20 -0400
Subject: [PATCH] Add helper functions to find element(s) by displayed text
 value

---
 .../mixins/response_mixin.py                  |  43 ++++
 tests/test_cases/test_integration_case.py     | 185 ++++++++++++++++++
 2 files changed, 228 insertions(+)

diff --git a/django_expanded_test_cases/mixins/response_mixin.py b/django_expanded_test_cases/mixins/response_mixin.py
index a0fa01e..ca6d167 100644
--- a/django_expanded_test_cases/mixins/response_mixin.py
+++ b/django_expanded_test_cases/mixins/response_mixin.py
@@ -821,6 +821,49 @@ class ResponseTestCaseMixin(CoreTestCaseMixin):
         # Return found item.
         return element_list[0]
 
+    def find_elements_by_text(self, content, text):
+        """Finds all HTML elements that contain the provided text.
+
+        :param content: Content to search through.
+        :param text: Element text to search for.
+        """
+        # Ensure response content is in expected minimized format.
+        content = self.get_minimized_response_content(content)
+
+        # Search for all matching elements.
+        soup = BeautifulSoup(content, 'html.parser')
+        elements = soup.find_all(string=re.compile('{0}'.format(text)))
+        element_list = [self.get_minimized_response_content(element.parent) for element in elements]
+
+        # Verify one or more values were found.
+        if not len(element_list) > 0:
+            self.fail(f'Unable to find element text "{text}" in content. Provided content was:\n{content}')
+
+        # Return found values.
+        return element_list
+
+    def find_element_by_text(self, content, text):
+        """Finds first HTML element that matches the provided text.
+
+        :param content: Content to search through.
+        :param text: Element text to search for.
+        """
+        # Ensure response content is in expected minimized format.
+        content = self.get_minimized_response_content(content)
+
+        # Call parent function logic.
+        element_list = self.find_elements_by_text(content, text)
+
+        # Verify only one value was found.
+        if len(element_list) > 1:
+            self.fail(
+                f'Found multiple instances of "{text}" element text. Expected only one instance. '
+                f'Content was:\n{content}'
+            )
+
+        # Return found item.
+        return element_list[0]
+
     # endregion Html Search Functions
 
 
diff --git a/tests/test_cases/test_integration_case.py b/tests/test_cases/test_integration_case.py
index 9b3a5c0..adb748d 100644
--- a/tests/test_cases/test_integration_case.py
+++ b/tests/test_cases/test_integration_case.py
@@ -5928,6 +5928,191 @@ class IntegrationClassTest__Base(IntegrationTestCase):
                 self.find_element_by_link_text(response, 'test_link_text')
             self.assertText(err_msg, str(err.exception))
 
+    def test__find_elements_by_text__success(self):
+        """
+        Tests find_elements_by_text() function, in cases when it should succeed.
+        """
+        with self.subTest('When expected link_text is the only item, with standard element'):
+            response = HttpResponse('<p>This are words test_element_text test test test.</p>')
+
+            results = self.find_elements_by_text(response, 'test_element_text')
+            self.assertEqual(len(results), 1)
+            print('found results:')
+            print(results)
+            self.assertIn('<p>This are words test_element_text test test test.</p>', results)
+
+        with self.subTest('When expected link_text exists multiple times - Two instances'):
+            response = HttpResponse('<li>test_element_text One</li><li>test_element_text Two</li>')
+
+            # By base element tag.
+            results = self.find_elements_by_text(response, 'test_element_text')
+            self.assertEqual(len(results), 2)
+            print('found results:')
+            print(results)
+            self.assertIn('<li>test_element_text One</li>', results)
+            self.assertIn('<li>test_element_text Two</li>', results)
+
+        with self.subTest('When expected element exists multiple times - Three instances plus extra'):
+            response = HttpResponse(
+                """
+                <div>
+                    <ul>
+                        <li><a href="">test_element_text One</a></li>
+                        <li><a href="">test_element_text Two</a></li>
+                        <li><a href="">other_element_textThree</a></li>
+                    </ul>
+                    <ul>
+                        <li><a href="">test_element_text Four</a></li>
+                        <li><a href="">another_element_text Five</a></li>
+                        <li><a href="">test Six</a></li>
+                    </ul>
+                    <ul>
+                        <li><a href="test_element_text">Seven</a></li>
+                        <li><a data="test_element_text">Eight</a></li>
+                        <li><a test_element_text="">Nine</a></li>
+                    </ul>
+                </div>
+                """
+            )
+            results = self.find_elements_by_text(response, 'test_element_text')
+            self.assertEqual(len(results), 3)
+            self.assertIn('<a href="">test_element_text One</a>', results)
+            self.assertIn('<a href="">test_element_text Two</a>', results)
+            self.assertIn('<a href="">test_element_text Four</a>', results)
+
+    def test__find_elements_by_text__failure(self):
+        """
+        Tests find_elements_by_text() function, in cases when it should fail.
+        """
+        with self.subTest('When expected text is not present - Blank response'):
+            response = HttpResponse('')
+            err_msg = 'Unable to find element text "test_element_text" in content. Provided content was:\n'
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_elements_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+        with self.subTest('When expected text is not present - Single-item response'):
+            response = HttpResponse('<a href="">other_element_text</a>')
+            err_msg = (
+                'Unable to find element text "test_element_text" in content. '
+                'Provided content was:\n<a href="">other_element_text</a>'
+            )
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_elements_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+        with self.subTest('When expected text is not present - Multi-item response'):
+            response = HttpResponse(
+                """
+                <div>
+                    <h1>Page Header</h1>
+                    <a href="">other_element_text Some text.</a>
+                    <a href="">another_element_text Some more text.</a>
+                    <a href="">test Some text with the str "element_text" in it.</a>
+                </div>
+                """
+            )
+            err_msg = (
+                'Unable to find element text "test_element_text" in content. Provided content was:\n'
+                '<div>\n'
+                '<h1>Page Header</h1>\n'
+                '<a href="">other_element_text Some text.</a>\n'
+                '<a href="">another_element_text Some more text.</a>\n'
+                '<a href="">test Some text with the str "element_text" in it.</a>\n'
+                '</div>\n'
+            )
+            with self.assertRaises(AssertionError) as err:
+                self.find_elements_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+    def test__find_element_by_text__success(self):
+        """
+        Tests find_element_by_text() function, in cases when it should succeed.
+        """
+        with self.subTest('When expected element is the only item, with standard element'):
+            response = HttpResponse('<p>test_element_text</p>')
+
+            results = self.find_element_by_text(response, 'test_element_text')
+            self.assertText('<p>test_element_text</p>', results)
+
+        with self.subTest('When expected element exists plus extra'):
+            response = HttpResponse(
+                """
+                <div>
+                    <ul>
+                        <li><a href="">test_element_text One</a></li>
+                    </ul>
+                    <ul></ul>
+                </div>
+                <div>
+                    <ul></ul>
+                </div>
+                """
+            )
+            results = self.find_element_by_text(response, 'test_element_text')
+            self.assertText('<a href="">test_element_text One</a>', results)
+
+    def test__find_element_by_text__failure(self):
+        """
+        Tests find_element_by_text() function, in cases when it should fail.
+        """
+        with self.subTest('When expected text is not present - Blank response'):
+            response = HttpResponse('')
+            err_msg = 'Unable to find element text "test_element_text" in content. Provided content was:\n'
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_element_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+        with self.subTest('When expected element_text is not present - Single-item response'):
+            response = HttpResponse('<a href="">other_element_text</a>')
+            err_msg = (
+                'Unable to find element text "test_element_text" in content. '
+                'Provided content was:\n<a href="">other_element_text</a>'
+            )
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_element_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+        with self.subTest('When expected text is not present - Multi-item response'):
+            response = HttpResponse(
+                """
+                <div>
+                    <h1>Page Header</h1>
+                    <a href="">other_element_text Some text.</a>
+                    <a href="">another_element_text Some more text.</a>
+                    <a href="">test Some text with the str "element_text" in it.</a>
+                </div>
+                """
+            )
+            err_msg = (
+                'Unable to find element text "test_element_text" in content. Provided content was:\n'
+                '<div>\n'
+                '<h1>Page Header</h1>\n'
+                '<a href="">other_element_text Some text.</a>\n'
+                '<a href="">another_element_text Some more text.</a>\n'
+                '<a href="">test Some text with the str "element_text" in it.</a>\n'
+                '</div>\n'
+            )
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_element_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
+        with self.subTest('When expected element_text is present multiple times'):
+            response = HttpResponse('<a href="">test_element_text</a><a href="">test_element_text</a>')
+            err_msg = (
+                'Found multiple instances of "test_element_text" element text. Expected only one instance. Content was:\n'
+                '<a href="">test_element_text</a><a href="">test_element_text</a>'
+            )
+
+            with self.assertRaises(AssertionError) as err:
+                self.find_element_by_text(response, 'test_element_text')
+            self.assertText(err_msg, str(err.exception))
+
     # endregion Helper Function Tests
 
 
-- 
GitLab