diff --git a/cadasta/test/__init__.py b/cadasta/test/__init__.py index fc79d63..7fd229a 100644 --- a/cadasta/test/__init__.py +++ b/cadasta/test/__init__.py @@ -1 +1 @@ -__version__ = '0.2.1' +__version__ = '0.2.0' diff --git a/cadasta/test/account_tests/test_login.py b/cadasta/test/account_tests/test_login.py index 3905cd9..7a177ef 100644 --- a/cadasta/test/account_tests/test_login.py +++ b/cadasta/test/account_tests/test_login.py @@ -1,73 +1,28 @@ import pytest from ..base_test import SeleniumTestCase -from ..util import random_string +pytestmark = pytest.mark.skip -class TestLogin(SeleniumTestCase): - @pytest.fixture(autouse=True) - def get_generic_user(self, generic_user): - self.user = generic_user +class Login(SeleniumTestCase): - def test_user_can_login_by_username(self): - """Verifies User Accounts test case #L1.""" + def test_login(self): + self.open("/account/login/") + self.wd.find_css('#id_login').send_keys("cadasta-test-user-1") + self.wd.find_css("#id_password").send_keys('XYZ#qwerty') + self.wd.find_element_by_xpath('//button[@name="sign-in"]').click() + self.wd.find_elements_by_xpath( + "//span[contains(text(), 'cadasta-test-user-1')]") - self.wd.BY_LINK('Sign in').click() - self.update_form_field('login', self.user['username']) - self.update_form_field('password', self.user['password']) - self.wd.BY_NAME('sign-in').click() - self.wd.wait_for_xpath( - '//header//*[normalize-space()=""]'.format(self.user['full_name'])) - self.wait_for_alert( - 'Successfully signed in as {}.'.format(self.user['username'])) - - def test_user_can_login_by_email(self): - """Verifies User Accounts test case #L3.""" - - self.wd.BY_LINK('Sign in').click() - self.update_form_field('login', self.user['email']) - self.update_form_field('password', self.user['password']) - self.wd.BY_NAME('sign-in').click() - self.wd.wait_for_xpath( - '//header//*[normalize-space()=""]'.format(self.user['full_name'])) - self.wait_for_alert( - 'Successfully signed in as {}.'.format(self.user['username'])) - - def test_user_cannot_log_in(self): - """Verifies User Accounts test case #L2.""" - - self.wd.BY_LINK('Sign in').click() - - msg = 'The username and/or password you specified are not correct.' - self.update_form_field('login', self.user['username']) - self.update_form_field('password', random_string()) - self.wd.BY_NAME('sign-in').click() - self.wait_for_alert(msg) - self.wd.BY_LINK('Sign in') - self.wd.BY_LINK('Register') - - self.update_form_field('login', random_string()) - self.update_form_field('password', self.user['password']) - self.wd.BY_NAME('sign-in').click() - self.wait_for_alert(msg) - self.wd.BY_LINK('Sign in') - self.wd.BY_LINK('Register') - - msg = ('The e-mail address and/or password you specified are not ' - 'correct.') - - self.update_form_field('login', self.user['email']) - self.update_form_field('password', random_string()) - self.wd.BY_NAME('sign-in').click() - self.wait_for_alert(msg) - self.wd.BY_LINK('Sign in') - self.wd.BY_LINK('Register') +class LoginFailure(SeleniumTestCase): - self.update_form_field('login', random_string() + '@cadasta.org') - self.update_form_field('password', self.user['password']) + def test_login_failure(self): + self.open("/account/login/") + self.wd.BY_NAME('login').send_keys('admin') + self.wd.BY_NAME('password').send_keys('admin') self.wd.BY_NAME('sign-in').click() - self.wait_for_alert(msg) - self.wd.BY_LINK('Sign in') - self.wd.BY_LINK('Register') + self.wd.BY_XPATH( + '//*[@role="alert" and contains(normalize-space(),' + '"The login and/or password you specified are not correct.")]') diff --git a/cadasta/test/account_tests/test_registration.py b/cadasta/test/account_tests/test_registration.py index 2c41e06..f8172cd 100644 --- a/cadasta/test/account_tests/test_registration.py +++ b/cadasta/test/account_tests/test_registration.py @@ -1,241 +1,87 @@ import pytest +import time -from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.common.keys import Keys from ..base_test import SeleniumTestCase -from ..util import random_string - - -class TestRegistration(SeleniumTestCase): - - @pytest.fixture(autouse=True) - def setup_test_data(self): - self.username = 'functest_tmp_{}'.format(random_string()) - self.email = 'evillar+tmp_{}@cadasta.org'.format(random_string()) - self.password = 'XYZ#qwerty' - self.full_name = 'John Lennon' - - def click_register_button(self): - button = self.wd.BY_NAME('register') - self.scroll_element_into_view(button) - button.click() - - def test_user_can_create_account(self): - """Verifies User Accounts test case #R1.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.wd.wait_for_xpath( - '//header//*[normalize-space()="{}"]'.format(self.full_name)) - self.assert_url_path('/dashboard/') - try: - self.wd.BY_LINK('Sign in') - raise AssertionError('Sign in link is present') - except NoSuchElementException: - pass - try: - self.wd.BY_LINK('Register') - raise AssertionError('Register link is present') - except NoSuchElementException: - pass - - def test_show_password_button_works(self): - """Verifies User Accounts test case #R2.""" - - self.wd.BY_LINK('Register').click() - password_input = self.wd.BY_NAME('password') - password_input.send_keys(self.password) - button = self.wd.BY_XPATH( - '//*[contains(@class, "form-group") and ' - ' //*[@name="password"]]//button' - ) - button.click() - assert password_input.get_attribute('type') == 'text' - button.click() - assert password_input.get_attribute('type') == 'password' - - def test_username_is_required(self): - """Verifies User Accounts test case #R6.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error('username', 'This field is required.') - - def test_username_must_be_unique(self, generic_user): - """Verifies User Accounts test case #R7.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', generic_user['username']) - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error( - 'username', 'A user with that username already exists') - - def test_username_format_is_validated(self): - """Verifies User Accounts test case #R8.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - username_input = self.wd.BY_NAME('username') - username_input.send_keys('1234567890' * 20) - assert username_input.get_attribute('value') == '1234567890' * 15 - username_input.clear() - username_input.send_keys('with space') - self.click_register_button() - self.assert_form_field_has_error( - 'username', - 'Enter a valid username. This value may contain ' - 'only letters, numbers, and @/./+/-/_ characters.') - - def test_email_address_is_required(self): - """Verifies User Accounts test case #R9.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error('email', 'This field is required.') - - def test_email_address_must_be_unique(self, generic_user): - """Verifies User Accounts test case #R10.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', generic_user['email']) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error( - 'email', 'Another user with this email already exists') - - def test_email_address_format_is_validated(self): - """Verifies User Accounts test case #R11.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', 'invalid') - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error( - 'email', 'This field should be a valid email.') - - def test_password_is_required(self): - """Verifies User Accounts test case #R12.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error('password', 'This field is required.') - - def test_password_format_is_validated(self): - """Verifies User Accounts test case #R13.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('full_name', self.full_name) - - password_help = self.wd.BY_XPATH( - '//*[contains(@class, "form-group") and //*[@name="password"]]' - '//*[contains(@class, "help-block")]') - assert 'hidden' in password_help.get_attribute('class') - password_input = self.wd.BY_NAME('password') - password_input.click() - assert 'hidden' not in password_help.get_attribute('class') - - password_input.send_keys('Aa1+') - self.click_register_button() - self.assert_form_field_has_error( - 'password', - 'This field is too short. It should have 10 characters or more.') - - error_msg = ( - 'Your password must contain at least 3 of the following: ' - 'lowercase characters, uppercase characters, special characters, ' - 'and/or numerical characters.') - - def check_invalid_password(password): - password_input.clear() - password_input.send_keys(password) - self.click_register_button() - self.assert_form_field_has_error('password', error_msg) - - check_invalid_password('ABCDEFGHIJ') - check_invalid_password('abcdefghij') - check_invalid_password('1234567890') - check_invalid_password('!@#$%^&*()') - check_invalid_password('ABCDEabcde') - check_invalid_password('ABCDE12345') - check_invalid_password('ABCDE!@#$%') - check_invalid_password('abcde12345') - check_invalid_password('abcde!@#$%') - check_invalid_password('12345!@#$%') - - def test_password_must_not_contain_username(self): - """Verifies User Accounts test case #R14.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('password', self.password + self.username) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error( - 'password', 'Your password cannot contain your username.') - - def test_password_must_not_contain_email_username(self): - """Verifies User Accounts test case #R15.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - email_username = self.email.split('@')[0] - self.update_form_field('password', self.password + email_username) - self.update_form_field('full_name', self.full_name) - self.click_register_button() - self.assert_form_field_has_error( - 'password', - 'Your password cannot contain your email mailbox name.') - - def test_full_name_is_not_required(self): - """Verifies User Accounts test case #R16.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.click_register_button() - self.wd.wait_for_xpath( - '//header//*[normalize-space()="{}"]'.format(self.username)) - self.assert_url_path('/dashboard/') - - def test_user_can_select_another_language(self): - """Verifies User Accounts test case #R17.""" - - self.wd.BY_LINK('Register').click() - self.update_form_field('username', self.username) - self.update_form_field('email', self.email) - self.update_form_field('password', self.password) - self.update_form_field('full_name', self.full_name) - self.update_form_field('language', 'es') - self.click_register_button() - self.wd.wait_for_xpath( - '//header//*[normalize-space()="{}"]'.format(self.full_name)) - self.assert_url_path('/dashboard/') - self.wd.BY_LINK('Proyectos') - self.wd.BY_LINK('Organizaciones') +from ..entities import Credentials +from ..pages import RegistrationPage + +pytestmark = pytest.mark.skip + + +class NewRegistration(SeleniumTestCase): + + def test_new_registration(self): + registration_page = RegistrationPage(self.wd, self) + registration_page.go_to() + username_available = False + index = 1 + + while not username_available: + test_username = "cadasta-test-user-" + repr(index) + test_password = "XYZ#qwerty" + self.wd.find_css('#id_username').clear() + self.wd.find_css('#id_username').send_keys(test_username) + self.wd.find_css('#id_email').clear() + self.wd.find_css('#id_email').send_keys( + test_username + "@example.com") + self.wd.find_css("#id_password").clear() + self.wd.find_css("#id_password").send_keys(test_password) + self.wd.find_css("#id_full_name").send_keys('') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + time.sleep(1) + elems = self.wd.find_elements_by_xpath( + "//*[contains(text(), " + "'A user with that username already exists')]") + elems.extend(self.wd.find_elements_by_xpath( + "//*[contains(text(), " + "'Another user with this email already exists')]")) + if len(elems) == 0: + username_available = True + # Credentials().set_test_username(test_username) + # Credentials().set_test_password(test_password) + # Credentials().set_test_email(test_username + "@example.com") + assert self.wd.wait_for_css('.btn-user') + else: + index = index + 1 + + +class RegistrationAttemptUsernameNotAvailable(SeleniumTestCase): + + def test_registration_attempt_already_taken_username(self): + registration_page = RegistrationPage(self.wd, self) + registration_page.go_to() + + self.wd.find_css('#id_username').send_keys( + Credentials().get_test_username()) + self.wd.find_css('#id_email').send_keys("user@abc.com") + self.wd.find_css("#id_password").send_keys('XYZ#qwerty') + self.wd.find_css("#id_full_name").send_keys('') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + assert self.wd.wait_for_xpath( + "//*[contains(text(), " + "'A user with that username already exists')]") + + +class RegistrationAttemptEmailNotAvailable(SeleniumTestCase): + + def test_registration_attempt_already_taken_email(self): + registration_page = RegistrationPage(self.wd, self) + registration_page.go_to() + + self.wd.find_css('#id_username').send_keys("cadasta-test-user") + self.wd.find_css('#id_email').send_keys(Credentials().get_test_email()) + self.wd.find_css("#id_password").send_keys('XYZ#qwerty') + self.wd.find_css("#id_full_name").send_keys('') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + assert self.wd.wait_for_xpath( + "//*[contains(text(), " + "'Another user with this email already exists')]") diff --git a/cadasta/test/account_tests/test_registration_form_validation.py b/cadasta/test/account_tests/test_registration_form_validation.py new file mode 100644 index 0000000..e19cbf0 --- /dev/null +++ b/cadasta/test/account_tests/test_registration_form_validation.py @@ -0,0 +1,131 @@ +import pytest + +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.common.keys import Keys + +from ..base_test import SeleniumTestCase +from ..util import random_string + + +@pytest.mark.skip +class PasswordValidation(SeleniumTestCase): + + def test_invalid_password(self): + self.open("/account/signup/") + + self.wd.find_css('#id_username').send_keys("cadasta-test-user2") + self.wd.find_css('#id_email').send_keys("user2@abc.com") + self.wd.find_css("#id_password").send_keys('password123') + self.wd.find_css("#id_full_name").send_keys('') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + text = self.wd.wait_for_xpath( + "//ul[contains(@class, 'parsley-errors-list')]").text + assert text == ("Your password must contain at least 3 of the " + "following: lowercase characters, uppercase " + "characters, special characters, and/or numerical " + "characters.") + + +class RegistrationTest(SeleniumTestCase): + + def setUp(self): + super().setUp() + self.username = random_string() + self.email = random_string() + '@example.com' + self.password = 'XYZ#qwerty' + self.full_name = 'John Lennon' + + def test_username_is_required(self): + """Verifies User Accounts test case #R6.""" + + self.open("/") + self.wd.BY_XPATH('//header//a[normalize-space()="Register"]').click() + self.wd.BY_NAME('email').send_keys(self.email) + self.wd.BY_NAME('password').send_keys(self.password) + self.wd.BY_NAME('full_name').send_keys(self.full_name) + button = self.wd.BY_NAME('register') + self.wd.scroll_element_into_view(button) + button.click() + + self.wd.wait_for_xpath( + '//*[contains(@class, "form-group") and ' + ' contains(@class, "has-error") and ' + ' //*[@name="username"] and ' + ' //*[normalize-space()="This field is required."]]' + ) + + def test_email_address_is_required(self): + """Verifies User Accounts test case #R9.""" + + self.open("/") + self.wd.BY_XPATH('//header//a[normalize-space()="Register"]').click() + self.wd.BY_NAME('username').send_keys(self.username) + self.wd.BY_NAME('password').send_keys(self.password) + self.wd.BY_NAME('full_name').send_keys(self.full_name) + button = self.wd.BY_NAME('register') + self.wd.scroll_element_into_view(button) + button.click() + + self.wd.wait_for_xpath( + '//*[contains(@class, "form-group") and ' + ' contains(@class, "has-error") and ' + ' //*[@name="email"] and ' + ' //*[normalize-space()="This field is required."]]' + ) + + def test_password_is_required(self): + """Verifies User Accounts test case #R12.""" + + self.open("/") + self.wd.BY_XPATH('//header//a[normalize-space()="Register"]').click() + self.wd.BY_NAME('username').send_keys(self.username) + self.wd.BY_NAME('email').send_keys(self.email) + self.wd.BY_NAME('full_name').send_keys(self.full_name) + button = self.wd.BY_NAME('register') + self.wd.scroll_element_into_view(button) + button.click() + + self.wd.wait_for_xpath( + '//*[contains(@class, "form-group") and ' + ' contains(@class, "has-error") and ' + ' //*[@name="password"] and ' + ' //*[normalize-space()="This field is required."]]' + ) + + +@pytest.mark.skip +class EmptyUsernameInPasswordValidation(SeleniumTestCase): + + def test_empty_username_in_password(self): + self.open("/account/signup/") + + self.wd.find_css('#id_username').send_keys('') + self.wd.find_css('#id_email').send_keys("user2@abc.com") + self.wd.find_css("#id_password").send_keys('XYZ#qwerty') + self.wd.find_css("#id_full_name").send_keys('user2-name') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + text = self.wd.find_elements_by_xpath( + "//ul[contains(@class, 'parsley-errors-list')]") + assert len(text) == 1 + + +@pytest.mark.skip +class EmptyEmailInPasswordValidation(SeleniumTestCase): + + def test_empty_email_in_password(self): + self.open("/account/signup/") + + self.wd.find_css('#id_username').send_keys("cadasta-test-user2") + self.wd.find_css('#id_email').send_keys("") + self.wd.find_css("#id_password").send_keys('XYZ#qwerty') + self.wd.find_css("#id_full_name").send_keys('user2-name') + action = ActionChains(self.wd) + action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform() + + text = self.wd.find_elements_by_xpath( + "//ul[contains(@class, 'parsley-errors-list')]") + assert len(text) == 1 diff --git a/cadasta/test/account_tests/test_updating.py b/cadasta/test/account_tests/test_updating.py deleted file mode 100644 index a2f368e..0000000 --- a/cadasta/test/account_tests/test_updating.py +++ /dev/null @@ -1,344 +0,0 @@ -import pytest -import re - -from os.path import abspath, dirname, join -from selenium.webdriver.support.select import Select - -from ..base_test import SeleniumTestCase -from ..util import random_string - - -TEST_TMP_USERNAME_FORMAT = 'functest_tmp_{}' -TEST_TMP_EMAIL_FORMAT = 'evillar+tmp_{}@cadasta.org' -TEST_TMP_PASSWORD = 'qwerty#XYZ' -USER_MENU_XPATH_FORMAT = '//header//*[normalize-space()="{}"]' - - -class TestUpdating(SeleniumTestCase): - - @pytest.fixture(autouse=True) - def get_generic_user(self, generic_user): - self.user = generic_user - - # ------ Utility functions ------ - - def log_in(self, use_username=True): - """Logs in the test user either by username or email.""" - self.wd.BY_LINK('Sign in').click() - if use_username: - self.update_form_field('login', self.user['username']) - else: - self.update_form_field('login', self.user['email']) - self.update_form_field('password', self.user['password']) - self.wd.BY_NAME('sign-in').click() - label = self.user['full_name'] or self.user['username'] - self.wd.wait_for_xpath(USER_MENU_XPATH_FORMAT.format(label)) - - def click_user_menu(self): - """Clicks the current user's user menu.""" - label = self.user['full_name'] or self.user['username'] - self.wd.BY_XPATH(USER_MENU_XPATH_FORMAT.format(label)).click() - - def go_to_profile(self): - """Goes to the current user's profile page via the user menu.""" - self.click_user_menu() - self.wd.BY_LINK('Edit profile').click() - self.assert_url_path('/account/profile/') - - def click_update_profile_button(self, label='Update profile'): - """Clicks the profile page update button with optional button label - for multilingual purposes.""" - button = self.wd.BY_XPATH( - '//*[@type="submit" and normalize-space()="{}"]'.format(label)) - self.scroll_element_into_view(button) - button.click() - - def invoke_update_profile( - self, - button_label='Update profile', - alert_msg='Successfully updated profile information' - ): - """Fills in the profile page password field and then submits the - profile page form with optional button and success alert messages for - multilingual purposes.""" - self.update_form_field('password', self.user['password']) - self.click_update_profile_button(label=button_label) - self.wait_for_alert(alert_msg) - self.assert_url_path('/account/profile/') - - def log_out(self): - """Logs out the current user via the user menu.""" - self.click_user_menu() - self.wd.BY_LINK('Logout').click() - self.assert_url_path('/account/login/') - - # ------ Test cases ------ - - def test_user_can_invoke_password_reset(self): - """Verifies User Accounts test case #U1.""" - - self.wd.BY_LINK('Sign in').click() - self.wd.BY_LINK('Forgotten password?').click() - self.assert_url_path('/account/password/reset/') - self.update_form_field('email', self.user['email']) - self.wd.BY_XPATH( - '//*[@type="submit" and @value="Reset password"]').click() - self.wd.wait_for_xpath('//h1[normalize-space()="Password reset"]') - self.assert_url_path('/account/password/reset/done/') - - def test_user_can_change_password(self): - """Verifies User Accounts test case #U5.""" - - self.log_in() - self.go_to_profile() - link = self.wd.BY_LINK('Change password') - self.scroll_element_into_view(link) - link.click() - self.assert_url_path('/account/password/change/') - - self.update_form_field('oldpassword', self.user['password']) - original_password = self.user['password'] - self.user['password'] = TEST_TMP_PASSWORD - self.update_form_field('password', self.user['password']) - self.wd.BY_XPATH( - '//*[@type="submit" and ' - 'normalize-space()="Change password"]').click() - self.wait_for_alert('Password successfully changed.') - - # Try to use the new password - self.log_out() - self.log_in() - - # [REVERSION] - self.open('/account/password/change/') - self.update_form_field('oldpassword', self.user['password']) - self.user['password'] = original_password - self.update_form_field('password', self.user['password']) - self.wd.BY_XPATH( - '//*[@type="submit" and ' - 'normalize-space()="Change password"]').click() - self.wait_for_alert('Password successfully changed.') - - def test_user_cannot_change_password_without_current_password(self): - """Verifies User Accounts test case #U6.""" - - self.log_in() - self.open('/account/password/change/') - self.update_form_field('oldpassword', random_string()) - self.update_form_field('password', TEST_TMP_PASSWORD) - self.wd.BY_XPATH( - '//*[@type="submit" and ' - 'normalize-space()="Change password"]').click() - self.assert_form_field_has_error( - 'oldpassword', 'Please type your current password.') - - # Try to use the old password - self.log_out() - self.log_in() - - def test_correct_user_info_is_shown(self): - """Verifies User Accounts test case #U19.""" - - self.log_in() - self.go_to_profile() - - def assert_field(name, value): - element = self.wd.BY_NAME(name) - if element.tag_name == 'select': - element = Select(element).first_selected_option - actual_value = element.get_attribute('value') - assert actual_value == value - - assert_field('username', self.user['username']) - assert_field('email', self.user['email']) - assert_field('full_name', self.user['full_name']) - assert_field('language', self.user['language']) - assert_field('measurement', self.user['measurement']) - - def test_user_cannot_update_profile_without_password(self): - """Verifies User Accounts test case #U20.""" - - self.log_in() - self.go_to_profile() - self.update_form_field('username', random_string()) - self.click_update_profile_button() - self.assert_form_field_has_error('password', 'This field is required.') - - self.update_form_field('password', random_string()) - self.click_update_profile_button() - self.wait_for_alert('Failed to update profile information') - self.assert_form_field_has_error( - 'password', - 'Please provide the correct password for your account.') - - # Try to use the existing username - self.log_out() - self.log_in() - - def test_user_can_update_username(self): - """Verifies User Accounts test case #U8.""" - - self.log_in() - self.go_to_profile() - original_username = self.user['username'] - self.user['username'] = ( - TEST_TMP_USERNAME_FORMAT.format(random_string())) - self.update_form_field('username', self.user['username']) - self.invoke_update_profile() - - # Try to use the new username - self.log_out() - self.log_in() - - # [REVERSION] - self.open('/account/profile/') - self.user['username'] = original_username - self.update_form_field('username', self.user['username']) - self.invoke_update_profile() - - def test_user_can_update_email_address(self): - """Verifies User Accounts test case #U9.""" - - # Create throwaway account because email cannot be verified now - username = TEST_TMP_USERNAME_FORMAT.format(random_string()) - first_email = TEST_TMP_EMAIL_FORMAT.format(random_string()) - password = 'XYZ#qwerty' - self.wd.BY_LINK('Register').click() - self.update_form_field('username', username) - self.update_form_field('email', first_email) - self.update_form_field('password', password) - button = self.wd.BY_NAME('register') - self.scroll_element_into_view(button) - button.click() - self.wd.wait_for_xpath(USER_MENU_XPATH_FORMAT.format(username)) - - # Update email address - self.open('/account/profile/') - second_email = TEST_TMP_EMAIL_FORMAT.format(random_string()) - self.update_form_field('email', second_email) - self.update_form_field('password', password) - self.click_update_profile_button() - self.wait_for_alert('Successfully updated profile information') - self.wait_for_alert( - 'Confirmation email sent to {}.'.format(second_email)) - self.wd.BY_NAME('email').get_attribute('value') == first_email - self.wd.BY_XPATH( - '//*[contains(@class, "form-group") and //*[@name="email"]]' - '//*[contains(normalize-space(), ' - '"The email for this account has been changed recently")]') - - # Can only login with the old email address yet - self.open('/account/logout/') - self.update_form_field('login', first_email) - self.update_form_field('password', password) - self.wd.BY_NAME('sign-in').click() - self.wd.wait_for_xpath(USER_MENU_XPATH_FORMAT.format(username)) - - def test_user_can_update_full_name(self): - """Verifies User Accounts test case #U12.""" - - self.log_in() - self.go_to_profile() - tmp_full_name = 'Temp Name' - self.update_form_field('full_name', tmp_full_name) - self.invoke_update_profile() - self.wd.wait_for_xpath(USER_MENU_XPATH_FORMAT.format(tmp_full_name)) - - # [REVERSION] - self.update_form_field('full_name', self.user['full_name']) - self.invoke_update_profile() - self.wd.wait_for_xpath( - USER_MENU_XPATH_FORMAT.format(self.user['full_name'])) - - def test_user_can_update_preferred_language(self): - """Verifies User Accounts test case #U13.""" - - self.log_in() - self.go_to_profile() - self.update_form_field('language', 'es') - self.invoke_update_profile( - alert_msg='La informaciĆ³n del perfil se ha actualizado ' - 'correctamente') - self.wd.BY_LINK('Proyectos') - self.wd.BY_LINK('Organizaciones') - - # [REVERSION] - self.update_form_field('language', self.user['language']) - self.invoke_update_profile(button_label='Actualice el perfil') - self.wd.BY_LINK('Projects') - self.wd.BY_LINK('Organizations') - - def test_user_can_update_preferred_measurement_system(self): - """Verifies User Accounts test case #U14.""" - - self.log_in() - self.go_to_profile() - self.update_form_field('measurement', 'imperial') - self.invoke_update_profile() - - # [REVERSION] - self.update_form_field('measurement', 'metric') - self.invoke_update_profile() - - @pytest.mark.uploads - def test_user_avatar(self): - """Verifies User Accounts test case #U15, #U16, #U17, #U18.""" - - default_avatar_path = '/static/img/avatar_sm.jpg' - files_dir_path = join(dirname(dirname(abspath(__file__))), 'files') - avatar_form_group_xpath = ( - '//*[contains(@class, "form-group") and ' - '//label[normalize-space()="Profile picture"]]') - img_xpath = avatar_form_group_xpath + '//img' - file_input_xpath = avatar_form_group_xpath + '//input[@type="file"]' - remove_xpath = ( - avatar_form_group_xpath + '//*[contains(@class, "file-remove")]') - file_type_error_xpath = ( - avatar_form_group_xpath + - '//*[normalize-space()="File type not allowed."]') - - self.log_in() - self.go_to_profile() - - # Test case #U17 - img = self.wd.BY_XPATH(img_xpath) - assert default_avatar_path in img.get_attribute('src') - self.wd.BY_XPATH(file_input_xpath).send_keys( - join(files_dir_path, 'user_avatar_3.gif')) - self.wd.BY_XPATH(file_type_error_xpath) - - # Test case #U15 - self.wd.refresh() - img = self.wd.BY_XPATH(img_xpath) - assert default_avatar_path in img.get_attribute('src') - self.wd.BY_XPATH(file_input_xpath).send_keys( - join(files_dir_path, 'user_avatar_1.jpg')) - self.wd.wait_for_xpath(remove_xpath) - assert default_avatar_path not in img.get_attribute('src') - self.invoke_update_profile() - img = self.wd.BY_XPATH(img_xpath) - src = img.get_attribute('src') - assert default_avatar_path not in src - assert re.search('[a-z0-9]{24}\.jpg$', src) - - # Test case #U16 - self.wd.refresh() - self.wd.BY_XPATH(remove_xpath).click() - img = self.wd.BY_XPATH(img_xpath) - assert default_avatar_path in img.get_attribute('src') - self.wd.BY_XPATH(file_input_xpath).send_keys( - join(files_dir_path, 'user_avatar_2.png')) - self.wd.wait_for_xpath(remove_xpath) - assert default_avatar_path not in img.get_attribute('src') - self.invoke_update_profile() - img = self.wd.BY_XPATH(img_xpath) - src = img.get_attribute('src') - assert default_avatar_path not in src - assert re.search('[a-z0-9]{24}\.png$', src) - - # [REVERSION] and test case #U18 - self.wd.refresh() - self.wd.BY_XPATH(remove_xpath).click() - self.invoke_update_profile() - img = self.wd.BY_XPATH(img_xpath) - assert default_avatar_path in img.get_attribute('src') diff --git a/cadasta/test/account_tests/test_user_profile.py b/cadasta/test/account_tests/test_user_profile.py new file mode 100644 index 0000000..72a2504 --- /dev/null +++ b/cadasta/test/account_tests/test_user_profile.py @@ -0,0 +1,104 @@ +import pytest + +from ..base_test import SeleniumTestCase +from ..entities import Credentials + +pytestmark = pytest.mark.skip + + +class PasswordReset(SeleniumTestCase): + + def test_password_reset(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/password/reset/") + self.wd.find_css('#id_email').send_keys(Credentials.get_test_email()) + self.wd.find_element_by_xpath( + '//input[@value="Reset password"]').click() + text = self.wd.find_element_by_xpath("//h1").text + assert text == "Password reset" + + +class PasswordChange(SeleniumTestCase): + + def test_password_change_success(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/password/change/") + self.wd.wait_for_css('#id_oldpassword') + + self.wd.find_css('#id_oldpassword').send_keys("XYZ#qwerty") + self.wd.find_css('#id_password').send_keys("XYZ#qwertyA") + self.wd.find_elements_by_xpath( + "//button[contains(text(), 'Change password')]")[0].click() + text = self.wd.find_element_by_xpath("//h1").text + assert text == "Update your profile" + self.open("/account/logout/") + self.restore_password("XYZ#qwerty", "XYZ#qwertyA") + + def test_password_change_failure(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/password/change/") + self.wd.wait_for_css('#id_oldpassword') + + self.wd.find_css('#id_oldpassword').send_keys("abc") + self.wd.find_css('#id_password').send_keys("XYZ#qwertyA") + self.wd.find_elements_by_xpath( + "//button[contains(text(), 'Change password')]")[0].click() + text = self.wd.find_element_by_xpath("//h1").text + assert text == "Change your password" + + +class UsernameChange(SeleniumTestCase): + + def test_username_change(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/profile/") + + self.wd.find_css('#id_username').clear() + self.wd.find_css('#id_username').send_keys("cadasta-test-user-Y") + self.wd.find_element_by_xpath('//button[@name="update"]').click() + + # text = self.wd.find_elements_by_xpath( + # "//span[@class, 'username')]").text + # print text + # assert text == "cadasta-test-user-11" + + def tearDown(self): + self.restore_username(Credentials.get_test_username()) + super().tearDown() + + +class FullnameChange(SeleniumTestCase): + + def test_fullname_change(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/profile/") + + self.wd.find_css('#id_full_name').clear() + self.wd.find_css('#id_full_name').send_keys( + "cadasta-test-user-1-fullname") + self.wd.find_element_by_xpath('//button[@name="update"]').click() + + def tearDown(self): + self.restore_fullname("") + super().tearDown() + + +class EmailChange(SeleniumTestCase): + + def test_email_change(self): + self.user_login() + self.wd.wait_for_css('.btn-user') + self.open("/account/profile/") + + self.wd.find_css('#id_email').clear() + self.wd.find_css('#id_email').send_keys("cadasta-test-user-1@abc.com") + self.wd.find_element_by_xpath('//button[@name="update"]').click() + + def tearDown(self): + self.restore_email(Credentials.get_test_email()) + super().tearDown() diff --git a/cadasta/test/base_test.py b/cadasta/test/base_test.py index 505d344..c105b2b 100644 --- a/cadasta/test/base_test.py +++ b/cadasta/test/base_test.py @@ -1,23 +1,20 @@ import os -import pytest +import unittest from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support.select import Select -from urllib.parse import urlparse from .entities import Credentials from .webdriver import CustomWebDriver -class SeleniumTestCase(): +class SeleniumTestCase(unittest.TestCase): """ - A base test case for Selenium, providing helper methods for generating + A base test case for selenium, providing hepler methods for generating clients and logging in profiles. """ - - @pytest.fixture(autouse=True) - def webdriver(self): + def setUp(self): + self.host_url = os.environ.get('CADASTA_HOST', 'http://localhost:8000') # Initialize webdriver webdriver_option = os.environ.get('CADASTA_TEST_WEBDRIVER', 'Chrome') @@ -39,49 +36,12 @@ def webdriver(self): else: self.wd = CustomWebDriver() - # Set up the Django host URL and load the home page - self.host_url = os.environ.get('CADASTA_HOST', 'http://localhost:8000') - self.wd.get(self.host_url + '/') - - # Initiate the test - yield - - # Clean up after the test + def tearDown(self): self.wd.quit() def open(self, path): self.wd.get(self.host_url + path) - def get_url_path(self): - return urlparse(self.wd.current_url).path - - def assert_url_path(self, path): - assert self.get_url_path() == path - - def scroll_element_into_view(self, element): - self.wd.execute_script('arguments[0].scrollIntoView()', element) - - def wait_for_alert(self, msg): - self.wd.wait_for_xpath( - '//*[@role="alert" and ' - 'contains(normalize-space(), "{}")]'.format(msg)) - - def update_form_field(self, field_name, field_value): - field = self.wd.BY_NAME(field_name) - if field.tag_name == 'select': - Select(field).select_by_value(field_value) - else: # Assume tag_name is 'input' with type 'text' or 'password' - field.clear() - field.send_keys(field_value) - - def assert_form_field_has_error(self, field_name, error_msg): - self.wd.wait_for_xpath(( - '//*[contains(@class, "form-group") and ' - ' contains(@class, "has-error") and ' - ' //*[@name="{}"] and ' - ' //*[normalize-space()="{}"]]' - ).format(field_name, error_msg)) - def user_login(self): self.open("/account/login/") self.wd.find_css('#id_login').send_keys( diff --git a/cadasta/test/conftest.py b/cadasta/test/conftest.py deleted file mode 100644 index 00a2816..0000000 --- a/cadasta/test/conftest.py +++ /dev/null @@ -1,32 +0,0 @@ -import json -import os -import pytest - - -DEFAULT_PASSWORD = 'XYZ#qwerty' - - -@pytest.fixture(scope='session') -def all_fixtures(): - """This is a master fixture function that loads the Django loaddata test - fixtures and provides them as queryable dicts for secondary fixture - functions.""" - - # Load the JSON files - fixtures = {} - dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fixtures') - files = [os.path.join(dir, f) for f in os.listdir(dir) if '.json' in f] - for f in files: - for datum in json.load(open(f)): - if datum['model'] not in fixtures: - fixtures[datum['model']] = [] - if datum['model'] == 'accounts.user': - datum['fields']['password'] = DEFAULT_PASSWORD - fixtures[datum['model']].append(datum['fields']) - return fixtures - - -@pytest.fixture(scope='session') -def generic_user(all_fixtures): - return next(item for item in all_fixtures['accounts.user'] - if 'functest_generic' in item['username']) diff --git a/cadasta/test/files/user_avatar_1.jpg b/cadasta/test/files/user_avatar_1.jpg deleted file mode 100644 index e6e9e24..0000000 Binary files a/cadasta/test/files/user_avatar_1.jpg and /dev/null differ diff --git a/cadasta/test/files/user_avatar_2.png b/cadasta/test/files/user_avatar_2.png deleted file mode 100644 index 9786b4e..0000000 Binary files a/cadasta/test/files/user_avatar_2.png and /dev/null differ diff --git a/cadasta/test/files/user_avatar_3.gif b/cadasta/test/files/user_avatar_3.gif deleted file mode 100644 index fbf078d..0000000 Binary files a/cadasta/test/files/user_avatar_3.gif and /dev/null differ diff --git a/cadasta/test/fixtures/.gitkeep b/cadasta/test/fixtures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/cadasta/test/fixtures/main.json b/cadasta/test/fixtures/main.json deleted file mode 100644 index 24ec5cc..0000000 --- a/cadasta/test/fixtures/main.json +++ /dev/null @@ -1,26 +0,0 @@ -[ -{ - "model": "accounts.user", - "fields": { - "password": "argon2$argon2i$v=19$m=512,t=2,p=2$a3dVVjVaTG92V2FU$gR3FjRtiBYflH4UCshayQA", - "last_login": "2017-08-01T00:00:00.000Z", - "is_superuser": false, - "username": "functest_generic_5q6aqy5usyf7d2u69bgt3qw7", - "email": "evillar+dccsru66eic33a46jgkcnjda@cadasta.org", - "is_staff": false, - "is_active": true, - "date_joined": "2017-08-01T00:00:00.000Z", - "full_name": "Cadasta Generic User", - "email_verified": true, - "verify_email_by": "2017-08-03T00:00:00.000Z", - "change_pw": true, - "language": "en", - "measurement": "metric", - "avatar": "", - "created_date": "2017-08-01T00:00:00.000Z", - "last_updated": "2017-08-01T00:00:00.000Z", - "groups": [], - "user_permissions": [] - } -} -] diff --git a/cadasta/test/runtests.py b/cadasta/test/runtests.py index 9c4faaa..6e73a27 100755 --- a/cadasta/test/runtests.py +++ b/cadasta/test/runtests.py @@ -2,7 +2,6 @@ import argparse import os -import re import sys import pytest from subprocess import Popen, DEVNULL @@ -24,7 +23,7 @@ ) parser.add_argument( '-w', '--webdriver', - choices=['Chrome', 'Firefox', 'BrowserStack-Chrome'], + choices=['Chrome', 'Firefox'], default='Chrome', help="Selenium WebDriver to use", ) @@ -44,10 +43,6 @@ xvfb = Popen(["Xvfb", ":1"], stdout=DEVNULL, stderr=DEVNULL) os.environ['DISPLAY'] = ':1' - # Convert any pytest options - for i in range(len(args.pyargs)): - args.pyargs[i] = re.sub('^\+', '-', args.pyargs[i]) - # Run the tests using pytest result = pytest.main(args.pyargs) diff --git a/cadasta/test/webdriver.py b/cadasta/test/webdriver.py index 2cb50b5..f99fae5 100644 --- a/cadasta/test/webdriver.py +++ b/cadasta/test/webdriver.py @@ -30,7 +30,6 @@ def __init__(self, **kwargs): self.BYS_CSS = self.find_elements_by_css_selector self.BY_ID = self.find_element_by_id self.BY_NAME = self.find_element_by_name - self.BY_LINK = self.find_element_by_link_text self.BY_TAG = self.find_element_by_tag_name self.BYS_TAG = self.find_elements_by_tag_name self.BY_XPATH = self.find_element_by_xpath @@ -57,6 +56,9 @@ def wait_for_xpath(self, xpath, timeout=10): wait = WebDriverWait(self, timeout) return wait.until(EC.presence_of_element_located((By.XPATH, xpath))) + def scroll_element_into_view(self, element): + self.execute_script('arguments[0].scrollIntoView()', element) + def switch_to_modal_dialog(self): modal_dialog_window_handle = None main_window_handle = self.current_window_handle