Search code examples
djangodjango-unittest

Django testing the html of your homepage against the content of a response


If I have a test like so...

 def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        expected_html = render_to_string('home.html', request=request)
        self.assertEqual(response.content.decode(), expected_html)

As soon as I add a form in curly braces, e.g. {{ form }} The above test will fail as the .html file will not render the form only the response will. Thus causing the assertion to not match. Is there a way round this so that I can still test my html against the response?


Solution

  • You can pass a form instance to the render_to_string function:

    from django.template import RequestContext
    from django.template.loader import render_to_string
    
    form = ModelForm()
    context = RequestContext(request, {'form': form})
    expected_html = render_to_string('home.html', context)
    

    Usually what I do is splitting this kind of test into several other tests, like this:

    Using from django.test import TestCase

    def setUp(self):
        self.user = User.objects.create_user('john', '[email protected]', '123')
        self.client.login(username='john', password='123')
        self.response = self.client.get(r('home'))
    

    First test which template was used:

    def test_template(self):
        self.assertTemplateUsed(self.response, 'home.html')
    

    Test the form:

    def test_has_form(self):
        form = self.response.context['form']
        self.assertIsInstance(form, CreateModelForm)
    

    And then I test the key parts of the HTML:

    def test_html(self):
        self.assertContains(self.response, '<form')
        self.assertContains(self.response, 'type="hidden"', 1)
        self.assertContains(self.response, 'type="text"', 2)
        self.assertContains(self.response, 'type="radio"', 3)
        self.assertContains(self.response, 'type="submit"', 1)
    

    Finally if the rendered template has a csrf token:

    def test_csrf(self):
        self.assertContains(self.response, 'csrfmiddlewaretoken')