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())
Cookies are saved in a session. So
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
).