diff --git a/api/osf_api.py b/api/osf_api.py index f985e2e5..9469b2d3 100644 --- a/api/osf_api.py +++ b/api/osf_api.py @@ -1197,14 +1197,14 @@ def update_file_metadata(session, file_guid): ) -def get_registration_resource_id(registration_id): +def get_registration_resource_id(registration_id, resource_type): """This function returns the most recent resource id added to the given registration""" session = client.Session( api_base_url=settings.API_DOMAIN, auth=(settings.REGISTRATIONS_USER, settings.REGISTRATIONS_USER_PASSWORD), ) - + resource = resource_type.replace(' ', '_').lower() url = '/v2/registrations/{}/resources/'.format(registration_id) data = session.get(url)['data'] if data: @@ -1212,19 +1212,24 @@ def get_registration_resource_id(registration_id): date_created = data[i]['attributes']['date_created'] now = datetime.now() current_date = now.strftime('%Y-%m-%d') - if current_date in date_created: + if ( + current_date in date_created + and data[i]['attributes']['resource_type'] == resource + ): return data[i]['id'] break return None -def delete_registration_resource(registration_id): +def delete_registration_resource(registration_id, resource_type): """This function deletes the resource added to the given registration""" session = client.Session( api_base_url=settings.API_DOMAIN, auth=(settings.REGISTRATIONS_USER, settings.REGISTRATIONS_USER_PASSWORD), ) - registration_resource_id = get_registration_resource_id(registration_id) + registration_resource_id = get_registration_resource_id( + registration_id, resource_type + ) url = '/v2/resources/{}'.format(registration_resource_id) session.delete(url, item_type='resources') @@ -1238,9 +1243,9 @@ def create_registration_resource(registration_guid, resource_type): api_base_url=settings.API_DOMAIN, auth=(settings.REGISTRATIONS_USER, settings.REGISTRATIONS_USER_PASSWORD), ) - resource_id = get_registration_resource_id(registration_guid) + resource_id = get_registration_resource_id(registration_guid, resource_type) if resource_id is not None: - delete_registration_resource(registration_guid) + delete_registration_resource(registration_guid, resource_type) url = '/v2/resources/' raw_payload = { @@ -1279,3 +1284,22 @@ def create_registration_resource(registration_guid, resource_type): item_id=resource_id, item_type='resources', )['data'] + + +def delete_registration_resources(registration_id): + """This function deletes all the resources added to the given registration""" + session = client.Session( + api_base_url=settings.API_DOMAIN, + auth=(settings.REGISTRATIONS_USER, settings.REGISTRATIONS_USER_PASSWORD), + ) + url = '/v2/registrations/{}/resources/'.format(registration_id) + data = session.get(url)['data'] + if data: + for i in range(0, len(data)): + date_created = data[i]['attributes']['date_created'] + now = datetime.now() + current_date = now.strftime('%Y-%m-%d') + if current_date in date_created: + registration_resource_id = data[i]['id'] + delete_url = '/v2/resources/{}'.format(registration_resource_id) + session.delete(delete_url, item_type='resources') diff --git a/components/project.py b/components/project.py index 70f140c2..1283cf11 100644 --- a/components/project.py +++ b/components/project.py @@ -1,6 +1,7 @@ from selenium.webdriver.common.by import By import settings +import utils from base.locators import ( BaseElement, GroupLocator, @@ -96,7 +97,7 @@ class CreateRegistrationModal(BaseElement): def get_schema_names_list(self): """Returns the schema names from the schema list""" - return [schema.text for schema in self.schema_list] + return [utils.clean_text(schema.text) for schema in self.schema_list] def select_schema_radio_button(self, schema_name='Open-Ended Registration'): """Selects the radio button corresponding to the given schema name""" diff --git a/pages/cos.py b/pages/cos.py index 175fbfcb..8a120348 100644 --- a/pages/cos.py +++ b/pages/cos.py @@ -8,4 +8,4 @@ class COSDonatePage(BasePage): url = 'https://www.cos.io/support-cos' - identity = Locator(By.ID, 'Yourdonationtitle', settings.LONG_TIMEOUT) + identity = Locator(By.CSS_SELECTOR, 'h2#Yourdonationtitle', settings.LONG_TIMEOUT) diff --git a/pages/preprints.py b/pages/preprints.py index d598173b..408ddaaa 100644 --- a/pages/preprints.py +++ b/pages/preprints.py @@ -4,6 +4,7 @@ from selenium.webdriver.common.by import By import settings +import utils from base.locators import ( ComponentLocator, GroupLocator, @@ -101,7 +102,7 @@ class PreprintSubmitPage(BasePreprintPage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break @@ -114,7 +115,7 @@ def select_from_dropdown_listbox(self, selection): def select_top_level_subject(self, selection): for subject in self.top_level_subjects: - if subject.text == selection: + if utils.clean_text(subject.text) == selection: # Find the checkbox element and click it to select the subject checkbox = subject.find_element_by_css_selector( 'input.ember-checkbox.ember-view' @@ -325,7 +326,7 @@ def click_provider_group_link(self, provider_name, link_name): group_name = provider_group.find_element_by_css_selector( 'span._provider-name_gp8jcl' ) - if provider_name == group_name.text: + if provider_name == utils.clean_text(group_name.text): links = provider_group.find_elements_by_css_selector( 'ul._provider-links_gp8jcl > li > a' ) diff --git a/pages/project.py b/pages/project.py index 8651aa0c..354c90f0 100644 --- a/pages/project.py +++ b/pages/project.py @@ -8,6 +8,7 @@ from selenium.webdriver.common.by import By import settings +import utils from api import osf_api from base.locators import ( ComponentLocator, @@ -43,7 +44,7 @@ class ProjectPage(GuidBasePage): - identity = Locator(By.ID, 'projectScope') + identity = Locator(By.ID, 'projectScope', settings.LONG_TIMEOUT) title = Locator(By.ID, 'nodeTitleEditable', settings.LONG_TIMEOUT) title_input = Locator(By.CSS_SELECTOR, '.form-inline input') title_edit_submit_button = Locator(By.CSS_SELECTOR, '.editable-submit') @@ -535,7 +536,7 @@ class FilesMetadataPage(GuidBasePage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break @@ -588,7 +589,7 @@ class ProjectMetadataPage(GuidBasePage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break diff --git a/pages/registries.py b/pages/registries.py index d69c0465..aa8813ca 100644 --- a/pages/registries.py +++ b/pages/registries.py @@ -3,6 +3,7 @@ from selenium.webdriver.common.by import By import settings +import utils from base.locators import ( ComponentLocator, GroupLocator, @@ -114,7 +115,7 @@ class RegistrationDetailPage(BaseSubmittedRegistrationPage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break @@ -179,7 +180,7 @@ class RegistrationMetadataPage(BaseSubmittedRegistrationPage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break @@ -254,7 +255,7 @@ class RegistrationFileDetailPage(GuidBasePage): def get_tag(self, tag_value): for tag in self.tags: - if tag.text == tag_value: + if utils.clean_text(tag.text) == tag_value: return tag return None @@ -366,7 +367,7 @@ def url(self): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break @@ -438,13 +439,13 @@ class DraftRegistrationMetadataPage(BaseRegistrationDraftPage): def select_from_dropdown_listbox(self, selection): for option in self.dropdown_options: - if option.text == selection: + if utils.clean_text(option.text) == selection: option.click() break def select_top_level_subject(self, selection): for subject in self.top_level_subjects: - if subject.text == selection: + if utils.clean_text(subject.text) == selection: # Find the checkbox element and click it to select the subject checkbox = subject.find_element_by_css_selector( 'input.ember-checkbox.ember-view' @@ -474,10 +475,8 @@ class DraftRegistrationDesignPlanPage(BaseRegistrationDraftPage): """Draft Design Plan Page for an OSF Preregistration Template""" url_addition = '2-design-plan' - identity = Locator( - By.CSS_SELECTOR, 'input[id^="radio-Experiment"]', settings.LONG_TIMEOUT - ) - other_radio_button = Locator(By.CSS_SELECTOR, 'input[id^="radio-Other"]') + identity = Locator(By.CSS_SELECTOR, '[data-test-page-heading]') + other_radio_button = Locator(By.XPATH, '//div/input[@value="Other"]') no_blinding_checkbox = Locator( By.CSS_SELECTOR, 'div._Checkboxes_qxt8ij > div:nth-child(1) > input' ) @@ -492,12 +491,12 @@ class DraftRegistrationSamplingPlanPage(BaseRegistrationDraftPage): url_addition = '3-sampling-plan' identity = Locator( - By.CSS_SELECTOR, - 'input[id^="radio-Registration prior to creation"]', + By.XPATH, + '//input[@value="Registration following analysis of the data"]', settings.LONG_TIMEOUT, ) reg_following_radio_button = Locator( - By.CSS_SELECTOR, 'input[id^="radio-Registration following"]' + By.XPATH, '//input[@value="Registration following analysis of the data"]' ) data_procedures_textbox = Locator(By.NAME, '__responseKey_q10|question') sample_size_textbox = Locator(By.NAME, '__responseKey_q11') diff --git a/pages/user.py b/pages/user.py index ba8fdd8f..85a74f28 100644 --- a/pages/user.py +++ b/pages/user.py @@ -83,9 +83,13 @@ class AccountSettingsPage(BaseUserSettingsPage): storage_location_listbox = Locator( By.CSS_SELECTOR, 'div[data-test-region-selector] > div' ) + affiliation_help_text = Locator( + By.CSS_SELECTOR, '[data-test-affiliated-institutions-help-text]' + ) first_affiliated_institution = Locator( By.CSS_SELECTOR, 'span[data-test-affiliated-institutions-item]' ) + first_aff_inst_delete_button = Locator( By.CSS_SELECTOR, 'span[data-test-affiliated-institutions-delete] > button' ) @@ -110,6 +114,7 @@ class AccountSettingsPage(BaseUserSettingsPage): configure_2fa_button = Locator( By.CSS_SELECTOR, 'button[data-test-two-factor-enable-button]' ) + two_factor_help = Locator(By.CSS_SELECTOR, '[data-test-why-two-factor]') two_factor_qr_code_img = Locator(By.CSS_SELECTOR, 'div[data-test-2f-qr-code] > img') cancel_2fa_button = Locator( By.CSS_SELECTOR, 'button[data-test-two-factor-verify-cancel-button]' @@ -127,7 +132,6 @@ class AccountSettingsPage(BaseUserSettingsPage): unconfirmed_emails = GroupLocator( By.CSS_SELECTOR, 'div[data-test-unconfirmed-email-item]' ) - configure_2fa_modal = ComponentLocator(Configure2FAModal) confirm_deactivation_modal = ComponentLocator(ConfirmDeactivationRequestModal) undo_deactivation_modal = ComponentLocator(UndoDeactivationRequestModal) @@ -147,7 +151,7 @@ def get_unconfirmed_email_item(self, email_address): class ConfigureAddonsPage(BaseUserSettingsPage): url = settings.OSF_HOME + '/settings/addons/' - identity = Locator(By.CSS_SELECTOR, '#configureAddons') + identity = Locator(By.CSS_SELECTOR, 'div[data-analytics-scope="User addons"]') class NotificationsPage(BaseUserSettingsPage): diff --git a/settings.py b/settings.py index 63ff4ba6..8bd1e06e 100644 --- a/settings.py +++ b/settings.py @@ -111,6 +111,16 @@ 'resolution': '2048x1536', 'timezone': 'UTC', }, + 'safari': { + 'browser': 'Safari', + 'browser_version': '17', + 'os': 'OS X', + 'os_version': 'Sonoma', + 'timezone': 'UTC', + 'networkLogs': True, + 'enablePopups': False, + 'acceptInsecureCerts': True, + }, } BUILD = DRIVER diff --git a/tests/test_collections.py b/tests/test_collections.py index a46ac6d4..1ba580a3 100644 --- a/tests/test_collections.py +++ b/tests/test_collections.py @@ -6,6 +6,7 @@ import markers import settings +import utils from api import osf_api from pages.collections import ( CollectionDiscoverPage, @@ -326,9 +327,11 @@ def test_pre_moderation_collection_reject( # first). rejected_card = rejected_page.get_submission_card(collection_project.id) assert ( - rejected_card.find_element_by_css_selector( - '[data-test-review-action-comment]' - ).text + utils.clean_text( + rejected_card.find_element_by_css_selector( + '[data-test-review-action-comment]' + ).text + ) == '— Rejecting collection submission via selenium automated test.' ) rejected_card.find_element_by_css_selector( @@ -354,12 +357,12 @@ def test_pre_moderation_collection_reject( assert project_page.collections_container.present() project_page.collections_container.click() assert ( - project_page.first_collection_label.text + utils.clean_text(project_page.first_collection_label.text) == "Rejected from Selenium Testing Collection's Collection" ) project_page.collection_justification_link.click() assert ( - project_page.collection_justification_reason.text + utils.clean_text(project_page.collection_justification_reason.text) == 'Rejecting collection submission via selenium automated test.' ) finally: @@ -436,9 +439,11 @@ def test_post_moderation_collection_remove( # first). removed_card = removed_page.get_submission_card(collection_project.id) assert ( - removed_card.find_element_by_css_selector( - '[data-test-review-action-comment]' - ).text + utils.clean_text( + removed_card.find_element_by_css_selector( + '[data-test-review-action-comment]' + ).text + ) == '— Removing collection submission via selenium automated test.' ) removed_card.find_element_by_css_selector( @@ -567,9 +572,11 @@ def test_post_moderation_collection_remove_by_project_admin( # in the table since the default sort order is by Date (newest first). removed_card = removed_page.get_submission_card(collection_project.id) assert ( - removed_card.find_element_by_css_selector( - '[data-test-review-action-comment]' - ).text + utils.clean_text( + removed_card.find_element_by_css_selector( + '[data-test-review-action-comment]' + ).text + ) == '— Project admin removing project from collection via selenium automated test.' ) removed_card.find_element_by_css_selector( diff --git a/tests/test_dashboard.py b/tests/test_dashboard.py index a75c9d1c..10a23194 100644 --- a/tests/test_dashboard.py +++ b/tests/test_dashboard.py @@ -80,7 +80,7 @@ def test_collections_link(self, driver, dashboard_page): # and switch focus to it. WebDriverWait(driver, 3).until(EC.number_of_windows_to_be(2)) driver.switch_to.window(driver.window_handles[1]) - WebDriverWait(driver, 3).until( + WebDriverWait(driver, 10).until( EC.visibility_of_element_located((By.CLASS_NAME, 'hs-menu-wrapper')) ) assert 'https://www.cos.io/products/osf-collections' in driver.current_url diff --git a/tests/test_landing.py b/tests/test_landing.py index b0479bad..7dafc917 100644 --- a/tests/test_landing.py +++ b/tests/test_landing.py @@ -1,5 +1,7 @@ import pytest from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait import markers import settings @@ -34,6 +36,9 @@ def test_search(self, driver, landing_page): @markers.core_functionality def test_learn_more(self, driver, landing_page): landing_page.learn_more_button.click() + WebDriverWait(driver, 5).until( + EC.url_matches(('https://www.cos.io/products/osf')) + ) assert 'https://www.cos.io/products/osf' in driver.current_url def test_testimonials_by_buttons(self, driver, landing_page): diff --git a/tests/test_login.py b/tests/test_login.py index da8e5c79..0c4df5df 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -8,6 +8,7 @@ import markers import settings +import utils from base.exceptions import PageException from pages.landing import LandingPage from pages.login import ( @@ -57,6 +58,10 @@ def test_orcid_login(self, driver, login_page): # Oauth will redirect to callback url with "error" if anything goes wrong assert 'error' not in driver.current_url + @pytest.mark.skipif( + settings.env('TEST_BUILD') == 'safari' and settings.DRIVER == 'Remote', + reason='Test fails on safari browser due to some oauth setting on the browser', + ) def test_osf_home_link(self, driver, login_page): login_page.osf_home_link.click() assert LandingPage(driver, verify=True) @@ -75,10 +80,18 @@ def test_need_help_link(self, driver, login_page): def test_cos_footer_link(self, driver, login_page): login_page.cos_footer_link.click() + WebDriverWait(driver, 5).until(EC.url_matches(('https://www.cos.io/'))) assert driver.current_url == 'https://www.cos.io/' def test_terms_of_use_footer_link(self, driver, login_page): login_page.terms_of_use_footer_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' @@ -86,6 +99,13 @@ def test_terms_of_use_footer_link(self, driver, login_page): def test_privacy_policy_footer_link(self, driver, login_page): login_page.privacy_policy_footer_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' @@ -116,7 +136,8 @@ def test_one_time_password_required(self, driver): # click the Verify button and verify that you receive an error message that a one-time password is required two_factor_page.verify_button.click() assert ( - two_factor_page.login_error_message.text == 'One-time password is required.' + utils.clean_text(two_factor_page.login_error_message.text) + == 'One-time password is required.' ) def test_invalid_one_time_password(self, driver): @@ -128,7 +149,7 @@ def test_invalid_one_time_password(self, driver): two_factor_page.oneTimePassword_input.send_keys_deliberately('999999') two_factor_page.verify_button.click() assert ( - two_factor_page.login_error_message.text + utils.clean_text(two_factor_page.login_error_message.text) == 'The one-time password you entered is incorrect.' ) @@ -180,6 +201,13 @@ def test_terms_of_use_link(self, driver): ) tos_page = LoginToSPage(driver, verify=True) tos_page.terms_of_use_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' @@ -191,6 +219,13 @@ def test_privacy_policy_link(self, driver): ) tos_page = LoginToSPage(driver, verify=True) tos_page.privacy_policy_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' @@ -219,7 +254,7 @@ def test_generic_logged_in_page(self, driver, must_be_logged_in): driver.get(settings.CAS_DOMAIN + '/login') logged_in_page = GenericCASPage(driver, verify=True) assert ( - logged_in_page.auto_redirect_message.text + utils.clean_text(logged_in_page.auto_redirect_message.text) == "Auto-redirection didn't happen ..." ) assert logged_in_page.status_message.text == 'Login successful' @@ -229,7 +264,7 @@ def test_generic_logged_out_page(self, driver): driver.get(settings.CAS_DOMAIN + '/logout') logged_out_page = GenericCASPage(driver, verify=True) assert ( - logged_out_page.auto_redirect_message.text + utils.clean_text(logged_out_page.auto_redirect_message.text) == "Auto-redirection didn't happen ..." ) assert logged_out_page.status_message.text == 'Logout successful' @@ -241,19 +276,25 @@ class TestLoginErrors: def test_missing_email(self, driver, login_page): login_page.submit_button.click() - assert login_page.login_error_message.text == 'Email is required.' + assert ( + utils.clean_text(login_page.login_error_message.text) + == 'Email is required.' + ) def test_missing_password(self, driver, login_page): login_page.username_input.send_keys_deliberately('foo') login_page.submit_button.click() - assert login_page.login_error_message.text == 'Password is required.' + assert ( + utils.clean_text(login_page.login_error_message.text) + == 'Password is required.' + ) def test_invalid_email_and_password(self, driver, login_page): login_page.username_input.send_keys_deliberately('foo') login_page.password_input.send_keys_deliberately('foo') login_page.submit_button.click() assert ( - login_page.login_error_message.text + utils.clean_text(login_page.login_error_message.text) == 'The email or password you entered is incorrect.' ) @@ -262,7 +303,7 @@ def test_invalid_password(self, driver, login_page): login_page.password_input.send_keys_deliberately('foo') login_page.submit_button.click() assert ( - login_page.login_error_message.text + utils.clean_text(login_page.login_error_message.text) == 'The email or password you entered is incorrect.' ) @@ -277,8 +318,11 @@ def test_service_not_authorized_page(self, driver): """Test the Service not authorized exception page by having an invalid service in the url""" driver.get(settings.CAS_DOMAIN + '/login?service=https://noservice.osf.io/') exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Service not authorized' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) + == 'Service not authorized' + ) def test_verification_key_login_failed_page(self, driver): """Test the Verification key login failed exception page by having an invalid verification_key parameter @@ -295,8 +339,11 @@ def test_verification_key_login_failed_page(self, driver): + '&verification_key=foo' ) exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Verification key login failed' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) + == 'Verification key login failed' + ) def test_flow_less_page_not_found_page(self, driver): """Test the Page Not Found exception page by having an invalid path in the url. CAS only supports 3 valid paths: @@ -305,8 +352,8 @@ def test_flow_less_page_not_found_page(self, driver): driver.get(settings.CAS_DOMAIN + '/nopath') exception_page = GenericCASPage(driver, verify=True) # Since this exception page is flow-less (a.k.a. OSF unaware) the navbar will display OSF CAS instead of OSF HOME - assert exception_page.navbar_brand.text == 'OSF CAS' - assert exception_page.status_message.text == 'Page Not Found' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF CAS' + assert utils.clean_text(exception_page.status_message.text) == 'Page Not Found' @markers.dont_run_on_prod def test_account_not_confirmed_page(self, driver): @@ -316,8 +363,11 @@ def test_account_not_confirmed_page(self, driver): password=settings.UNCONFIRMED_USER_PASSWORD, ) exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Account not confirmed' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) + == 'Account not confirmed' + ) @markers.dont_run_on_prod def test_account_disabled_page(self, driver): @@ -327,8 +377,10 @@ def test_account_disabled_page(self, driver): password=settings.DEACTIVATED_USER_PASSWORD, ) exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Account disabled' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) == 'Account disabled' + ) def try_login_page(driver, page_class): @@ -383,10 +435,18 @@ def test_sign_in_with_osf_link(self, driver, institution_login_page): def test_cos_footer_link(self, driver, institution_login_page): institution_login_page.cos_footer_link.click() + WebDriverWait(driver, 5).until(EC.url_matches(('https://www.cos.io/'))) assert driver.current_url == 'https://www.cos.io/' def test_terms_of_use_footer_link(self, driver, institution_login_page): institution_login_page.terms_of_use_footer_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/TERMS_OF_USE.md' @@ -394,6 +454,13 @@ def test_terms_of_use_footer_link(self, driver, institution_login_page): def test_privacy_policy_footer_link(self, driver, institution_login_page): institution_login_page.privacy_policy_footer_link.click() + WebDriverWait(driver, 5).until( + EC.url_matches( + ( + 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' + ) + ) + ) assert ( driver.current_url == 'https://github.com/CenterForOpenScience/cos.io/blob/master/PRIVACY_POLICY.md' @@ -476,6 +543,10 @@ def test_individual_institution_login_pages( @markers.dont_run_on_prod class TestOauthAPI: + @pytest.mark.skipif( + settings.env('TEST_BUILD') == 'safari', + reason='Test fails on safari browser due to some oauth setting on the browser', + ) def test_authorization_online(self, driver, must_be_logged_in): client_id = settings.DEVAPP_CLIENT_ID client_secret = settings.DEVAPP_CLIENT_SECRET @@ -496,8 +567,11 @@ def test_authorization_online(self, driver, must_be_logged_in): # navigate to the authorization url in the browser driver.get(authorization_url) authorization_page = CASAuthorizationPage(driver, verify=True) - assert authorization_page.navbar_brand.text == 'OSF HOME' - assert authorization_page.status_message.text == 'Approve or deny authorization' + assert utils.clean_text(authorization_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(authorization_page.status_message.text) + == 'Approve or deny authorization' + ) # click allow button to redirect to callback url with authorization code authorization_page.allow_button.click() callback_url = driver.current_url @@ -540,6 +614,10 @@ def test_authorization_online(self, driver, must_be_logged_in): assert r.status_code == 401 assert r.json()['error'] == 'expired_accessToken' + @pytest.mark.skipif( + settings.env('TEST_BUILD') == 'safari', + reason='Test fails on safari browser due to some oauth setting on the browser', + ) def test_authorization_offline(self, driver, must_be_logged_in): client_id = settings.DEVAPP_CLIENT_ID client_secret = settings.DEVAPP_CLIENT_SECRET @@ -558,8 +636,11 @@ def test_authorization_offline(self, driver, must_be_logged_in): # navigate to the authorization url in the browser driver.get(authorization_url) authorization_page = CASAuthorizationPage(driver, verify=True) - assert authorization_page.navbar_brand.text == 'OSF HOME' - assert authorization_page.status_message.text == 'Approve or deny authorization' + assert utils.clean_text(authorization_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(authorization_page.status_message.text) + == 'Approve or deny authorization' + ) # click allow button to redirect to callback url with authorization code authorization_page.allow_button.click() callback_url = driver.current_url @@ -632,6 +713,10 @@ def test_authorization_offline(self, driver, must_be_logged_in): assert r.status_code == 401 assert r.json()['error'] == 'expired_accessToken' + @pytest.mark.skipif( + settings.env('TEST_BUILD') == 'safari', + reason='Test fails on safari browser due to some oauth setting on the browser', + ) def test_authorization_single_scope(self, driver, must_be_logged_in): client_id = settings.DEVAPP_CLIENT_ID client_secret = settings.DEVAPP_CLIENT_SECRET @@ -650,7 +735,7 @@ def test_authorization_single_scope(self, driver, must_be_logged_in): # navigate to the authorization url in the browser driver.get(authorization_url) authorization_page = CASAuthorizationPage(driver, verify=True) - assert authorization_page.navbar_brand.text == 'OSF HOME' + assert utils.clean_text(authorization_page.navbar_brand.text) == 'OSF HOME' assert authorization_page.status_message.text == 'Approve or deny authorization' # click allow button to redirect to callback url with authorization code authorization_page.allow_button.click() @@ -711,8 +796,11 @@ def test_deny_authorization(self, driver, must_be_logged_in): # navigate to the authorization url in the browser driver.get(authorization_url) authorization_page = CASAuthorizationPage(driver, verify=True) - assert authorization_page.navbar_brand.text == 'OSF HOME' - assert authorization_page.status_message.text == 'Approve or deny authorization' + assert utils.clean_text(authorization_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(authorization_page.status_message.text) + == 'Approve or deny authorization' + ) # click deny button to redirect to callback url with access denied error message authorization_page.deny_button.click() callback_url = driver.current_url @@ -738,9 +826,15 @@ def test_authorization_failed_missing_client_id(self, driver, must_be_logged_in) driver.get(authorization_url) # verify exception page exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Authorization failed' - assert exception_page.error_detail.text == 'missing_request_param: client_id' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) + == 'Authorization failed' + ) + assert ( + utils.clean_text(exception_page.error_detail.text) + == 'missing_request_param: client_id' + ) def test_authorization_failed_invalid_redirect_uri(self, driver, must_be_logged_in): client_id = settings.DEVAPP_CLIENT_ID @@ -760,10 +854,13 @@ def test_authorization_failed_invalid_redirect_uri(self, driver, must_be_logged_ driver.get(authorization_url) # verify exception page exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Authorization failed' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' assert ( - exception_page.error_detail.text + utils.clean_text(exception_page.status_message.text) + == 'Authorization failed' + ) + assert ( + utils.clean_text(exception_page.error_detail.text) == 'invalid_redirect_url: https://www.gogle.com/' ) @@ -785,6 +882,12 @@ def test_authorization_failed_invalid_scope(self, driver, must_be_logged_in): driver.get(authorization_url) # verify exception page exception_page = GenericCASPage(driver, verify=True) - assert exception_page.navbar_brand.text == 'OSF HOME' - assert exception_page.status_message.text == 'Authorization failed' - assert exception_page.error_detail.text == 'invalid_scope: everything' + assert utils.clean_text(exception_page.navbar_brand.text) == 'OSF HOME' + assert ( + utils.clean_text(exception_page.status_message.text) + == 'Authorization failed' + ) + assert ( + utils.clean_text(exception_page.error_detail.text) + == 'invalid_scope: everything' + ) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index c2246a14..88fbc591 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -140,7 +140,9 @@ def test_change_file_metadata_title(self, driver, file_metadata_page, fake): title_input.clear() title_input.send_keys(new_title) file_metadata_page.save_metadata_button.click() - assert new_title == file_metadata_page.files_metadata_title.text + assert new_title == utils.clean_text( + file_metadata_page.files_metadata_title.text + ) file_metadata_tab = utils.switch_to_new_tab(driver) utils.close_current_tab(driver, file_metadata_tab) @@ -164,7 +166,9 @@ def test_change_file_metadata_description(self, driver, file_metadata_page, fake description_input.clear() description_input.send_keys(new_description) file_metadata_page.save_metadata_button.click() - assert new_description == file_metadata_page.files_metadata_description.text + assert new_description == utils.clean_text( + file_metadata_page.files_metadata_description.text + ) file_metadata_tab = utils.switch_to_new_tab(driver) utils.close_current_tab(driver, file_metadata_tab) @@ -322,7 +326,9 @@ def test_edit_metadata_description(self, driver, project_metadata_page, fake): description_input.clear() description_input.send_keys(new_description) project_metadata_page.save_description_button.click() - assert new_description == project_metadata_page.description.text + assert new_description == utils.clean_text( + project_metadata_page.description.text + ) def test_edit_contributors( self, session, driver, project_metadata_page, default_project_with_metadata @@ -345,7 +351,7 @@ def test_edit_contributors( WebDriverWait(driver, 5).until( EC.element_to_be_clickable( - (By.CSS_SELECTOR, '[data-test-edit-contributors]') + (By.CSS_SELECTOR, '[data-test-contributors-link]') ) ).click() @@ -361,6 +367,7 @@ def test_edit_contributors( project_metadata_page.search_input.click() project_metadata_page.search_input.send_keys(new_user) project_metadata_page.contributor_search_button.click() + # project_metadata_page.contributor_search_button.click() # Get the row number for the user from the search table WebDriverWait(driver, 5).until( @@ -402,7 +409,7 @@ def test_edit_contributors( user = driver.find_element_by_xpath( contributor_table_path + '/tbody/tr[' + str(rowno) + ']/td[2]' ) - assert new_user in user.text + assert new_user in utils.clean_text(user.text) def test_edit_resource_information(self, driver, project_metadata_page): """This test verifies that user can add/remove @@ -540,7 +547,9 @@ def test_edit_metadata_description(self, driver, registration_metadata_page, fak description_input.clear() description_input.send_keys(new_description) registration_metadata_page.save_metadata_description_button.click() - assert new_description == registration_metadata_page.metadata_description.text + assert new_description == utils.clean_text( + registration_metadata_page.metadata_description.text + ) def test_edit_resource_information(self, driver, registration_metadata_page): """This test verifies that user can add/remove @@ -579,9 +588,11 @@ def test_edit_resource_information(self, driver, registration_metadata_page): registration_metadata_page.select_from_dropdown_listbox('Bengali') registration_metadata_page.resource_information_save_button.click() - assert orig_resource_type != registration_metadata_page.resource_type.text - assert ( - orig_resource_language != registration_metadata_page.resource_language.text + assert orig_resource_type != utils.clean_text( + registration_metadata_page.resource_type.text + ) + assert orig_resource_language != utils.clean_text( + registration_metadata_page.resource_language.text ) def test_edit_support_funding_information( diff --git a/tests/test_navbar.py b/tests/test_navbar.py index 0823d92e..4ddcf0a1 100644 --- a/tests/test_navbar.py +++ b/tests/test_navbar.py @@ -1,3 +1,5 @@ +import time + import pytest from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @@ -74,6 +76,9 @@ def test_institutions_dropdown_link(self, page, driver): def test_donate_link(self, page, driver): page.navbar.donate_link.click() donate_page = COSDonatePage(driver, verify=False) + WebDriverWait(driver, 10).until( + EC.url_matches(('https://www.cos.io/support-cos')) + ) assert_donate_page(driver, donate_page) def test_sign_in_button(self, page, driver): @@ -323,7 +328,7 @@ def assert_donate_page(driver, donate_page): meta_tag = driver.find_element_by_xpath( '//meta[@property="og:title" and contains(@content, "Support COS")]' ) - + WebDriverWait(driver, 10).until(EC.url_matches(('https://www.cos.io/support-cos'))) assert 'support-cos' in driver.current_url assert meta_tag.get_attribute('property') == 'og:title' assert meta_tag.get_attribute('content') == 'Support COS' @@ -353,6 +358,7 @@ def test_search_link(self, driver, collections_discover_page): def test_donate_link(self, session, driver, collections_discover_page): collections_discover_page.donate_link.click() donate_page = COSDonatePage(driver, verify=False) + time.sleep(3) assert_donate_page(driver, donate_page) @@ -389,6 +395,7 @@ def test_search_link(self, driver, page): def test_donate_link(self, session, driver, page): page.donate_link.click() donate_page = COSDonatePage(driver, verify=False) + time.sleep(1) assert_donate_page(driver, donate_page) @@ -418,4 +425,5 @@ def test_support_link(self, session, driver, page): def test_donate_link(self, session, driver, page): page.navbar.donate_link.click() donate_page = COSDonatePage(driver, verify=False) + time.sleep(1) assert_donate_page(driver, donate_page) diff --git a/tests/test_preprints.py b/tests/test_preprints.py index f4c040af..d5e378ae 100644 --- a/tests/test_preprints.py +++ b/tests/test_preprints.py @@ -133,7 +133,10 @@ def test_create_preprint_from_landing( WebDriverWait(driver, 5).until( EC.visibility_of(submit_page.first_selected_subject) ) - assert submit_page.first_selected_subject.text == 'Engineering' + assert ( + utils.clean_text(submit_page.first_selected_subject.text) + == 'Engineering' + ) # Need to scroll down since the Keyword/tags section is obscured by the Dev # mode warning in the test environments @@ -199,7 +202,9 @@ def test_create_preprint_from_landing( submit_page.create_preprint_button.click() preprint_detail = PreprintDetailPage(driver, verify=True) WebDriverWait(driver, 10).until(EC.visibility_of(preprint_detail.title)) - assert preprint_detail.title.text == 'Selenium Test Preprint' + assert ( + utils.clean_text(preprint_detail.title.text) == 'Selenium Test Preprint' + ) # Capture guid of supplemental materials project created during workflow supplemental_url = preprint_detail.view_page.get_attribute('href') supplemental_guid = utils.get_guid_from_url(supplemental_url, 3) @@ -277,7 +282,6 @@ def test_edit_preprint(self, session, driver, preprint_detail_page): WebDriverWait(driver, 5).until( EC.visibility_of_element_located((By.CSS_SELECTOR, '[data-test-title]')) ) - edit_page.next_button.click() # Next add another subject in the Discipline section WebDriverWait(driver, 5).until( @@ -309,11 +313,15 @@ def test_edit_preprint(self, session, driver, preprint_detail_page): WebDriverWait(driver, 5).until( EC.element_to_be_clickable((By.CSS_SELECTOR, '[data-test-submit-button]')) ) + edit_page.submit_preprint_button.click() detail_page = PreprintDetailPage(driver, verify=True) # Verify Title and Abstract assert detail_page.title.text == 'Selenium Preprint Edit' - assert detail_page.abstract.text == 'Testing Selenium Abstract edit' + assert ( + utils.clean_text(detail_page.abstract.text) + == 'Testing Selenium Abstract edit' + ) # Verify new Subject appears on the page subjects = detail_page.subjects subject_found = False diff --git a/tests/test_project.py b/tests/test_project.py index cdb11447..7f0d3847 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1,4 +1,5 @@ import re +import time from urllib.parse import urljoin import pytest @@ -8,6 +9,7 @@ import markers import settings +import utils from api import osf_api from pages.login import ( LoginPage, @@ -247,9 +249,10 @@ def test_add_component(self, driver, session, project_page): # the Overview page of a new node project_page.component_created_modal.go_to_new_component_link.click() component_page = ProjectPage(driver, verify=True) + time.sleep(1) assert component_page.title.text == 'Selenium Component' assert ( - component_page.description.text + utils.clean_text(component_page.description.text) == 'This component was added by an automated selenium test.' ) @@ -277,6 +280,7 @@ def test_add_component(self, driver, session, project_page): # back to the original parent Project Overview page. component_page.scroll_into_view(component_page.parent_project_link.element) component_page.parent_project_link.click() + time.sleep(2) assert project_page # Verify that the Components section of the parent Project now lists the @@ -376,7 +380,7 @@ def test_delete_component_from_project(self, driver, session, default_project): EC.visibility_of(project_page.alert_message.element) ) assert ( - project_page.alert_message.text + utils.clean_text(project_page.alert_message.text) == 'Component has been successfully deleted.' ) assert len(project_page.components) == 0 @@ -482,13 +486,13 @@ def test_vol_project_overview_page(self, driver, session, project_with_file): # Verify VOL message at the top of the page assert ( - project_page.alert_info_message.text + utils.clean_text(project_page.alert_info_message.text) == 'This project is being viewed through a private, view-only link. Anyone with the link can view this project. Keep the link safe.' ) # Verify Contributor is visible user = osf_api.current_user() - assert project_page.contributors_list.text == user.full_name + assert utils.clean_text(project_page.contributors_list.text) == user.full_name # Verify File Widget loads assert project_page.file_widget.first_file @@ -526,7 +530,7 @@ def test_avol_project_overview_page(self, driver, session, project_with_file): # Verify VOL message at the top of the page assert ( - project_page.alert_info_message.text + utils.clean_text(project_page.alert_info_message.text) == 'This project is being viewed through a private, view-only link. Anyone with the link can view this project. Keep the link safe.' ) diff --git a/tests/test_project_analytics.py b/tests/test_project_analytics.py index 644b6610..a2adda3d 100644 --- a/tests/test_project_analytics.py +++ b/tests/test_project_analytics.py @@ -135,6 +135,10 @@ def public_project_node(session, driver): @markers.smoke_test @pytest.mark.usefixtures('hide_footer_slide_in') +@pytest.mark.skipif( + settings.env('TEST_BUILD') == 'safari', + reason='Test fails on safari browser due to some oauth setting on the browser', +) class TestNodeAnalytics: def test_unique_visits_graph(self, session, driver, public_project_node): """Test the Unique Visits Graph on the Project Analytics page. First retrieve diff --git a/tests/test_project_files.py b/tests/test_project_files.py index 38f65718..ec15000b 100644 --- a/tests/test_project_files.py +++ b/tests/test_project_files.py @@ -10,6 +10,7 @@ import markers import settings +import utils from api import osf_api from pages.landing import LandingPage from pages.project import ( @@ -659,7 +660,7 @@ def test_vol_project_files_page( # Verify VOL message at the top of the page assert ( - files_page.alert_info_message.text + utils.clean_text(files_page.alert_info_message.text) == 'You are viewing OSF through a view-only link, which may limit the data you have permission to see.' ) @@ -670,11 +671,16 @@ def test_vol_project_files_page( row = find_row_by_name(files_page, file_name) # Get initial Download Count for the file (should be 0) - initial_download_count = int( - row.find_element_by_css_selector( - '[data-test-file-list-download-count]' - ).text[:2] + # initial_download_count = int( + # row.find_element_by_css_selector( + # '[data-test-file-list-download-count]' + # ).text[:2] + # ) + element = row.find_element_by_css_selector( + '[data-test-file-list-download-count]' ) + download_count_text = element.get_attribute('textContent').strip()[:2] + initial_download_count = int(download_count_text) assert initial_download_count == 0 # Verify File Download Functionality @@ -682,11 +688,16 @@ def test_vol_project_files_page( # Verify Download Count has incremented by 1 row = find_row_by_name(files_page, file_name) - new_download_count = int( - row.find_element_by_css_selector( - '[data-test-file-list-download-count]' - ).text[:2] + # new_download_count = int( + # row.find_element_by_css_selector( + # '[data-test-file-list-download-count]' + # ).text[:2] + # ) + element = row.find_element_by_css_selector( + '[data-test-file-list-download-count]' ) + download_count_text = element.get_attribute('textContent').strip()[:2] + new_download_count = int(download_count_text) assert new_download_count == initial_download_count + 1 # Click the Leave this View button and verify we are navigated to OSF Home page diff --git a/tests/test_project_registrations.py b/tests/test_project_registrations.py index 84ba3945..115013bb 100644 --- a/tests/test_project_registrations.py +++ b/tests/test_project_registrations.py @@ -1,6 +1,7 @@ import pytest import markers +import utils from api import osf_api from pages.project import RegistrationsPage from pages.registries import ( @@ -65,15 +66,15 @@ def test_empty_registrations_tab(self, driver, registrations_page): ) assert registrations_page.registration_card.absent() assert ( - registrations_page.no_registrations_message_1.text + utils.clean_text(registrations_page.no_registrations_message_1.text) == 'There have been no completed registrations of this project.' ) assert ( - registrations_page.no_registrations_message_2.text + utils.clean_text(registrations_page.no_registrations_message_2.text) == 'Start a new registration by clicking the “New registration” button. Once created, registrations cannot be edited or deleted.' ) assert ( - registrations_page.no_registrations_message_3.text + utils.clean_text(registrations_page.no_registrations_message_3.text) == 'Learn more about registrations here.' ) # Click 'here' link and verify redirection to support page @@ -96,15 +97,15 @@ def test_empty_draft_registrations_tab(self, driver, registrations_page): ) assert registrations_page.draft_registration_card.absent() assert ( - registrations_page.no_draft_registrations_message_1.text + utils.clean_text(registrations_page.no_draft_registrations_message_1.text) == 'There are no draft registrations of this project.' ) assert ( - registrations_page.no_draft_registrations_message_2.text + utils.clean_text(registrations_page.no_draft_registrations_message_2.text) == 'Start a new registration by clicking the “New registration” button. Once created, registrations cannot be edited or deleted.' ) assert ( - registrations_page.no_draft_registrations_message_3.text + utils.clean_text(registrations_page.no_draft_registrations_message_3.text) == 'Learn more about registrations here.' ) # Click 'here' link and verify redirection to support page @@ -124,7 +125,7 @@ def test_create_new_registration_modal(self, driver, registrations_page): # Get list of allowed schema names for OSF Registries from the api and verify # the list on the modal matches the api list api_schemas = osf_api.get_registration_schemas_for_provider(provider_id='osf') - api_schema_list = [schema[0] for schema in api_schemas] + api_schema_list = [utils.clean_text(schema[0]) for schema in api_schemas] api_schema_list.sort() modal_schema_list = create_registration_modal.get_schema_names_list() modal_schema_list.sort() @@ -161,15 +162,21 @@ def test_review_draft_registration( """ assert registrations_page_with_draft.draft_registration_card.present() assert ( - registrations_page_with_draft.draft_registration_title.text + utils.clean_text( + registrations_page_with_draft.draft_registration_title.text + ) == 'OSF Test Project' ) assert ( - registrations_page_with_draft.draft_registration_schema_name.text + utils.clean_text( + registrations_page_with_draft.draft_registration_schema_name.text + ) == 'Open-Ended Registration' ) assert ( - registrations_page_with_draft.draft_registration_provider.text + utils.clean_text( + registrations_page_with_draft.draft_registration_provider.text + ) == 'OSF Registries' ) registrations_page_with_draft.review_draft_button.click() @@ -186,7 +193,9 @@ def test_edit_draft_registration( """ assert registrations_page_with_draft.draft_registration_card.present() assert ( - registrations_page_with_draft.draft_registration_title.text + utils.clean_text( + registrations_page_with_draft.draft_registration_title.text + ) == 'OSF Test Project' ) registrations_page_with_draft.edit_draft_button.click() @@ -203,7 +212,9 @@ def test_delete_draft_registration( """ assert registrations_page_with_draft.draft_registration_card.present() assert ( - registrations_page_with_draft.draft_registration_title.text + utils.clean_text( + registrations_page_with_draft.draft_registration_title.text + ) == 'OSF Test Project' ) # Click the Delete button for the Draft Registration card and then click the @@ -220,6 +231,8 @@ def test_delete_draft_registration( registrations_page_with_draft.delete_draft_registration_modal.delete_button.click() assert registrations_page_with_draft.draft_registration_card.absent() assert ( - registrations_page_with_draft.no_draft_registrations_message_1.text + utils.clean_text( + registrations_page_with_draft.no_draft_registrations_message_1.text + ) == 'There are no draft registrations of this project.' ) diff --git a/tests/test_registration_sidebar.py b/tests/test_registration_sidebar.py index bb3203f6..f6782621 100644 --- a/tests/test_registration_sidebar.py +++ b/tests/test_registration_sidebar.py @@ -4,6 +4,7 @@ from selenium.webdriver.support.ui import WebDriverWait import markers +import utils from api import osf_api from pages.registries import ( RegistrationAnalyticsPage, @@ -141,10 +142,10 @@ def test_add_new_resource( ) # Verify and delete the resource if already exists resource_id = osf_api.get_registration_resource_id( - registration_id=registration_guid + registration_id=registration_guid, resource_type=resource_type ) if resource_id is not None: - osf_api.delete_registration_resource(registration_guid) + osf_api.delete_registration_resources(registration_guid) registration_details_page.reload() WebDriverWait(driver, 10).until( EC.invisibility_of_element_located( @@ -161,7 +162,7 @@ def test_add_new_resource( ) ) assert data_resource is not None - osf_api.delete_registration_resource(registration_guid) + osf_api.delete_registration_resource(registration_guid, resource_type) @pytest.mark.parametrize('resource_type', resource_types) def test_edit_resource( @@ -184,10 +185,12 @@ def test_edit_resource( ) registration_details_page_with_resource.save_button.click() assert ( - registration_details_page_with_resource.resource_card_description.text + utils.clean_text( + registration_details_page_with_resource.resource_card_description.text + ) == resource_description ) - osf_api.delete_registration_resource(registration_guid) + osf_api.delete_registration_resources(registration_guid) @pytest.mark.parametrize('resource_type', resource_types) def test_delete_resource( @@ -199,9 +202,7 @@ def test_delete_resource( fake, ): """This test verifies delete functionality of data output resource for a registration""" - registration_details_page_with_resource.open_practice_resource_data.click() - registration_details_page_with_resource.resource_type_delete_button.click() registration_details_page_with_resource.resource_type_delete_confirm.click() @@ -211,8 +212,8 @@ def test_delete_resource( (By.CSS_SELECTOR, '[data-test-add-resource-section]') ) ) - - assert ( - registration_details_page_with_resource.resource_list.text - == 'This registration has no resources.' + resource_id = osf_api.get_registration_resource_id( + registration_id=registration_guid, resource_type=resource_type ) + assert resource_id is None + osf_api.delete_registration_resources(registration_guid) diff --git a/tests/test_registries.py b/tests/test_registries.py index 1b072e15..a7ecac64 100644 --- a/tests/test_registries.py +++ b/tests/test_registries.py @@ -12,6 +12,7 @@ import markers import settings +import utils from api import osf_api from pages.login import safe_login from pages.registrations import MyRegistrationsPage @@ -62,7 +63,10 @@ def test_search_results_exist(self, driver, landing_page): ) assert search_page.search_input.get_attribute('value') == 'QA Test' assert len(search_page.search_results) > 0 - assert search_page.first_card_object_type_label.text[:12] == 'REGISTRATION' + assert ( + utils.clean_text(search_page.first_card_object_type_label.text.upper()) + == 'REGISTRATION' + ) @markers.smoke_test @markers.core_functionality @@ -119,6 +123,8 @@ def test_detail_page(self, driver): # Wait for the new tab to open - window count should then = 2 WebDriverWait(driver, 5).until(EC.number_of_windows_to_be(2)) # Switch focus to the new tab + if settings.env('TEST_BUILD') == 'safari': + driver.switch_to.window(driver.window_handles[-1]) driver.switch_to.window(driver.window_handles[1]) detail_page = RegistrationDetailPage(driver, verify=True) assert detail_page.title.text in target_registration_title @@ -317,17 +323,6 @@ def test_submit_registration_from_project( 'This is a test registration created from a project using Selenium.' ) - metadata_page.scroll_into_view(metadata_page.category_listbox_trigger.element) - metadata_page.category_listbox_trigger.click() - WebDriverWait(driver, 5).until( - EC.visibility_of_element_located( - ( - By.CSS_SELECTOR, - '#ember-basic-dropdown-wormhole > div > ul >li.ember-power-select-option', - ) - ) - ) - metadata_page.select_from_dropdown_listbox('Software') metadata_page.scroll_into_view(metadata_page.license_listbox_trigger.element) metadata_page.license_listbox_trigger.click() WebDriverWait(driver, 5).until( @@ -345,7 +340,9 @@ def test_submit_registration_from_project( WebDriverWait(driver, 5).until( EC.visibility_of(metadata_page.first_selected_subject) ) - assert metadata_page.first_selected_subject.text == 'Engineering' + assert ( + utils.clean_text(metadata_page.first_selected_subject.text) == 'Engineering' + ) metadata_page.tags_input_box.click() metadata_page.tags_input_box.send_keys('selenium\r') @@ -358,7 +355,7 @@ def test_submit_registration_from_project( # Study Information Page study_page = DraftRegistrationStudyInfoPage(driver, verify=True) - assert study_page.page_heading.text == 'Study Information' + assert utils.clean_text(study_page.page_heading.text) == 'Study Information' study_page.hypothesis_textbox.click() study_page.hypothesis_textbox.send_keys_deliberately( @@ -369,7 +366,7 @@ def test_submit_registration_from_project( # Design Plan Page design_page = DraftRegistrationDesignPlanPage(driver, verify=True) - assert design_page.page_heading.text == 'Design Plan' + assert utils.clean_text(design_page.page_heading.text) == 'Design Plan' design_page.other_radio_button.click() design_page.scroll_into_view( @@ -385,7 +382,7 @@ def test_submit_registration_from_project( # Verify file is attached design_page.scroll_into_view(design_page.first_file_name.element) assert ( - design_page.first_file_name.text + utils.clean_text(design_page.first_file_name.text) == 'osf selenium test file for registration.txt' ) @@ -394,7 +391,7 @@ def test_submit_registration_from_project( # Sampling Plan Page sampling_page = DraftRegistrationSamplingPlanPage(driver, verify=True) - assert sampling_page.page_heading.text == 'Sampling Plan' + assert utils.clean_text(sampling_page.page_heading.text) == 'Sampling Plan' sampling_page.reg_following_radio_button.click() sampling_page.scroll_into_view(sampling_page.data_procedures_textbox.element) @@ -404,7 +401,7 @@ def test_submit_registration_from_project( ) sampling_page.scroll_into_view(sampling_page.first_file_name.element) assert ( - sampling_page.first_file_name.text + utils.clean_text(sampling_page.first_file_name.text) == 'osf selenium test file for registration.txt' ) @@ -415,7 +412,7 @@ def test_submit_registration_from_project( # Variables Page variables_page = DraftRegistrationVariablesPage(driver, verify=True) - assert variables_page.page_heading.text == 'Variables' + assert utils.clean_text(variables_page.page_heading.text) == 'Variables' # Verify that the Required Data Missing Indicator now displays in the left # sidebar since we left a required textbox empty on the previous page. @@ -424,7 +421,7 @@ def test_submit_registration_from_project( # Verify file is attached variables_page.scroll_into_view(variables_page.first_file_name.element) assert ( - variables_page.first_file_name.text + utils.clean_text(variables_page.first_file_name.text) == 'osf selenium test file for registration.txt' ) @@ -439,7 +436,7 @@ def test_submit_registration_from_project( # Analysis Plan Page analysis_page = DraftRegistrationAnalysisPlanPage(driver, verify=True) - assert analysis_page.page_heading.text == 'Analysis Plan' + assert utils.clean_text(analysis_page.page_heading.text) == 'Analysis Plan' analysis_page.stat_models_textbox.click() analysis_page.stat_models_textbox.send_keys_deliberately( @@ -449,7 +446,7 @@ def test_submit_registration_from_project( # Verify file is attached analysis_page.scroll_into_view(analysis_page.first_file_name.element) assert ( - analysis_page.first_file_name.text + utils.clean_text(analysis_page.first_file_name.text) == 'osf selenium test file for registration.txt' ) @@ -458,7 +455,7 @@ def test_submit_registration_from_project( # Other Page other_page = DraftRegistrationOtherPage(driver, verify=True) - assert other_page.page_heading.text == 'Other' + assert utils.clean_text(other_page.page_heading.text) == 'Other' other_page.other_textbox.click() other_page.other_textbox.send_keys_deliberately( @@ -470,27 +467,31 @@ def test_submit_registration_from_project( # Review Page review_page = DraftRegistrationReviewPage(driver, verify=True) - assert review_page.title.text == 'Selenium Test Project With File Registration' assert ( - review_page.description.text + utils.clean_text(review_page.title.text) + == 'Selenium Test Project With File Registration' + ) + assert ( + utils.clean_text(review_page.description.text) == 'This is a test registration created from a project using Selenium.' ) - assert review_page.category.text == 'Software' - assert review_page.license.text == 'CC0 1.0 Universal' - assert review_page.subject.text == 'Engineering' + assert utils.clean_text(review_page.category.text) == 'Project' + assert utils.clean_text(review_page.license.text) == 'CC0 1.0 Universal' + assert utils.clean_text(review_page.subject.text) == 'Engineering' assert ( - review_page.tags.text + utils.clean_text(review_page.tags.text) == 'qatest selenium tests/test_registries.py::TestRegistrationSubmission::()::test_submit_registration_from_project (setup)' ) # Verify the validation error since we intentionally left the required Sample # Size textbox empty assert ( - review_page.invalid_responses_text.text + utils.clean_text(review_page.invalid_responses_text.text) == 'Please address invalid or missing entries to complete registration.' ) assert ( - review_page.sample_size_question_error.text == "This field can't be blank." + utils.clean_text(review_page.sample_size_question_error.text) + == "This field can't be blank." ) # Verify Register button is disabled assert driver.find_element( @@ -500,7 +501,7 @@ def test_submit_registration_from_project( # Go back to Sampling Plan page and enter data in Sample Size textbox review_page.sampling_plan_page_link.click() sampling_page = DraftRegistrationSamplingPlanPage(driver, verify=True) - assert sampling_page.page_heading.text == 'Sampling Plan' + assert utils.clean_text(sampling_page.page_heading.text) == 'Sampling Plan' sampling_page.scroll_into_view(sampling_page.sample_size_textbox.element) sampling_page.sample_size_textbox.click() sampling_page.sample_size_textbox.send_keys_deliberately( @@ -519,7 +520,7 @@ def test_submit_registration_from_project( assert review_page.invalid_responses_text.absent() assert review_page.sample_size_question_error.absent() assert ( - review_page.sample_size_response.text + utils.clean_text(review_page.sample_size_response.text) == 'Sample Size textbox - regression testing using selenium.' ) @@ -533,7 +534,7 @@ def test_submit_registration_from_project( # Admin Approval status tombstone_page = RegistrationTombstonePage(driver, verify=True) assert ( - tombstone_page.tombstone_title.text + utils.clean_text(tombstone_page.tombstone_title.text) == 'This registration is currently archiving, and no changes can be made at this time.' ) @@ -588,18 +589,6 @@ def test_submit_no_project_registration( 'This is a test registration created using Selenium.' ) - metadata_page.scroll_into_view(metadata_page.category_listbox_trigger.element) - metadata_page.category_listbox_trigger.click() - WebDriverWait(driver, 5).until( - EC.visibility_of_element_located( - ( - By.CSS_SELECTOR, - '#ember-basic-dropdown-wormhole > div > ul >li.ember-power-select-option', - ) - ) - ) - metadata_page.select_from_dropdown_listbox('Software') - metadata_page.scroll_into_view(metadata_page.license_listbox_trigger.element) metadata_page.license_listbox_trigger.click() WebDriverWait(driver, 5).until( @@ -617,7 +606,9 @@ def test_submit_no_project_registration( WebDriverWait(driver, 5).until( EC.visibility_of(metadata_page.first_selected_subject) ) - assert metadata_page.first_selected_subject.text == 'Engineering' + assert ( + utils.clean_text(metadata_page.first_selected_subject.text) == 'Engineering' + ) metadata_page.tags_input_box.click() metadata_page.tags_input_box.send_keys('selenium\r') @@ -627,7 +618,7 @@ def test_submit_no_project_registration( metadata_page.next_page_button.click() summary_page = DraftRegistrationSummaryPage(driver, verify=True) - assert summary_page.page_heading.text == 'Summary' + assert utils.clean_text(summary_page.page_heading.text) == 'Summary' summary_page.summary_textbox.click() summary_page.summary_textbox.send_keys_deliberately( @@ -641,15 +632,18 @@ def test_submit_no_project_registration( review_page = DraftRegistrationReviewPage(driver, verify=True) review_page.loading_indicator.here_then_gone() - assert review_page.title.text == 'Selenium Test No Project Registration' assert ( - review_page.description.text + utils.clean_text(review_page.title.text) + == 'Selenium Test No Project Registration' + ) + assert ( + utils.clean_text(review_page.description.text) == 'This is a test registration created using Selenium.' ) - assert review_page.category.text == 'Software' - assert review_page.license.text == 'CC0 1.0 Universal' - assert review_page.subject.text == 'Engineering' - assert review_page.tags.text == 'selenium' + # assert utils.clean_text(review_page.category.text) == 'Software' + assert utils.clean_text(review_page.license.text) == 'CC0 1.0 Universal' + assert utils.clean_text(review_page.subject.text) == 'Engineering' + assert utils.clean_text(review_page.tags.text) == 'selenium' review_page.register_button.click() @@ -774,6 +768,7 @@ def verify_download_link(self, driver, page, file_name, wait_selector): 'browserstack_executor: {"action": "fileExists", "arguments": {"fileName": "%s"}}' % (file_name) ) + # Next get the file properties and then verify that the file creation date # is today file_props = driver.execute_script( @@ -804,7 +799,7 @@ def test_files_list_page(self, driver, files_list_page): self.verify_embed_links(files_list_page) # Get file name of first file listed - file_name = files_list_page.first_file_name.text + file_name = utils.clean_text(files_list_page.first_file_name.text) # Verify file download self.verify_download_link( @@ -822,7 +817,7 @@ def test_file_detail_page(self, driver, files_list_page): WebDriverWait(driver, 5).until(EC.number_of_windows_to_be(2)) # Switch focus to the new tab - driver.switch_to.window(driver.window_handles[1]) + utils.switch_to_new_tab(driver) file_detail_page = RegistrationFileDetailPage(driver, verify=True) # Wait for File Renderer to load @@ -836,7 +831,7 @@ def test_file_detail_page(self, driver, files_list_page): if settings.DRIVER != 'Remote': # Can't access clipboard on remote machine self.verify_embed_links(file_detail_page) - file_name = file_detail_page.file_name.text + file_name = utils.clean_text(file_detail_page.file_name.text) # Verify file download self.verify_download_link(driver, file_detail_page, file_name, 'iframe') diff --git a/tests/test_search.py b/tests/test_search.py index 50a61930..0af7b74f 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -5,6 +5,7 @@ from selenium.webdriver.support.ui import WebDriverWait import markers +import utils from pages.search import SearchPage @@ -43,7 +44,11 @@ def test_search_results_exist_projects_tab(self, driver, search_page): ) assert len(search_page.search_results) > 0 # Verify that first search result is of Project type - assert search_page.first_card_object_type_label.text[:7] == 'PROJECT' + # assert search_page.first_card_object_type_label.text[:7] == 'PROJECT' + assert ( + 'PROJECT' + in utils.clean_text(search_page.first_card_object_type_label.text).upper() + ) def test_search_results_exist_registrations_tab(self, driver, search_page): search_page.search_input.send_keys('test') @@ -59,7 +64,10 @@ def test_search_results_exist_registrations_tab(self, driver, search_page): ) assert len(search_page.search_results) > 0 # Verify that first search result is of Registration type - assert search_page.first_card_object_type_label.text[:12] == 'REGISTRATION' + assert ( + utils.clean_text(search_page.first_card_object_type_label.text.upper()) + == 'REGISTRATION' + ) def test_search_results_exist_preprints_tab(self, driver, search_page): search_page.search_input.send_keys('test') @@ -75,7 +83,10 @@ def test_search_results_exist_preprints_tab(self, driver, search_page): ) assert len(search_page.search_results) > 0 # Verify that first search result is of Preprint type - assert search_page.first_card_object_type_label.text == 'PREPRINT' + assert ( + utils.clean_text(search_page.first_card_object_type_label.text.upper()) + == 'PREPRINT' + ) def test_search_results_exist_files_tab(self, driver, search_page): search_page.search_input.send_keys('test') @@ -91,7 +102,10 @@ def test_search_results_exist_files_tab(self, driver, search_page): ) assert len(search_page.search_results) > 0 # Verify that first search result is of File type - assert search_page.first_card_object_type_label.text == 'FILE' + assert ( + utils.clean_text(search_page.first_card_object_type_label.text.upper()) + == 'FILE' + ) def test_search_results_exist_users_tab(self, driver, search_page): search_page.loading_indicator.here_then_gone() @@ -105,4 +119,7 @@ def test_search_results_exist_users_tab(self, driver, search_page): ) assert len(search_page.search_results) > 0 # Verify that first search result is of User type - assert search_page.first_card_object_type_label.text == 'USER' + assert ( + utils.clean_text(search_page.first_card_object_type_label.text.upper()) + == 'USER' + ) diff --git a/tests/test_user.py b/tests/test_user.py index c7ee0a87..187600a6 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -11,6 +11,7 @@ import components.email_access as EmailAccess import markers import settings +import utils from api import osf_api from pages import user @@ -210,7 +211,9 @@ def test_user_account_settings_storage_locations(self, driver, session): # matches the storage location region that is displayed as selected in the # listbox user_region = osf_api.get_user_region_name(session) - assert settings_page.storage_location_listbox.text == user_region + assert ( + utils.clean_text(settings_page.storage_location_listbox.text) == user_region + ) # Click the listbox to display all of the storage locations and get a list # of the displayed regions @@ -219,7 +222,9 @@ def test_user_account_settings_storage_locations(self, driver, session): By.CSS_SELECTOR, 'div.ember-basic-dropdown-content-wormhole-origin > div > ul > li', ) - listbox_regions = sorted([region.text for region in listbox_items]) + listbox_regions = sorted( + [utils.clean_text(region.text) for region in listbox_items] + ) # Get available regions using the api and verify that the lists match regions_data = osf_api.get_regions_data(session) @@ -236,9 +241,7 @@ def test_user_account_settings_delete_affiliated_institution(self, driver, sessi settings_page = user.AccountSettingsPage(driver) settings_page.goto() assert user.AccountSettingsPage(driver, verify=True) - settings_page.scroll_into_view( - settings_page.first_affiliated_institution.element - ) + settings_page.scroll_into_view(settings_page.affiliation_help_text.element) # Click the Delete button to the far right of the first affiliated institution. # On the Delete modal, first click the Cancel button and verify that the @@ -254,7 +257,10 @@ def test_user_account_settings_delete_affiliated_institution(self, driver, sessi settings_page.delete_aff_inst_modal.delete_button.click() settings_page.loading_indicator.here_then_gone() settings_page.first_affiliated_institution.absent() - assert settings_page.no_affiliations_message.text == 'You have no affiliations.' + assert ( + utils.clean_text(settings_page.no_affiliations_message.text) + == 'You have no affiliations.' + ) def test_user_account_settings_update_password(self, driver, session): """Test the Change password section on the User Account Settings page in OSF. @@ -271,17 +277,17 @@ def test_user_account_settings_update_password(self, driver, session): assert settings_page.old_password_error_message.present() assert ( - settings_page.old_password_error_message.text + utils.clean_text(settings_page.old_password_error_message.text) == "This field can't be blank." ) assert settings_page.new_password_error_message.present() assert ( - settings_page.new_password_error_message.text + utils.clean_text(settings_page.new_password_error_message.text) == "This field can't be blank." ) assert settings_page.confirm_password_error_message.present() assert ( - settings_page.confirm_password_error_message.text + utils.clean_text(settings_page.confirm_password_error_message.text) == "This field can't be blank." ) @@ -297,7 +303,7 @@ def test_user_account_settings_enable_2fa(self, driver, session): # Scroll down to the Security settings section near the bottom of the page and # click the Configure button - settings_page.scroll_into_view(settings_page.configure_2fa_button.element) + settings_page.scroll_into_view(settings_page.two_factor_help.element) settings_page.configure_2fa_button.click() # On the Configure 2FA Modal, first click the Cancel button and verify that the @@ -343,7 +349,7 @@ def test_user_account_settings_deactivate_account(self, driver, session): # Verify that the account pending deactivation message is now displayed assert settings_page.pending_deactivation_message.present() assert ( - settings_page.pending_deactivation_message.text + utils.clean_text(settings_page.pending_deactivation_message.text) == 'Your account is currently pending deactivation.' ) @@ -354,7 +360,7 @@ def test_user_account_settings_deactivate_account(self, driver, session): settings_page.undo_deactivation_modal.cancel_button.click() assert settings_page.pending_deactivation_message.present() assert ( - settings_page.pending_deactivation_message.text + utils.clean_text(settings_page.pending_deactivation_message.text) == 'Your account is currently pending deactivation.' ) @@ -452,7 +458,10 @@ def test_user_settings_create_dev_app(self, driver, session, fake): # Click the Show client secret button to unveil the client secret and verify # the text on the button has changed to 'Hide client secret' edit_page.show_client_secret_button.click() - assert edit_page.show_client_secret_button.text == 'Hide client secret' + assert ( + utils.clean_text(edit_page.show_client_secret_button.text) + == 'Hide client secret' + ) assert edit_page.client_secret_input.get_attribute('value') == client_secret edit_page.scroll_into_view(edit_page.app_name_input.element) assert edit_page.app_name_input.get_attribute('value') == app_name @@ -689,7 +698,10 @@ def test_user_settings_edit_dev_app(self, driver, session, fake): # Click the Show client secret button to unveil the client secret and verify # the text on the button has changed to 'Hide client secret' edit_page.show_client_secret_button.click() - assert edit_page.show_client_secret_button.text == 'Hide client secret' + assert ( + utils.clean_text(edit_page.show_client_secret_button.text) + == 'Hide client secret' + ) assert edit_page.client_secret_input.get_attribute('value') == client_secret edit_page.scroll_into_view(edit_page.app_name_input.element) assert edit_page.app_name_input.get_attribute('value') == new_app_name diff --git a/utils.py b/utils.py index 263ceb75..84f7f9fa 100644 --- a/utils.py +++ b/utils.py @@ -95,7 +95,6 @@ def launch_driver(driver_name=settings.DRIVER, desired_capabilities=None): driver = driver_cls(options=ffo) elif driver_name == 'Edge' and not settings.HEADLESS: driver = webdriver.Edge() - else: driver = driver_cls() @@ -203,3 +202,10 @@ def read_data_from_table(driver, table_path, check_match, item_match=None): return i, datalist return rlen, datalist + + +def clean_text(stringvalue): + clean_text = stringvalue.strip() + clean_text = clean_text.replace('\n', ' ') + clean_text = ' '.join(clean_text.split()) + return clean_text