import logging import unittest from contextlib import suppress import allure import pytest from assertpy import assert_that from faker import Faker from requests import HTTPError from ui_automation_framework.utils import CoreConfig from ui_automation_framework.utils import logger as cl from app.src.api.facade import ApiClient from app.src.api.models.auth_model import AuthData from app.src.helpers.api_data_provider import ApiDataProvider from app.src.pages.login_page import LoginPage from app.src.pages.search_page import SearchPage from app.src.pages.starred_page import StarredPage from app.src.pages.track_page import TrackPage @pytest.mark.usefixtures("set_up", "one_time_set_up", "authorized_api") class GlobalSearchTest(unittest.TestCase): log = cl.Logger(logging.DEBUG) @pytest.fixture(autouse=True) def classSetup(self, authorized_api): self.api = authorized_api self.loginPage = LoginPage(self.driver, authorized_api) self.searchPage = SearchPage(self.driver, authorized_api) self.trackPage = TrackPage(self.driver, authorized_api) self.starredPage = StarredPage(self.driver, authorized_api) self.data_provider = ApiDataProvider(authorized_api) self.fake = Faker() self.notification_api = ApiClient() self.notification_api.authorize(AuthData(CoreConfig.NOTIFICATIONS_EMAIL, CoreConfig.NOTIFICATIONS_PASSWORD)) @allure.story("https://data-analytics.atlassian.net/browse/AG-4869") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Focus on the search field") @allure.description("USer should be able to see keyboard and recent searches") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-369") @pytest.mark.smoke def test_focusing_on_search_field(self): self.loginPage.login_as_regular_user() self.searchPage.click_search_field() assert_that(self.driver.is_keyboard_shown(), "Keyboard is presented").is_true() assert_that(self.searchPage.is_recent_search_displayed(), "Recent search is displayed").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-4869") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Search results according to the search query") @allure.description("Search results should be relevant to the search query") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-370") @pytest.mark.smoke def test_search_results_accordingly_to_query(self): search_query = self.fake.word() new_query = self.fake.word() self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) results = self.searchPage.get_result_track_title_full(1) assert_that(results.lower()).described_as("Search result includes query").contains(search_query) self.searchPage.update_search_query(new_query) new_results = self.searchPage.get_result_track_title_full(1) assert_that(new_results.lower()).described_as("Search result includes query").contains(new_query) @allure.story("https://data-analytics.atlassian.net/browse/AG-4869") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Scrolling through search results") @allure.description("Search results are uploading when user in the bottom of the screen proceeds scrolling") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-371") @pytest.mark.smoke def test_search_results_scroll(self): search_query = "Love" self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query).scroll_down_search_results() assert_that(self.searchPage.is_track_scrolled(), "Track is scrolled").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-4869") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Navigation to Track screen via clicking on search result") @allure.description("User should be able to open relevant track from the search results") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-371") @pytest.mark.smoke def test_track_opening(self): search_query = self.fake.word() self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) first_track_name = self.searchPage.get_result_track_title(1) self.searchPage.open_track_page_from_results(1) assert_that(self.trackPage.is_track_page_opened(first_track_name), "Track page was successfully opened").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-4869") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Starring track on Search screen") @allure.description("User should be able to star/un-star track on search results screen") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-375") @pytest.mark.smoke def test_star_track_on_search(self): search_query = self.fake.word() self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) search_track_name = self.searchPage.get_result_track_title(2) self.searchPage.swipe_track_on_search_results(2).star_on_search_results(2).select_starred_tracks_tab() assert_that(self.starredPage.is_track_starred(search_track_name), "Verified track is added to the starred tracks screen").is_true() self.starredPage.select_search_tab() self.searchPage.search_for(search_query).swipe_track_on_search_results(2).unstar_on_search_results(2).select_starred_tracks_tab() assert_that( self.starredPage.is_track_unstarred(search_track_name), "Verified track is removed from the starred tracks screen", ).is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("No search results") @allure.description("Appropriate message should be shown") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-372") @pytest.mark.regression def test_no_search_results(self): search_query = "zzzzz123" self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) assert_that(self.searchPage.is_no_results_shown(), "No results message is displayed").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Search for starred track") @allure.description("Starred track should be marked with star in results") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-386") @pytest.mark.regression def test_search_starred_tracks(self): search_query = "Self Esteem" track = self.notification_api.apollo.get_list_of_spotify_tracks(search_query)["body"]["tracks"]["items"][0] with suppress(HTTPError): self.notification_api.apollo.post_v1_starred_tracks(track["external_ids"]["isrc"], track["uri"]) self.loginPage.login_as_notifications_user() self.searchPage.search_for(search_query) assert_that(self.searchPage.is_track_starred(search_query), "Verified track is shown with starred icon").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Cancellation of starring track") @allure.description("User should be able to open another track even is starring icon shown for different tracks") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-377" "https://data-analytics.atlassian.net/browse/AG-378") @pytest.mark.regression def test_starring_cancellation(self): search_query = "Love" self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) track_1 = self.searchPage.get_result_track_title_full(1) track_1_title = self.searchPage.get_result_track_title(1) track_2 = self.searchPage.get_result_track_title_full(2) self.searchPage.swipe_track_on_search_results(1) assert_that(self.searchPage.is_star_icon_displayed(track_1), "Verified star icon is displayed").is_true() self.searchPage.swipe_right_track_on_search_results(1) assert_that(self.searchPage.is_star_icon_closed(track_1), "Verified star icon is NOT displayed").is_true() self.searchPage.swipe_track_on_search_results(1) assert_that(self.searchPage.is_star_icon_displayed(track_1), "Verified star icon is displayed").is_true() self.searchPage.swipe_track_on_search_results(2) assert_that(self.searchPage.is_star_icon_closed(track_1), "Verified star icon is NOT displayed").is_true() assert_that(self.searchPage.is_star_icon_displayed(track_2), "Verified star icon is displayed").is_true() self.searchPage.open_track_page_from_results(2) assert_that(self.searchPage.is_star_icon_closed(track_2), "Verified star icon is NOT displayed").is_true() self.searchPage.open_track_page_from_results(1) assert_that(self.trackPage.is_track_page_opened(track_1_title), "Verified appropriate track page is opened").is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Search initiates after 2 entered chars") @allure.description("Search is initiated only after entering ≥2 symbols") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-407") @pytest.mark.regression def test_search_after_two_chars_entered(self): search_query = "lo" self.loginPage.login_as_regular_user() self.searchPage.search_for(search_query) results = self.searchPage.get_result_track_title_full(1).lower() assert_that(results).described_as("Search result includes query").contains(search_query) @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Paste to the search") @allure.description("User should be able to paste search from clipboard") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-734") @pytest.mark.regression def test_paste_query_from_clipboard(self): self.loginPage.login_as_regular_user() self.searchPage.set_clipboard("love").search_for(self.searchPage.get_clipboard()) results = self.searchPage.get_result_track_title_full(1).lower() assert_that(results).described_as("Search result includes the search query").contains(self.searchPage.get_clipboard()) @allure.story("https://data-analytics.atlassian.net/browse/AG-6512") @allure.severity(allure.severity_level.CRITICAL) @allure.title("No duplicates") @allure.description("No duplicated tracks should be in the test result") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-2134") @pytest.mark.regression def test_no_duplicates(self): query = "Thriller" tracks_from_api = self.data_provider.get_search_results_api(query) self.loginPage.login_as_regular_user() self.searchPage.search_for(query) results_ui = self.searchPage.get_search_results() assert_that( self.searchPage.are_no_duplicates_in_results(results_ui, tracks_from_api), "Search results shown without duplicates", ).is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-7447") @allure.severity(allure.severity_level.NORMAL) @allure.title("Global search API/UI integration") @allure.description("API and UI data for global search list should match") @pytest.mark.smoke def test_global_search_api_integration(self): query = "Strung Out" api_data = self.api.dsp.search_tracks(f"q={query}", "limit=20", "offset=0")["body"]["tracks"]["items"] self.loginPage.login_as_regular_user() self.searchPage.search_for(query) ui_data = self.searchPage.get_search_results() for i in range(len(api_data)): # We can see a list of artists/names in API and not sure about logic of what should go on UI assert_that( any(api_data[i]["artists"][0]["name"] in element for element in ui_data), f"Artist name not in recent searches, artist {api_data[i]['artists'][0]['name']} not in" f" {ui_data}", ).is_true() assert_that( any(api_data[i]["name"] in element for element in ui_data), f"Track names don't match, track: {api_data[i]['name']} not in: {ui_data}", ).is_true() @allure.story("https://data-analytics.atlassian.net/browse/AG-8265") @allure.severity(allure.severity_level.CRITICAL) @allure.title("Global search tabs") @allure.description("Default tabs is track") @allure.testcase("https://data-analytics.atlassian.net/browse/AG-7639" "https://data-analytics.atlassian.net/browse/AG-7638") @pytest.mark.regression def test_global_search_tabs(self): query = "love" self.api.authorize() second_track_album_name = self.api.apollo.get_search_results_portal(query, item_type=["track"]).tracks.items[1].album.name self.loginPage.login_as_regular_user() assert_that(self.searchPage.is_tracks_tab_selected(), "Default tab is not tracks").is_true() self.searchPage.search_for(query) results = self.searchPage.get_result_track_title_full(2).lower() if query not in results: assert_that(second_track_album_name.lower(), "Search result includes query").contains(query) self.searchPage.click_playlists_tab() query_text = self.searchPage.get_search_query_text() assert_that(query_text, "Search query wasn't saved").is_equal_to(query) results = self.searchPage.get_result_playlists_title_full(2) assert_that(results).described_as("Search result includes query").contains(query) self.searchPage.close_keyboard_by_swipe() self.searchPage.select_profile_tab().select_search_tab() assert_that(self.searchPage.is_tracks_tab_selected(), "Default tab is not tracks").is_true()