Testing a Wagtail language switch with Factory Boy

In this tutorial we will test a language switch that keeps the user on the same page and is able to handle Wagtail pages as well as pages outside of the Wagtail tree.

July 15, 2020, 1:27 p.m.
Themes: Multiple languages Testing

We have developed such a language switch in an earlier tutorial. To test it we need to have a site with some pages in it. In another tutorial we have set up a small framework for this, using Factory Boy. We reuse this to set up our test data in a file /tests/test_languages.py:

from .factories import HomePageFactory, ArticlePageFactory, ArticleIndexPageFactory
from django.conf import settings
from django.test import TestCase, RequestFactory, Client
from wagtail.core.models import Page, Site
from wagtailtrans.models import Language, TranslatablePage

class TestChangeLanguageViews(TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.client = Client()
        cls.factory = RequestFactory()
        cls.site = Site.objects.create(is_default_site=True, root_page=Page.get_first_root_node())
        cls.homepage = HomePageFactory()
        cls.articleindexpage = ArticleIndexPageFactory(parent=cls.homepage)
        cls.articlepage1 = ArticlePageFactory(parent=cls.articleindexpage)
        cls.foreign_language_code = [code for code, lang in settings.LANGUAGES if code != settings.LANGUAGE_CODE][0]
        # note: Wagtailtrans automatically creates a language tree for every language that is defined
        cls.foreign_language = Language.objects.get_or_create(code=cls.foreign_language_code)[0]
        cls.foreign_articlepage1 = TranslatablePage.objects.get(language=cls.foreign_language,
                                                              canonical_page=cls.articlepage1)

We need the client and the request factory from Django for our tests. The Page instances homepage, articleindexpage and articlepage1 are created in the same way as in the earlier tutorial. We have also seen the foreign language code and the foreign version of the article page in the testing of our menu. Time for our first test: check whether the view set_language_from_url correctly brings us to the home page in the requested language when there is no previous page given. We use the Django test client to get a response from the url of our view:

from django.urls import reverse

def test_change_language_without_previous_page(self):
    response = self.client.get(
        reverse('set_language_from_url', kwargs={'language_code': self.foreign_language_code}))
    expected_url = '/' + self.foreign_language_code + '/'
    self.assertEquals(response.url, expected_url)

Running the test is done with:

python3 manage.py test cms.tests.test_languages

If the previous page has a url outside of the Wagtail tree, such as /accounts/login/, the function set_language_from_url should bring us to the translated version of this:

from django.utils import translation

def test_change_language_of_login_url(self):
    # get the url from the get_language_from_url view and make a request object
    url = reverse('set_language_from_url', kwargs={'language_code': self.foreign_language_code})
    request = self.factory.get(url)

    # manually set the HTTP_REFERER value to login url  
    request.META['HTTP_REFERER'] = '/' + settings.LANGUAGE_CODE + '/accounts/login/'
    translation.activate(settings.LANGUAGE_CODE)
    response = set_language_from_url(request, self.foreign_language_code)
    expected_url = '/' + self.foreign_language_code + '/accounts/login/'
    self.assertEquals(response.url, expected_url)

We need a request object, because we need to add the HTTP_REFERER information to it, so therefore we use the Django request factory. We simulate that the previous page is in the default language and activate that language, and then call our function. We expect our function to translate the url with the prefix of the foreign language. Running the test tells us if everything works out as expected.

Finally we test whether set_language_from_url does the same when the referring page is part of the Wagtail tree, namely articlepage1. The sequence is the same: define the url and the request, add the referring page to it, set the language and call the function to see if it does the translation right:

def test_change_language_from_canonical_page(self):
    # get the url, make a request object and set the HTTP_REFERER
    url = reverse('set_language_from_url', kwargs={'language_code': self.foreign_language_code})
    request = self.factory.get(url)
    request.META['HTTP_REFERER'] = str(self.articlepage1.url)
    translation.activate(settings.LANGUAGE_CODE)
    response = set_language_from_url(request, self.foreign_language_code)
    self.assertEqual(response.url, self.foreign_articlepage1.url)

Check our code coverage:

coverage run --source=cms manage.py test cms

Our views.py is covered well enough. On to testing our commenting functionality and our streamforms.

Comment on this article (sign in first or confirm by name and email below)