def generic_language_switcher_should_be_set_to(context: Context, language: str): language_code = Language[language.upper()].value with assertion_msg("Required dictionary with page views is missing"): assert hasattr(context, "views") views = context.views page_names = ( [row["page"] for row in context.table] if context.table else views.keys() ) results = defaultdict() for page_name in page_names: response = views[page_name] content = response.content.decode("utf-8") check_for_errors(content, response.url) selector = f"#great-header-language-select option[selected]::attr(value)" selected_language_switcher_option = ( Selector(text=content).css(selector).extract() ) error = f"Couldn't find language switcher on {response.url}" with assertion_msg(error): assert selected_language_switcher_option selected_language_switcher_option = selected_language_switcher_option[0] results[page_name] = selected_language_switcher_option logging.debug(f"Selected language in Language Switcher on: {dict(results)}") undetected_languages = { page: selected_language_switcher_option for page, selected_language_switcher_option in results.items() if language_code not in selected_language_switcher_option } with assertion_msg( f"'{language}' was not selected in Language Switcher for following pages: {undetected_languages}" ): assert not undetected_languages
def fas_should_see_filtered_search_results(context: Context, actor_alias: str): results = context.results sector_filters_selector = "#id_sectors input" for industry, result in results.items(): context.response = result["response"] content = result["response"].content.decode("utf-8") filters = Selector(text=content).css(sector_filters_selector).extract() for filter in filters: sector = Selector(text=filter).css("input::attr(value)").extract()[0] input = Selector(text=filter).css("input::attr(checked)").extract() checked = True if input else False if sector in result["sectors"]: with assertion_msg( "Expected search results to be filtered by '%s' sector" " but this filter was not checked!" ): assert checked else: with assertion_msg( "Expected search results to be filtered only by " "following sectors '%s', but they are also filtered " "by '%s'!", ", ".join(result["sectors"]), sector, ): assert not checked logging.debug( "%s was presented with '%s' industry search results correctly " "filtered by following sectors: '%s'", actor_alias, industry, ", ".join(result["sectors"]), )
def generic_page_language_should_be_set_to(context: Context, language: str): language_code = Language[language.upper()].value with assertion_msg("Required dictionary with page views is missing"): assert hasattr(context, "views") views = context.views page_names = ( [row["page"] for row in context.table] if context.table else views.keys() ) results = defaultdict() for page_name in page_names: response = views[page_name] content = response.content.decode("utf-8") check_for_errors(content, response.url) html_tag_language = Selector(text=content).css("html::attr(lang)").extract()[0] results[page_name] = html_tag_language logging.debug(f"HTML tag language attributes for: {dict(results)}") undetected_languages = { page: html_tag_lang for page, html_tag_lang in results.items() if language_code not in html_tag_lang } with assertion_msg( f"HTML document language was not set to '{language_code}' in following pages: {undetected_languages}" ): assert not undetected_languages
def fas_should_see_different_png_logo_thumbnail(context: Context, actor_alias: str): """Will check if Company's Logo visible on FAS profile page is the same as the one uploaded on FAB. """ actor = get_actor(context, actor_alias) session = actor.session company = get_company(context, actor.company_alias) fas_logo_url = company.logo_url # Step 1 - Go to the FAS profile page & extract URL of visible logo image response = fas.profile.go_to(session, company.number) context.response = response fas.profile.should_be_here(response) visible_logo_url = extract_logo_url(response) placeholder = FAS_LOGO_PLACEHOLDER_IMAGE with assertion_msg( "Expected company logo but got image placeholder", visible_logo_url ): assert visible_logo_url != placeholder with assertion_msg( "Expected to see other logo thumbnail than the previous one '%s'.", visible_logo_url, ): assert visible_logo_url != fas_logo_url with assertion_msg("Expected PNG logo thumbnail, but got: %s", visible_logo_url): assert visible_logo_url.lower().endswith(".png")
def sso_should_be_signed_in_to_sso_account(context: Context, supplier_alias: str): response = context.response with assertion_msg( "Response doesn't contain 'Sign out' button. It looks " "like user is not logged in" ): assert "Sign out" in response.content.decode("utf-8") error = f"Missing response history in SSO login request!" assert response.history, error intermediate_headers = [] for r in response.history: dev_session = r.cookies.get("directory_sso_dev_session", None) stage_session = r.cookies.get("sso_stage_session", None) sso_display_logged_in = r.cookies.get("sso_display_logged_in", None) cookies = { "url": r.url, "location": r.headers.get("location", None), "sso_session": dev_session or stage_session, "sso_display_logged_in": sso_display_logged_in, } intermediate_headers.append(cookies) logging.debug(f"SSO session cookie history: {intermediate_headers}") with assertion_msg( "Expected to see following SSO Session cookies to be set in intermediate " "responses: sso_display_logged_in=true and directory_sso_dev_session or " "sso_stage_session. It looks like user did not log in successfully!" ): assert all( cookies["sso_display_logged_in"] == "true" for cookies in intermediate_headers ) logging.debug("%s is logged in to the SSO account", supplier_alias)
def should_not_see_online_profiles(response: Response): content = response.content.decode("utf-8").lower() with assertion_msg("Found a link to 'visit Facebook' profile"): assert "visit company facebook" not in content with assertion_msg("Found a link to 'visit LinkedIn' profile"): assert "visit company linkedin" not in content with assertion_msg("Found a link to 'visit Twitter' profile"): assert "visit company twitter" not in content
def should_see_details(company: Company, response: Response, table_of_details: Table): """Supplier should see all expected Company details of FAS profile page. :param company: a namedtuple with Company details :param response: a response object :param table_of_details: a table of expected company details """ visible_details = [row["detail"] for row in table_of_details] content = extract_page_contents(response.content.decode("utf-8")).lower() title = DETAILS["NAME"] in visible_details keywords = DETAILS["KEYWORDS"] in visible_details website = DETAILS["WEBSITE"] in visible_details size = DETAILS["SIZE"] in visible_details sector = DETAILS["SECTOR"] in visible_details if title: with assertion_msg("Couldn't find Company's title '%s'", company.title): assert company.title.lower() in content logging.debug(f"Found title: '{company.title}' on: {response.url}") if keywords: for keyword in company.keywords.split(", "): with assertion_msg("Couldn't find Company's keyword '%s'", keyword): assert keyword.strip().lower() in content logging.debug( f"Found keywords: '{company.keywords}' on: {response.url}") if website: with assertion_msg("Couldn't find Company's website '%s'", company.website): assert company.website.lower() in content logging.debug(f"Found website: '{company.website}' on: {response.url}") if size: with assertion_msg( "Couldn't find the size of the company '%s' in the response", company.no_employees, ): if company.no_employees == "10001+": assert "10,001+" in content elif company.no_employees == "1001-10000": assert "1,001-10,000" in content elif company.no_employees == "501-1000": assert "501-1,000" in content else: assert company.no_employees in content logging.debug( f"Found size: '{company.no_employees}' on: {response.url}") if sector: with assertion_msg( "Couldn't find company's sector '%s' in the response", SECTORS_WITH_LABELS[company.sector], ): assert SECTORS_WITH_LABELS[company.sector].lower() in content logging.debug(f"Found sector: '{company.sector}' on: {response.url}") logging.debug(f"Found all expected details on: {response.url}")
def should_be_logged_out(response: Response): """Check if Supplier is logged out by checking the cookies.""" with assertion_msg( "Found sso_display_logged_in cookie in the response. Maybe user is" " still logged in?"): assert "sso_display_logged_in" not in response.cookies with assertion_msg( "Found directory_sso_dev_session cookie in the response. Maybe " "user is still logged in?"): assert "directory_sso_dev_session" not in response.cookies
def should_not_see_links_to_online_profiles(response: Response): content = response.content.decode("utf-8").lower() with assertion_msg("Found a link to Facebook profile"): assert "add facebook" in content with assertion_msg("Found a link to LinkedIn profile"): assert "add linkedin" in content with assertion_msg("Found a link to Twitter profile"): assert "add twitter" in content logging.debug( "Supplier cannot see links to any Online Profile on FAB " "Company's Directory Profile Page" )
def should_see_errors( response: Response, *, facebook=True, linkedin=True, twitter=True ): content = response.content.decode("utf-8") if facebook: with assertion_msg("Could't find link to Facebook profile"): assert "Please provide a link to Facebook." in content if linkedin: with assertion_msg("Could't find link to LinkedIn profile"): assert "Please provide a link to LinkedIn." in content if twitter: with assertion_msg("Could't find link to Twitter profile"): assert "Please provide a link to Twitter." in content
def should_see_online_profiles(company: Company, response: Response): content = response.content.decode("utf-8") if company.facebook: with assertion_msg("Couldn't find link to company's Facebook profile"): assert "Visit company Facebook" in content assert company.facebook in content if company.linkedin: with assertion_msg("Couldn't find link to company's LinkedIn profile"): assert "Visit company LinkedIn" in content assert company.linkedin in content if company.twitter: with assertion_msg("Couldn't find link to company's Twitter profile"): assert "Visit company Twitter" in content assert company.twitter in content
def check_url(response: Response, expected_url: str, *, startswith: bool = False): # avoid circular imports from tests.functional.utils.generic import assertion_msg if startswith: error = ( f"Expected response URL to start with {expected_url} but got " f"{response.url} instead" ) with assertion_msg(error): assert response.url.startswith(expected_url) else: error = f"Expected {expected_url} but got {response.url} instead" with assertion_msg(error): assert response.url == expected_url
def should_see_online_profiles(company: Company, response: Response): content = response.content.decode("utf-8") if company.facebook: with assertion_msg("Couldn't find link to company's Facebook profile"): assert company.facebook in content if company.linkedin: with assertion_msg("Couldn't find link to company's LinkedIn profile"): assert company.linkedin in content if company.twitter: with assertion_msg("Couldn't find link to company's Twitter profile"): assert company.twitter in content logging.debug( "Supplier can see all expected links to Online Profiles on " "FAB Company's Directory Profile Page" )
def fas_should_see_highlighted_search_term( context: Context, actor_alias: str, search_term: str ): response = context.response content = response.content.decode("utf-8") search_summaries_selector = "#companies-column div.width-full.details-container" summaries = Selector(text=content).css(search_summaries_selector).extract() tag = "em" keywords = [surround(keyword, tag) for keyword in search_term.split()] founds = [] for summary in summaries: founds += [(keyword in summary) for keyword in keywords] with assertion_msg( f"Expected to see at least 1 search result with highlighted search " f"term: '{', '.join(keywords)}'" ): assert any(founds) logging.debug( "{alias} found highlighted search {term}: '{keywords}' {founds} " "{times} in {results} search results".format( alias=actor_alias, term="terms" if len(keywords) > 1 else "term", keywords=", ".join(keywords), founds=len([f for f in founds if f]), times="times" if len([f for f in founds if f]) > 1 else "time", results=len(summaries), ) )
def should_be_here( response: Response, *, user_added: bool = False, owner_transferred: bool = False, user_removed: bool = False, ): """Check if Supplier is on Profile 'Find a Buyer' page. NOTE: Supplier has to be logged in to get to this page. """ check_response(response, 200, body_contains=EXPECTED_STRINGS) expected_query = None expected_strings = None if user_added: expected_query = "?user-added" expected_strings = EXPECTED_STRINGS_USER_ADDED if owner_transferred: expected_query = "?owner-transferred" expected_strings = EXPECTED_STRINGS_OWNER_TRANSFERRED if user_removed: expected_query = "?user-removed" expected_strings = EXPECTED_STRINGS_USER_REMOVED if expected_strings: error = (f"Expected to see '{expected_query}' in the URL but got: " f"'{response.url}' instead") with assertion_msg(error): assert expected_query in response.url check_response(response, 200, body_contains=expected_strings) logging.debug("Successfully got to the Profile 'Find a Buyer' page")
def should_see_message(context: Context, actor_alias: str, message: str): content = context.response.content.decode("utf-8") with assertion_msg( "Response content doesn't contain expected message: '%s'", message ): assert message in content logging.debug("%s saw expected message: '%s'", actor_alias, message)
def fas_should_see_company_once_in_search_results( context: Context, actor_alias: str, company_alias: str ): company = get_company(context, company_alias) results = context.results founds = [ (page, result["found"]) for page, result in results.items() if result["found"] ] with assertion_msg( "Expected to see company '%s' only once on first %d search result " "pages but found it %d times. On pages: %s", company.title, len(results), len(founds), founds, ): assert len(founds) == 1 logging.debug( "As expected %s found company '%s' (%s) only once on first %d search " "result pages", actor_alias, company.title, company_alias, len(results) + 1, )
def profile_should_see_expected_error_messages(context: Context, supplier_alias: str): results = context.results assertion_results = [] for company, response, error in results: if error not in response.content.decode("utf-8"): context.response = response logging.debug(f"Modified company's details: {company}") logging.debug(f"Expected error message: {error}") logging.debug( f"Response: {extract_page_contents(response.content.decode('utf-8'))}" ) assertion_results.append((response, error)) formatted_message = ";\n\n".join( [ f"'{error}' in response from '{response.url}':\n" f"'{extract_page_contents(response.content.decode('utf-8'))}'" for response, error in assertion_results ] ) with assertion_msg( f"Expected to see correct error messages, but couldn't find them in" f" following responses: {formatted_message}" ): assert not assertion_results logging.debug("%s has seen all expected form errors", supplier_alias)
def should_not_see_message(context: Context, actor_alias: str, message: str): content = context.response.content.decode("utf-8") with assertion_msg(f"Response content contains unexpected message: '{message}'"): assert message not in content logging.debug( f"As expected {actor_alias} haven't seen unexpected message: '{message}'" )
def isd_should_see_unfiltered_search_results(context: Context, actor_alias: str): response = context.response content = response.content.decode("utf-8") sector_filters_selector = "#filter-column input[type=checkbox]" filters = Selector(text=content).css(sector_filters_selector).extract() with assertion_msg(f"Couldn't find filter checkboxes on {response.url}"): assert filters for filter in filters: sector = Selector(text=filter).css("input::attr(value)").extract()[0] selector = "input::attr(checked)" checked = True if Selector(text=filter).css(selector).extract() else False with assertion_msg( "Expected search results to be unfiltered but this " "filter was checked: '%s'", sector, ): assert not checked logging.debug("%s was shown with unfiltered search results", actor_alias)
def should_see_details(company: Company, response: Response, table_of_details: Table): """Supplier should see all expected Company details of Profile page.""" visible_details = [row["detail"] for row in table_of_details] content = response.content.decode("utf-8") title = DETAILS["NAME"] in visible_details keywords = DETAILS["KEYWORDS"] in visible_details website = DETAILS["WEBSITE"] in visible_details size = DETAILS["SIZE"] in visible_details sector = DETAILS["SECTOR"] in visible_details if title: with assertion_msg( "Couldn't find company's title '%s' in the response", company.title ): assert company.title in content if keywords: for keyword in company.keywords.split(", "): with assertion_msg("Couldn't find keyword '%s' in the response", keyword): assert escape_html(keyword.strip()) in content if website: with assertion_msg( "Couldn't find company's website '%s' in the response", company.website ): assert company.website in content if size: with assertion_msg( "Couldn't find the size of the company '%s' in the response", company.no_employees, ): if company.no_employees == "10001+": assert "10,001+" in content elif company.no_employees == "1001-10000": assert "1,001-10,000" in content elif company.no_employees == "501-1000": assert "501-1,000" in content else: assert company.no_employees in content if sector: with assertion_msg( "Couldn't find company's sector '%s' in the response", SECTORS_WITH_LABELS[company.sector], ): assert SECTORS_WITH_LABELS[company.sector].lower() in content.lower()
def fas_should_find_all_sought_companies(context: Context, buyer_alias: str): """Check if Buyer was able to find Supplier using all provided terms.""" with assertion_msg( "Context has no required `search_details` dict. Please check if " "one of previous steps sets it correctly." ): assert hasattr(context, "search_results") logging.debug(context.search_results) for company, results in context.search_results.items(): for result in results: term = result["term"] term_type = result["type"] context.response = result["response"] with assertion_msg( "%s could not find Supplier '%s' using '%s' term '%s'", buyer_alias, company, term_type, term, ): assert result["found"]
def fas_should_see_png_logo_thumbnail(context: Context, supplier_alias: str): """Will check if Company's PNG thumbnail logo visible on FAS profile.""" actor = get_actor(context, supplier_alias) session = actor.session company = get_company(context, actor.company_alias) # Step 1 - Go to the FAS profile page & extract URL of visible logo image response = fas.profile.go_to(session, company.number) context.response = response fas.profile.should_be_here(response) visible_logo_url = extract_logo_url(response) placeholder = FAS_LOGO_PLACEHOLDER_IMAGE with assertion_msg( "Expected company logo but got image placeholder '%s'", visible_logo_url ): assert visible_logo_url != placeholder with assertion_msg("Expected PNG logo thumbnail, but got: %s", visible_logo_url): assert visible_logo_url.lower().endswith(".png") set_company_logo_detail(context, actor.company_alias, url=visible_logo_url) logging.debug("Set Company's logo URL to: %s", visible_logo_url)
def fab_should_see_case_study_error_message(context: Context, supplier_alias: str): results = context.results logging.debug(results) for field, value_type, case_study, response, error in results: context.response = response with assertion_msg( "Could not find expected error message: '%s' in the response, " "after submitting the add case study form with '%s' value " "being '%s' following and other details: '%s'", error, field, value_type, case_study, ): assert error in response.content.decode("utf-8") logging.debug("%s has seen all expected case study errors", supplier_alias)
def profile_all_unsupported_files_should_be_rejected( context: Context, supplier_alias: str ): """Check if all unsupported files were rejected upon upload as company logo NOTE: This require `context.rejections` to be set. It should be a list of bool values. """ assert hasattr(context, "rejections") with assertion_msg( "Some of the uploaded files that should be marked as unsupported " "were actually accepted. Please check the logs for more details" ): assert all(context.rejections) logging.debug(f"All files of unsupported types uploaded by %s were rejected")
def fas_supplier_cannot_be_found_using_case_study_details( context: Context, buyer_alias: str, company_alias: str, case_alias: str ): actor = get_actor(context, buyer_alias) session = actor.session company = get_company(context, company_alias) case_study = company.case_studies[case_alias] keys = SEARCHABLE_CASE_STUDY_DETAILS search_terms = {} for key in keys: if key == "keywords": for index, keyword in enumerate(case_study.keywords.split(", ")): search_terms[f"keyword #{index}"] = keyword else: search_terms[key] = getattr(case_study, key) logging.debug( "Now %s will try to find '%s' using following search terms: %s", buyer_alias, company.title, search_terms, ) for term_name in search_terms: term = search_terms[term_name] logging.debug( "Searching for '%s' using %s: %s", company.title, term_name, search_terms ) response = fas.search.go_to(session, term=term) context.response = response fas.search.should_be_here(response) found = fas.search.should_not_see_company(response, company.title) with assertion_msg( "Buyer found Supplier '%s' on FAS using %s: %s", company.title, term_name, term, ): assert found logging.debug( "Buyer was not able to find unverified Supplier '%s' on FAS using " "%s: %s", company.title, term_name, term, )
def go_to(session: Session, *, term: str = None, page: int = None, **kwargs) -> Response: """Go to "FAS Find a Supplier" page. :param session: Actor's request Session :param term: (optional) search term :param page: (optional) number of search result page :param kwargs: (optional) search filters """ allowed_search_filters = [ "expertise_regions", "expertise_industries", "expertise_languages", "expertise_countries", "expertise_products_services_financial", "expertise_products_services_management", "expertise_products_services_human_resources", "expertise_products_services_legal", "expertise_products_services_publicity", "expertise_products_services_business_support", ] params = {} if term is not None: params.update({"q": term}) if page is not None: params.update({"page": page}) filter_diff = set(kwargs.keys()) - set(allowed_search_filters) with assertion_msg(f"Got unexpected search filters: {filter_diff}"): assert not filter_diff headers = {"Referer": URLs.PROFILE_BUSINESS_PROFILE.absolute} return make_request(Method.GET, URL, session=session, params=params, headers=headers)
def fas_should_find_with_company_details( context: Context, buyer_alias: str, company_alias: str ): """Check if Buyer was able to find Supplier using all selected search terms NOTE: This step requires the search_results dict to be stored in context """ assert hasattr(context, "search_results") company = get_company(context, company_alias) for result in context.search_results: # get response for specific search request. This helps to debug logging.debug(f"Search results: {context.search_results}") context.response = context.search_responses[result] with assertion_msg( "%s wasn't able to find '%s' (alias: %s) using its '%s'", buyer_alias, company.title, company_alias, result, ): assert context.search_results[result]
def open(session: Session, link: str) -> Response: with assertion_msg("Expected a non-empty invitation link"): assert link return make_request(Method.GET, link, session=session)
def generic_content_of_viewed_pages_should_in_selected_language( context: Context, language: str, *, page_part: str = None, probability: float = 0.9 ): """Check if all viewed pages contain content in expected language NOTE: This requires all responses with page views to be stored in context.views :param context: behave `context` object :param language: expected language of the view FAS page content :param page_part: detect language of the whole page or just the main part :param probability: expected probability of expected language """ with assertion_msg("Required dictionary with page views is missing"): assert hasattr(context, "views") views = context.views page_names = ( [row["page"] for row in context.table] if context.table else views.keys() ) if page_part: if page_part == "main": main = True elif page_part == "whole": main = False else: raise KeyError("Please select valid part of the page: main or whole") else: main = False if language.lower() == "chinese": expected_language_code = "zh-cn" elif language.lower() == "english": expected_language_code = "en" else: expected_language_code = Language[language.upper()].value results = defaultdict() for page_name in page_names: response = views[page_name] content = response.content.decode("utf-8") check_for_errors(content, response.url) logging.debug(f"Detecting the language of '{page_name}'' page {response.url}") lang_detect_results = detect_page_language(page_name, "", content, main=main) median_results = { language: median(probabilities) for language, probabilities in lang_detect_results.items() } results[page_name] = median_results undetected_languages = { page: medians for page, medians in results.items() if expected_language_code not in medians } with assertion_msg( f"Could not detect '{expected_language_code}' in page content on following pages: {undetected_languages}" ): assert not undetected_languages unmet_probabilities = { page: medians for page, medians in results.items() if medians[expected_language_code] < probability } with assertion_msg( f"Median '{expected_language_code}' language detection probability of " f"{probability} was not met on following pages: {unmet_probabilities}" ): assert not unmet_probabilities