Skip to content

Commit

Permalink
Add BS4SoupClient wrapper to ease html testing
Browse files Browse the repository at this point in the history
This wrapper allows for easy checking of the html responses by Django's
Test client. CSS-like selectors can be used to check for the presence of
certain html attributes.

No longer shall we resort to regexes.
  • Loading branch information
Stormheg committed Jul 27, 2023
1 parent dec8ec4 commit 5c481d1
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions wagtail/test/utils/wagtail_tests.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,54 @@
import warnings
from contextlib import contextmanager

from bs4 import BeautifulSoup
from django import VERSION as DJANGO_VERSION
from django.contrib.auth import get_user_model
from django.test.client import Client as DjangoTestClient
from django.test.testcases import assert_and_parse_html
from django.utils.functional import SimpleLazyObject


class BS4SoupClient(DjangoTestClient):
"""Convenience wrapper around Django's Client and BeautifulSoup's SoupSieve
The intend of this wrapper is to make it easier to check the html of a response.
Usage example:
client = BS4SoupClient()
response = client.get("/good-vibes/")
# Select a HTML <span class="good-vibes> in the response
good_vibes = response.select("span.good-vibes")
# Assert the is only one element on the page that matches the selector
self.assertEqual(len(soup), 1)
"""

def _get_soup(self, response):
content_type = response.headers.get("Content-Type", None)
if "text/html" in content_type:
return BeautifulSoup(response.content, "html5lib")
raise ValueError(
"Cannot use BeatifulSoup, the response content type is not HTML"
)

def request(self, **request):
response = super().request(**request)
# Make the soup available lazily. We will only incur the cost of instantiating
# the soup upon the initial access of this attribute.
response.soup = SimpleLazyObject(lambda: self._get_soup(response))

# Alias these BeautifulSoup functions the the response for convenience
response.select = lambda selector: response.soup.select(selector)
response.select_one = lambda selector: response.soup.select_one(selector)
return response


class WagtailTestUtils:
client_class = BS4SoupClient

@staticmethod
def create_test_user():
"""
Expand Down

0 comments on commit 5c481d1

Please sign in to comment.