django-webtest: How to test remember-me login/expire-on-browser-close cookies?

758 Views Asked by At

How do you test login-remember-me functionality with webtest-django? In other words, how do you use webtest to test things that involve expire-on-browser-exit cookies? I have the below draft, but it's not working. It seems that the server must be setup and torn down (as in the snippet below my testing class), but I'm not understanding how to integrate it. There does not seem to be much information out there on using StopableWSGIServer in this way.

Finally, I'm not even sure if this functionality is going to work at all in production, as it is my understanding that the major browsers ignore expire-cookie-on-browser-exit requests. Is that correct? It would be nice to see some references regarding it.

Doc top, imports, and class top:

"""
Tests for the remember-me functionality on the login page.

DEPENDS ON TEST:     test__utilities.py
DEPENDED ON BY TEST: None

To run the tests in this file:
    1. source /home/jeffy/django_files/djauth_lifecycle_tutorial/part_05/dalt05_venv/bin/activate
    2. cd /home/jeffy/django_files/djauth_lifecycle_tutorial/part_05/djauth_root/
    3. python -Wall manage.py test auth_lifecycle.registration.test_login_remember_me.py

See the top of <link to .test__utilities> for more information.
"""
from auth_lifecycle.test__utilities import UserFactory, TEST_PASSWORD
from django.core.urlresolvers       import reverse
from django_webtest                 import WebTest
from webtest                        import http
from webtest.debugapp               import debug_app
from webtest.http                   import StopableWSGIServer
import os
import time

class TestLoginRememberMeFunctionality(WebTest):
    """Tests for authentication related views."""
    def setUp(self):
        self.user = UserFactory()

Don't remember test:

    def test_login_dont_remember(self):
        """
        Log a user in with the remember-me checkbox unchecked. This takes
        you to the main page. Because they're logged in, the main page
        contains a link to their profile page. Restart the browser, and
        the session should be expired. Therefore, instead of a link to the
        profile, there should be a link to login.
        """

        #Log a user in with the remember-me checkbox unchecked.
        form = self.app.get(reverse('login')).form
        form['username'] = self.user.username
        form['password'] = TEST_PASSWORD
        form['remember'] = 'unchecked'
        response_main_page = form.submit().follow()

        #This takes you to the main page.
        self.assertEqual(response_main_page.context['user'].username,
                         self.user.username)

        #Because they're logged in, the main page contains a link to their
        #profile page.
        self.assertIn(reverse('user_profile'), str(response_main_page.content))

        #Restart the browser,
        http.StopableWSGIServer.shutdown()
        time.sleep(2)   #Two seconds
        http.StopableWSGIServer.run()

        #and the session should be expired.
        self.assertFalse(
            response_login_page.context['user'].is_authenticated())

        #Therefore, instead of a link to the profile, there should be a
        #link to login.
        response_main_page = self.app.get(reverse('main_page'))
        assert reverse('login') in response_main_page

Remember test:

    def test_login_dont_remember(self):
        """
        Log a user in with the remember-me checkbox checked. This takes
        you to the main page. Because they're logged in, the main page
        contains a link to their profile page. Restart the browser, and
        the session should still be active. Therefore, the link to their
        profile should still be there.
        """

        #Log a user in with the remember-me checkbox checked.
        form = self.app.get(reverse('login')).form
        form['username'] = self.user.username
        form['password'] = TEST_PASSWORD
        form['remember'] = 'checked'
        response_main_page = form.submit().follow()

        #This takes you to the main page.
        self.assertEqual(response_main_page.context['user'].username,
                         self.user.username)

        #Because they're logged in, the main page contains a link to their
        #profile page.
        user_prfl_url = reverse('user_profile')
        self.assertIn(user_prfl_url, str(response_main_page.content))

        #Restart the browser,
        http.StopableWSGIServer.shutdown()
        time.sleep(2)   #Two seconds
        http.StopableWSGIServer.run()

        #and the session should still be active.
        self.assertFalse(
            response_login_page.context['user'].is_authenticated())

        #Therefore, the link to their profile should still be there.
        response_main_page = self.app.get(reverse('main_page'))
        assert user_prfl_url in response_main_page

Here is the snippet, but it's not clear to me how to use this in the test itself.

import os
from webtest import http
from webtest.debugapp import debug_app


def setup_test(test):
    server = http.StopableWSGIServer.create(debug_app)
    server.wait()
    path_to_html_file = os.path.join('tests', 'test.html')
    test.globs.update(
        server=server,
        your_url=server.application_url.rstrip('/') + '/form.html',
        path_to_html_file=path_to_html_file,
    )
setup_test.__test__ = False


def teardown_test(test):
    test.globs['server'].shutdown()
teardown_test.__test__ = False

FYI: Here is a fully-working test for a login page, ignoring the remember-me functionality. It's what I based the above on:

"""
Tests for authentication related views.

DEPENDS ON TEST:     test__utilities.py
DEPENDED ON BY TEST: None

To run the tests in this file:
    1. source /home/myname/django_files/django_auth_lifecycle/djauth_venv/bin/activate
    2. cd /home/myname/django_files/django_auth_lifecycle/djauth_root/
    3. python -Wall manage.py test auth_lifecycle.registration.test_login_basic

See the top of <link to .test__utilities> for more information.
"""
from auth_lifecycle.test__utilities import UserFactory, TEST_PASSWORD
from django.core.urlresolvers       import reverse
from django_webtest                 import WebTest

class AuthTest(WebTest):
    """Tests for authentication related views."""
    def setUp(self):
        self.user = UserFactory()

Test function top:

    def test_login(self):
        """
        Log a user in, which takes you to the main page. Because they're
        logged in, the main page contains a link to their profile page. Go
        to it. The profile page contains their email address and a link to
        logout. Click that link, which expires the session and takes you
        back to the login page.
        """

        #The following warning is given even before the test database is
        #created:
        #
        #/home/myname/django_files/django_auth_lifecycle/djauth_venv/lib/python3.4/site-packages/bs4/builder/_htmlparser.py:157:
        #DeprecationWarning: The value of convert_charrefs will become True in 3.5. You are encouraged to set the value explicitly.
        #
        #It is also given repeatedly during the test. I therefore believe
        #it is unrelated to our code.

Test function main section:

        #Log a user in,
        form = self.app.get(reverse('login')).form
        form['username'] = self.user.username
        form['password'] = TEST_PASSWORD
        response_main_page = form.submit().follow()

        #which takes you to the main page.
        self.assertEqual(response_main_page.context['user'].username,
                         self.user.username)

        #Because they're logged in, the main page contains a link to their
        #profile page.
        user_prfl_url = reverse('user_profile')
        self.assertIn(user_prfl_url, str(response_main_page.content))

        #Go to it. The profile page contains their email address
        response_profile_page = response_main_page.click(href=user_prfl_url)
        assert self.user.email in response_profile_page

        #and a link to logout
        logout_url = reverse('logout_then_login')
        self.assertIn(logout_url, str(response_profile_page.content))

        #Click that link, which expires the session and takes you back to
        #the login page.
        response_login_page = response_profile_page.click(href=logout_url).follow()
        self.assertIn('value="login"', str(response_login_page.content))

        self.assertFalse(
            response_login_page.context['user'].is_authenticated())
1

There are 1 best solutions below

0
On

Cookies are saved in a session. So

self.app.set_user(user=None)
self.app.reset()

should unset the user and clear the client session (includes cookies). This way you can simulate a browser restart.

http.StopableWSGIServer.shutdown() stops I think the server side (wsgi=server-app connection).