Merge pull request #8262 from open-craft/tpa-pipeline-consolidation

Cleanup of third-party login and auto-enrollment
This commit is contained in:
Renzo Lucioni
2015-06-19 09:12:11 -04:00
52 changed files with 1216 additions and 1409 deletions

View File

@@ -80,7 +80,7 @@ class FieldsMixin(object):
query = self.q(css='.u-field-{} .u-field-message'.format(field_id))
return query.text[0] if query.present else None
def wait_for_messsage(self, field_id, message):
def wait_for_message(self, field_id, message):
"""
Wait for a message to appear in a field.
"""

View File

@@ -187,10 +187,14 @@ class CombinedLoginAndRegisterPage(PageObject):
"""
# Fill in the form
self.wait_for_element_visibility('#register-email', 'Email field is shown')
self.q(css="#register-email").fill(email)
self.q(css="#register-name").fill(full_name)
self.q(css="#register-username").fill(username)
self.q(css="#register-password").fill(password)
if email:
self.q(css="#register-email").fill(email)
if full_name:
self.q(css="#register-name").fill(full_name)
if username:
self.q(css="#register-username").fill(username)
if password:
self.q(css="#register-password").fill(password)
if country:
self.q(css="#register-country option[value='{country}']".format(country=country)).click()
if (terms_of_service):
@@ -220,6 +224,16 @@ class CombinedLoginAndRegisterPage(PageObject):
# Submit it
self.q(css=".login-button").click()
def click_third_party_dummy_provider(self):
"""Clicks on the Dummy third party provider login button.
Requires that the "login" form is visible.
This does NOT wait for the ensuing page[s] to load.
Only the "Dummy" provider is used for bok choy because it is the only
one that doesn't send traffic to external servers.
"""
self.q(css="button.{}-Dummy".format(self.current_form)).click()
def password_reset(self, email):
"""Navigates to, fills in, and submits the password reset form.
@@ -268,6 +282,21 @@ class CombinedLoginAndRegisterPage(PageObject):
elif self.q(css=".js-reset").visible:
return "password-reset"
@property
def email_value(self):
""" Current value of the email form field """
return self.q(css="#register-email").attrs('value')[0]
@property
def full_name_value(self):
""" Current value of the full_name form field """
return self.q(css="#register-name").attrs('value')[0]
@property
def username_value(self):
""" Current value of the username form field """
return self.q(css="#register-username").attrs('value')[0]
@property
def errors(self):
"""Return a list of errors displayed to the user. """
@@ -294,3 +323,15 @@ class CombinedLoginAndRegisterPage(PageObject):
success = self.success
return (bool(success), success)
return Promise(_check_func, "Success message is visible").fulfill()
@unguarded # Because we go from this page -> temporary page -> this page again when testing the Dummy provider
def wait_for_auth_status_message(self):
"""Wait for a status message to be visible following third_party registration, then return it."""
def _check_func():
"""Return third party auth status notice message."""
for selector in ['.already-authenticated-msg p', '.status p']:
msg_element = self.q(css=selector)
if msg_element.visible:
return (True, msg_element.text[0])
return (False, None)
return Promise(_check_func, "Result of third party auth is visible").fulfill()

View File

@@ -177,6 +177,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
{
'title': 'Connected Accounts',
'fields': [
'Dummy',
'Facebook',
'Google',
]
@@ -211,7 +212,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
for new_value in new_valid_values:
self.assertEqual(self.account_settings_page.value_for_text_field(field_id, new_value), new_value)
self.account_settings_page.wait_for_messsage(field_id, success_message)
self.account_settings_page.wait_for_message(field_id, success_message)
if assert_after_reload:
self.browser.refresh()
self.assertEqual(self.account_settings_page.value_for_text_field(field_id), new_value)
@@ -227,7 +228,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
for new_value in new_values:
self.assertEqual(self.account_settings_page.value_for_dropdown_field(field_id, new_value), new_value)
self.account_settings_page.wait_for_messsage(field_id, success_message)
self.account_settings_page.wait_for_message(field_id, success_message)
if reloads_on_save:
self.account_settings_page.wait_for_loading_indicator()
else:
@@ -242,7 +243,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
self.assertEqual(self.account_settings_page.title_for_field(field_id), title)
self.assertEqual(self.account_settings_page.link_title_for_link_field(field_id), link_title)
self.account_settings_page.click_on_link_in_link_field(field_id)
self.account_settings_page.wait_for_messsage(field_id, success_message)
self.account_settings_page.wait_for_message(field_id, success_message)
def test_username_field(self):
"""

View File

@@ -18,6 +18,7 @@ from ..helpers import (
select_option_by_value,
element_has_text
)
from ...pages.lms.account_settings import AccountSettingsPage
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.create_mode import ModeCreationPage
from ...pages.common.logout import LogoutPage
@@ -131,6 +132,46 @@ class LoginFromCombinedPageTest(UniqueCourseTest):
self.login_page.wait_for_errors()
)
def test_third_party_login(self):
"""
Test that we can login using third party credentials, and that the
third party account gets linked to the edX account.
"""
# Create a user account
email, password = self._create_unique_user()
# Navigate to the login page and try to log in using "Dummy" provider
self.login_page.visit()
self.login_page.click_third_party_dummy_provider()
# The user will be redirected somewhere and then back to the login page:
msg_text = self.login_page.wait_for_auth_status_message()
self.assertIn("You have successfully signed into Dummy", msg_text)
self.assertIn("To link your accounts, sign in now using your edX password", msg_text)
# Now login with username and password:
self.login_page.login(email=email, password=password)
# Expect that we reach the dashboard and we're auto-enrolled in the course
course_names = self.dashboard_page.wait_for_page().available_courses
self.assertIn(self.course_info["display_name"], course_names)
# Now logout and check that we can log back in instantly (because the account is linked):
LogoutPage(self.browser).visit()
self.login_page.visit()
self.login_page.click_third_party_dummy_provider()
self.dashboard_page.wait_for_page()
# Now unlink the account (To test the account settings view and also to prevent cross-test side effects)
account_settings = AccountSettingsPage(self.browser).visit()
field_id = "auth-dummy"
account_settings.wait_for_field(field_id)
self.assertEqual("Unlink", account_settings.link_title_for_link_field(field_id))
account_settings.click_on_link_in_link_field(field_id)
account_settings.wait_for_message(field_id, "Successfully unlinked")
def _create_unique_user(self):
"""
Create a new user with a unique name and email.
@@ -226,6 +267,50 @@ class RegisterFromCombinedPageTest(UniqueCourseTest):
self.register_page.visit().toggle_form()
self.assertEqual(self.register_page.current_form, "login")
def test_third_party_register(self):
"""
Test that we can register using third party credentials, and that the
third party account gets linked to the edX account.
"""
# Navigate to the register page and try to authenticate using the "Dummy" provider
self.register_page.visit()
self.register_page.click_third_party_dummy_provider()
# The user will be redirected somewhere and then back to the register page:
msg_text = self.register_page.wait_for_auth_status_message()
self.assertEqual(self.register_page.current_form, "register")
self.assertIn("You've successfully signed into Dummy", msg_text)
self.assertIn("We just need a little more information", msg_text)
# Now the form should be pre-filled with the data from the Dummy provider:
self.assertEqual(self.register_page.email_value, "adama@fleet.colonies.gov")
self.assertEqual(self.register_page.full_name_value, "William Adama")
self.assertIn("Galactica1", self.register_page.username_value)
# Set country, accept the terms, and submit the form:
self.register_page.register(country="US", terms_of_service=True)
# Expect that we reach the dashboard and we're auto-enrolled in the course
course_names = self.dashboard_page.wait_for_page().available_courses
self.assertIn(self.course_info["display_name"], course_names)
# Now logout and check that we can log back in instantly (because the account is linked):
LogoutPage(self.browser).visit()
login_page = CombinedLoginAndRegisterPage(self.browser, start_page="login")
login_page.visit()
login_page.click_third_party_dummy_provider()
self.dashboard_page.wait_for_page()
# Now unlink the account (To test the account settings view and also to prevent cross-test side effects)
account_settings = AccountSettingsPage(self.browser).visit()
field_id = "auth-dummy"
account_settings.wait_for_field(field_id)
self.assertEqual("Unlink", account_settings.link_title_for_link_field(field_id))
account_settings.click_on_link_in_link_field(field_id)
account_settings.wait_for_message(field_id, "Successfully unlinked")
@attr('shard_4')
class PayAndVerifyTest(EventsTestMixin, UniqueCourseTest):

View File

@@ -2468,59 +2468,6 @@ CREATE TABLE `shoppingcart_registrationcoderedemption` (
CONSTRAINT `registration_code_id_refs_id_4d01e47b` FOREIGN KEY (`registration_code_id`) REFERENCES `shoppingcart_courseregistrationcode` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `social_auth_association`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `social_auth_association` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`server_url` varchar(255) NOT NULL,
`handle` varchar(255) NOT NULL,
`secret` varchar(255) NOT NULL,
`issued` int(11) NOT NULL,
`lifetime` int(11) NOT NULL,
`assoc_type` varchar(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `social_auth_code`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `social_auth_code` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(75) NOT NULL,
`code` varchar(32) NOT NULL,
`verified` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`,`code`),
KEY `social_auth_code_65da3d2c` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `social_auth_nonce`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `social_auth_nonce` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`server_url` varchar(255) NOT NULL,
`timestamp` int(11) NOT NULL,
`salt` varchar(65) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `social_auth_usersocialauth`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `social_auth_usersocialauth` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`provider` varchar(32) NOT NULL,
`uid` varchar(255) NOT NULL,
`extra_data` longtext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `provider` (`provider`,`uid`),
KEY `social_auth_usersocialauth_fbfc09f1` (`user_id`),
CONSTRAINT `user_id_refs_id_60fa311b` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `south_migrationhistory`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;

Binary file not shown.