diff --git a/common/djangoapps/student/tests/test_create_account.py b/common/djangoapps/student/tests/test_create_account.py index e72dd971eb..f921504ea3 100644 --- a/common/djangoapps/student/tests/test_create_account.py +++ b/common/djangoapps/student/tests/test_create_account.py @@ -1,4 +1,5 @@ "Tests for account creation" +import json import ddt import unittest @@ -9,6 +10,7 @@ from django.core.urlresolvers import reverse from django.contrib.auth.models import AnonymousUser from django.utils.importlib import import_module from django.test import TestCase, TransactionTestCase +from django.test.utils import override_settings import mock @@ -23,6 +25,21 @@ TEST_CS_URL = 'https://comments.service.test:123/' @ddt.ddt +@override_settings( + MICROSITE_CONFIGURATION={ + "microsite": { + "domain_prefix": "microsite", + "extended_profile_fields": ["extra1", "extra2"], + } + }, + REGISTRATION_EXTRA_FIELDS={ + key: "optional" + for key in [ + "level_of_education", "gender", "mailing_address", "city", "country", "goals", + "year_of_birth" + ] + } +) class TestCreateAccount(TestCase): "Tests for account creation" @@ -54,6 +71,103 @@ class TestCreateAccount(TestCase): user = User.objects.get(username=self.username) self.assertEqual(UserPreference.get_preference(user, LANGUAGE_KEY), lang) + def create_account_and_fetch_profile(self): + """ + Create an account with self.params, assert that the response indicates + success, and return the UserProfile object for the newly created user + """ + response = self.client.post(self.url, self.params, HTTP_HOST="microsite.example.com") + self.assertEqual(response.status_code, 200) + user = User.objects.get(username=self.username) + return user.profile + + def test_marketing_cookie(self): + response = self.client.post(self.url, self.params) + self.assertEqual(response.status_code, 200) + self.assertIn(settings.EDXMKTG_COOKIE_NAME, self.client.cookies) + + @unittest.skipUnless( + "microsite_configuration.middleware.MicrositeMiddleware" in settings.MIDDLEWARE_CLASSES, + "Microsites not implemented in this environment" + ) + def test_profile_saved_no_optional_fields(self): + profile = self.create_account_and_fetch_profile() + self.assertEqual(profile.name, self.params["name"]) + self.assertIsNone(profile.level_of_education) + self.assertIsNone(profile.gender) + self.assertIsNone(profile.mailing_address) + self.assertIsNone(profile.city) + self.assertEqual(profile.country, "") + self.assertIsNone(profile.goals) + self.assertEqual(profile.meta, "") + self.assertIsNone(profile.year_of_birth) + + @unittest.skipUnless( + "microsite_configuration.middleware.MicrositeMiddleware" in settings.MIDDLEWARE_CLASSES, + "Microsites not implemented in this environment" + ) + def test_profile_saved_all_optional_fields(self): + self.params.update({ + "level_of_education": "a", + "gender": "o", + "mailing_address": "123 Example Rd", + "city": "Exampleton", + "country": "US", + "goals": "To test this feature", + "year_of_birth": "2015", + "extra1": "extra_value1", + "extra2": "extra_value2", + }) + profile = self.create_account_and_fetch_profile() + self.assertEqual(profile.level_of_education, "a") + self.assertEqual(profile.gender, "o") + self.assertEqual(profile.mailing_address, "123 Example Rd") + self.assertEqual(profile.city, "Exampleton") + self.assertEqual(profile.country, "US") + self.assertEqual(profile.goals, "To test this feature") + self.assertEqual( + profile.get_meta(), + { + "extra1": "extra_value1", + "extra2": "extra_value2", + } + ) + self.assertEqual(profile.year_of_birth, 2015) + + @unittest.skipUnless( + "microsite_configuration.middleware.MicrositeMiddleware" in settings.MIDDLEWARE_CLASSES, + "Microsites not implemented in this environment" + ) + def test_profile_saved_empty_optional_fields(self): + self.params.update({ + "level_of_education": "", + "gender": "", + "mailing_address": "", + "city": "", + "country": "", + "goals": "", + "year_of_birth": "", + "extra1": "", + "extra2": "", + }) + profile = self.create_account_and_fetch_profile() + self.assertEqual(profile.level_of_education, "") + self.assertEqual(profile.gender, "") + self.assertEqual(profile.mailing_address, "") + self.assertEqual(profile.city, "") + self.assertEqual(profile.country, "") + self.assertEqual(profile.goals, "") + self.assertEqual( + profile.get_meta(), + {"extra1": "", "extra2": ""} + ) + self.assertEqual(profile.year_of_birth, None) + + def test_profile_year_of_birth_non_integer(self): + self.params["year_of_birth"] = "not_an_integer" + profile = self.create_account_and_fetch_profile() + self.assertIsNone(profile.year_of_birth) + def base_extauth_bypass_sending_activation_email(self, bypass_activation_email_for_extauth_setting): """ Tests user creation without sending activation email when @@ -99,6 +213,225 @@ class TestCreateAccount(TestCase): self.base_extauth_bypass_sending_activation_email(False) +@ddt.ddt +class TestCreateAccountValidation(TestCase): + """ + Test validation of various parameters in the create_account view + """ + def setUp(self): + super(TestCreateAccountValidation, self).setUp() + self.url = reverse("create_account") + self.minimal_params = { + "username": "test_username", + "email": "test_email@example.com", + "password": "test_password", + "name": "Test Name", + "honor_code": "true", + "terms_of_service": "true", + } + + def assert_success(self, params): + """ + Request account creation with the given params and assert that the + response properly indicates success + """ + response = self.client.post(self.url, params) + self.assertEqual(response.status_code, 200) + response_data = json.loads(response.content) + self.assertTrue(response_data["success"]) + + def assert_error(self, params, expected_field, expected_value): + """ + Request account creation with the given params and assert that the + response properly indicates an error with the given field and value + """ + response = self.client.post(self.url, params) + self.assertEqual(response.status_code, 400) + response_data = json.loads(response.content) + self.assertFalse(response_data["success"]) + self.assertEqual(response_data["field"], expected_field) + self.assertEqual(response_data["value"], expected_value) + + def test_minimal_success(self): + self.assert_success(self.minimal_params) + + def test_username(self): + params = dict(self.minimal_params) + + def assert_username_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "username", expected_error) + + # Missing + del params["username"] + assert_username_error("Error (401 username). E-mail us.") + + # Empty, too short + for username in ["", "a"]: + params["username"] = username + assert_username_error("Username must be minimum of two characters long") + + # Too long + params["username"] = "this_username_has_31_characters" + assert_username_error("Username cannot be more than 30 characters long") + + # Invalid + params["username"] = "invalid username" + assert_username_error("Username should only consist of A-Z and 0-9, with no spaces.") + + # Matching password + params["username"] = params["password"] = "test_username_and_password" + assert_username_error("Username and password fields cannot match") + + def test_email(self): + params = dict(self.minimal_params) + + def assert_email_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "email", expected_error) + + # Missing + del params["email"] + assert_email_error("Error (401 email). E-mail us.") + + # Empty, too short + for email in ["", "a"]: + params["email"] = email + assert_email_error("A properly formatted e-mail is required") + + # Too long + params["email"] = "this_email_address_has_76_characters_in_it_so_it_is_unacceptable@example.com" + assert_email_error("Email cannot be more than 75 characters long") + + # Invalid + params["email"] = "not_an_email_address" + assert_email_error("Valid e-mail is required.") + + def test_password(self): + params = dict(self.minimal_params) + + def assert_password_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "password", expected_error) + + # Missing + del params["password"] + assert_password_error("Error (401 password). E-mail us.") + + # Empty, too short + for password in ["", "a"]: + params["password"] = password + assert_password_error("A valid password is required") + + # Password policy is tested elsewhere + + def test_name(self): + params = dict(self.minimal_params) + + def assert_name_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "name", expected_error) + + # Missing + del params["name"] + assert_name_error("Error (401 name). E-mail us.") + + # Empty, too short + for name in ["", "a"]: + params["name"] = name + assert_name_error("Your legal name must be a minimum of two characters long") + + def test_honor_code(self): + params = dict(self.minimal_params) + + def assert_honor_code_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "honor_code", expected_error) + + with override_settings(REGISTRATION_EXTRA_FIELDS={"honor_code": "required"}): + # Missing + del params["honor_code"] + assert_honor_code_error("To enroll, you must follow the honor code.") + + # Empty, invalid + for honor_code in ["", "false", "True"]: + params["honor_code"] = honor_code + assert_honor_code_error("To enroll, you must follow the honor code.") + + with override_settings(REGISTRATION_EXTRA_FIELDS={"honor_code": "optional"}): + # Missing + del params["honor_code"] + self.assert_success(params) + + def test_terms_of_service(self): + params = dict(self.minimal_params) + + def assert_terms_of_service_error(expected_error): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, "terms_of_service", expected_error) + + # Missing + del params["terms_of_service"] + assert_terms_of_service_error("You must accept the terms of service.") + + # Empty, invalid + for terms_of_service in ["", "false", "True"]: + params["terms_of_service"] = terms_of_service + assert_terms_of_service_error("You must accept the terms of service.") + + @ddt.data( + ("level_of_education", 1, "A level of education is required"), + ("gender", 1, "Your gender is required"), + ("year_of_birth", 2, "Your year of birth is required"), + ("mailing_address", 2, "Your mailing address is required"), + ("goals", 2, "A description of your goals is required"), + ("city", 2, "A city is required"), + ("country", 2, "A country is required"), + ("custom_field", 2, "You are missing one or more required fields") + ) + @ddt.unpack + def test_extra_fields(self, field, min_length, expected_error): + params = dict(self.minimal_params) + + def assert_extra_field_error(): + """ + Assert that requesting account creation results in the expected + error + """ + self.assert_error(params, field, expected_error) + + with override_settings(REGISTRATION_EXTRA_FIELDS={field: "required"}): + # Missing + assert_extra_field_error() + + # Empty + params[field] = "" + assert_extra_field_error() + + # Too short + if min_length > 1: + params[field] = "a" + assert_extra_field_error() + + @mock.patch.dict("student.models.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch("lms.lib.comment_client.User.base_url", TEST_CS_URL) @mock.patch("lms.lib.comment_client.utils.requests.request", return_value=mock.Mock(status_code=200, text='{}'))