Commit 3af9943d by Will Daly

Bugfix for ECOM-199: Visitors removed from auto-enroll pool if they need to…

Bugfix for ECOM-199: Visitors removed from auto-enroll pool if they need to authenticate while attempting to enroll
Sets a session variable as soon as a user enters the experimental condition to ensure that they stay in that condition,
even if they later access the control URL (e.g. from a redirect on the login page)
parent 9a554ec3
...@@ -29,12 +29,16 @@ class EnrollmentTest(ModuleStoreTestCase): ...@@ -29,12 +29,16 @@ class EnrollmentTest(ModuleStoreTestCase):
""" """
Test student enrollment, especially with different course modes. Test student enrollment, especially with different course modes.
""" """
USERNAME = "Bob"
EMAIL = "bob@example.com"
PASSWORD = "edx"
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """ Create a course and user, then log in. """
super(EnrollmentTest, self).setUp() super(EnrollmentTest, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx") self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
self.client.login(username=self.user.username, password="edx") self.client.login(username=self.USERNAME, password=self.PASSWORD)
self.urls = [ self.urls = [
reverse('course_modes_choose', kwargs={'course_id': unicode(self.course.id)}) reverse('course_modes_choose', kwargs={'course_id': unicode(self.course.id)})
...@@ -107,6 +111,50 @@ class EnrollmentTest(ModuleStoreTestCase): ...@@ -107,6 +111,50 @@ class EnrollmentTest(ModuleStoreTestCase):
self.assertTrue(is_active) self.assertTrue(is_active)
self.assertEqual(course_mode, enrollment_mode) self.assertEqual(course_mode, enrollment_mode)
# TODO (ECOM-16): Remove once the auto-registration A/B test completes.
def test_enroll_from_redirect_autoreg(self):
# Bugfix (ECOM-199): Visitors removed from auto-enroll pool
# if they need to authenticate while attempting to enroll.
# If a user is (a) in the experimental condition of the A/B test (autoreg enabled)
# and (b) is not logged in when registering for a course, then
# the user will be redirected to the "control" URL (change_enrollment)
# instead of the experimental URL (change_enrollment_autoreg)
# We work around this by setting a flag in the session, such that
# if a user is *ever* in the experimental condition, they remain
# in the experimental condition.
for mode_slug in ['honor', 'audit', 'verified']:
CourseModeFactory.create(
course_id=self.course.id,
mode_slug=mode_slug,
mode_display_name=mode_slug,
expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1)
)
# Log out, so we're no longer authenticated
self.client.logout()
# Visit the experimental condition URL
resp = self._change_enrollment('enroll', auto_reg=True)
# Expect that we're denied (since we're not authenticated)
# and instead are redirected to the login page
self.assertEqual(resp.status_code, 403)
# Log the user in
self.client.login(username=self.USERNAME, password=self.PASSWORD)
# Go to the control URL
# This simulates what the JavaScript client does after getting a 403 response
# from the register button.
resp = self._change_enrollment('enroll')
# Expect that we're auto-enrolled (even though we used the control URL the second time)
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
# Expect that the auto register flag is still set in the user's session
self.assertIn('auto_register', self.client.session)
self.assertTrue(self.client.session['auto_register'])
def test_unenroll(self): def test_unenroll(self):
# Enroll the student in the course # Enroll the student in the course
CourseEnrollment.enroll(self.user, self.course.id, mode="honor") CourseEnrollment.enroll(self.user, self.course.id, mode="honor")
......
...@@ -15,6 +15,7 @@ from django.test.utils import override_settings ...@@ -15,6 +15,7 @@ from django.test.utils import override_settings
from django.test.client import RequestFactory, Client from django.test.client import RequestFactory, Client
from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth.models import User, AnonymousUser
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.sessions.middleware import SessionMiddleware
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
...@@ -634,8 +635,17 @@ class PaidRegistrationTest(ModuleStoreTestCase): ...@@ -634,8 +635,17 @@ class PaidRegistrationTest(ModuleStoreTestCase):
@unittest.skipUnless(settings.FEATURES.get('ENABLE_SHOPPING_CART'), "Shopping Cart not enabled in settings") @unittest.skipUnless(settings.FEATURES.get('ENABLE_SHOPPING_CART'), "Shopping Cart not enabled in settings")
def test_change_enrollment_add_to_cart(self): def test_change_enrollment_add_to_cart(self):
request = self.req_factory.post(reverse('change_enrollment'), {'course_id': self.course.id.to_deprecated_string(), request = self.req_factory.post(
'enrollment_action': 'add_to_cart'}) reverse('change_enrollment'), {
'course_id': self.course.id.to_deprecated_string(),
'enrollment_action': 'add_to_cart'
}
)
# Add a session to the request
SessionMiddleware().process_request(request)
request.session.save()
request.user = self.user request.user = self.user
response = change_enrollment(request) response = change_enrollment(request)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
......
...@@ -619,6 +619,17 @@ def change_enrollment(request, auto_register=False): ...@@ -619,6 +619,17 @@ def change_enrollment(request, auto_register=False):
Response Response
""" """
# TODO (ECOM-16): Remove this once the auto-registration A/B test completes
# If a user is in the experimental condition (auto-registration enabled),
# immediately set a session flag so they stay in the experimental condition.
# We keep them in the experimental condition even if later on the user
# tries to register using the control URL (e.g. because of a redirect from the login page,
# which is hard-coded to use the control URL).
if auto_register:
request.session['auto_register'] = True
if request.session.get('auto_register') and not auto_register:
auto_register = True
user = request.user user = request.user
action = request.POST.get("enrollment_action") action = request.POST.get("enrollment_action")
...@@ -664,11 +675,6 @@ def change_enrollment(request, auto_register=False): ...@@ -664,11 +675,6 @@ def change_enrollment(request, auto_register=False):
# TODO (ECOM-16): Once the auto-registration AB-test is complete, delete # TODO (ECOM-16): Once the auto-registration AB-test is complete, delete
# one of these two conditions and remove the `auto_register` flag. # one of these two conditions and remove the `auto_register` flag.
if auto_register: if auto_register:
# TODO (ECOM-16): This stores a flag in the session so downstream
# views will recognize that the user is in the "auto-registration"
# experimental condition. We can remove this once the AB test completes.
request.session['auto_register'] = True
available_modes = CourseMode.modes_for_course_dict(course_id) available_modes = CourseMode.modes_for_course_dict(course_id)
# Handle professional ed as a special case. # Handle professional ed as a special case.
...@@ -703,12 +709,6 @@ def change_enrollment(request, auto_register=False): ...@@ -703,12 +709,6 @@ def change_enrollment(request, auto_register=False):
# before sending them to the "choose your track" page. # before sending them to the "choose your track" page.
# This is the control for the auto-registration AB-test. # This is the control for the auto-registration AB-test.
else: else:
# TODO (ECOM-16): If the user is NOT in the experimental condition,
# make sure their session reflects this. We can remove this
# once the AB test completes.
if 'auto_register' in request.session:
del request.session['auto_register']
# If this course is available in multiple modes, redirect them to a page # If this course is available in multiple modes, redirect them to a page
# where they can choose which mode they want. # where they can choose which mode they want.
available_modes = CourseMode.modes_for_course(course_id) available_modes = CourseMode.modes_for_course(course_id)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment