0

In my view.py I have the following check on several consecutive pages:

if(request.META.get('HTTP_REFERER') != request.build_absolute_uri(reverse('page1'))):
            return redirect('page1')

This is performed on every page, checking that the user was redirected from the previous page, so (for example), if a user tries to enter the url for page4 in the address bar, the test will fail and he will be sent to page3, then that pages test will fail and he will fall back to page2, and so on.

Im doing this because I have several pages linked together which users must visit consecutively.

The problem comes when I want to unit test. The following test would throw an error because it fails the redirect test and therefore cannot test the logic of the page which im trying to test:

def test_user_information_updated_on_validation_success(self):
        user = User.objects.create_superuser('username')
        self.client.force_login(user)

        self.client.post(reverse('page_4'), {
            'exampleQuestion': 'exampleAnswer'
        })
        user.refresh_from_db()

        self.assertEqual(user.exampleform.somefield, 'exampleAnswer')

How can I access the page within a unit test as if it had been redirected.

Thank you.

horse
  • 479
  • 7
  • 25

1 Answers1

3

A request in the test client accepts keywords that are mapped to WSGI environment variables. Environment variables that start with HTTP and are all uppercase, with dashes mapped to underscores - are Http headers, so the short version is that we can set HTTP headers as such:

# Wrong: Generates absolute paths without hosts
self.client.post(
    reverse('page_4'), {'exampleQuestion': 'exampleAnswer'},
    HTTP_REFERER=reverse('page_3')
)

Edit: It's a little too simple, because HTTP referrers are fully qualified, so we need:


referer = 'http://testserver{}'.format(reverse('page_3'))
self.client.post(
    reverse('page_4'), {'exampleQuestion': 'exampleAnswer'},
    HTTP_REFERER=referer
)

FYI: The protocol (wsgi.scheme) and host name (HTTP_SERVER) come from djang.test.client.RequestFactory._base_environ(). If you use a modified client that changes servername and/or protocol, you should adjust accordingly. In that case it would be wise to override _base_environ in your modified test client and derive values from that.

  • Thank you. Yesterday I was trying the same thing but without the ,{} after the reverse. I tried your solution and got ```TypeError: unhashable type: 'dict'```. I just read a few articles regarding this (https://stackoverflow.com/questions/13264511/typeerror-unhashable-type-dict), and while I somewhat understand them, I cant see why this error is being thrown in this scenario or more importantly, how to fix it. If you have any more insight it would be greatly appreciated :) Thank you. – horse May 30 '20 at 09:41
  • Cause I made typos. Corrected in edit. Also, the dict can be omitted if page 3 doesn't accept keyword arguments, but has to be filled with correct keyword arguments to be able to reverse. –  May 30 '20 at 09:47
  • 1
    Updated: I wasn't taking host/scheme into account. –  May 30 '20 at 10:39
  • Thank you. That's exactly what I was after. Much appreciated – horse May 30 '20 at 10:43