import csv import io import re from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from .base import SearchExportTester class ContactExport(SearchExportTester): """Tests if exporting contacts from a search returns a CSV file with all contacts.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("Contact Export") self.desc( "Testing if exporting contacts from a search returns a CSV file with all expected contacts." ) self.search_url = self.base_url + "/civicrm/contact/search" self.contact_selectall_id = "CIVICRM_QFID_ts_all_4" self.contact_dropdown_id = "select2-chosen-4" self.contact_exportoption_id = "select2-result-label-15" def download_csv(self): # Data of the request that is specific for this export and not genertic like qr_key data = { "_qf_Select_next": "Continue", "exportOption": 1, "mergeOption": 0, "postal_greeting": 1, "addressee": 1, } return self.download(data) def calculate_exported_contacts_number(self) -> int: """ Downloads csv, opens it in a string buffer using StringIO and passes it to the csv lib Counts number of rows (excl. header) and returns that value """ res = self.download_csv() csv_file = io.StringIO(res.text) # Dict reader should remove headers exported_csv = csv.DictReader(csv_file) exported_number_exports = sum(1 for row in exported_csv) self.debug( "found %d rows in exported csv excluding header row" % exported_number_exports ) return exported_number_exports def _test(self, search_term: str): """ Test Description: Go to the contact search url Search for the search term Select all contacts and set them to export Get the login cookie and search ID and download the export manually with requests Save the file in tmp Read it to check the number of exported contacts is the same as reported in the UI """ self.browser.get(self.search_url) search_box = self.find_element_by_id("sort_name") search_box.send_keys(search_term) search_box.send_keys(Keys.ENTER) self.debug("searching for contacts with term '%s'" % search_term) self.wait_until_visible( (By.ID, "alpha-filter") ) #wait for table to load self.debug("table of results has loaded") results_text = self.find_element_by_css_selector( ".form-layout-compressed > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(2) > label:nth-child(2)" ).text matches = re.findall( r"(\d+)", results_text ) # Should just be one match in normal cases result_no = int(matches[0]) self.debug("exporting results using the magic dropdown") self.find_element_by_id(self.contact_selectall_id).click() self.find_element_by_id(self.contact_dropdown_id).click() self.find_element_by_id(self.contact_exportoption_id).click() self.wait_until_visible((By.CSS_SELECTOR, ".crm-block")) exported_number_exports = self.calculate_exported_contacts_number() if exported_number_exports == (result_no): self.passed( "Number of expected contact exports for '%s' matches actual number of exports - Expected: %d, Actual: %d" % (search_term, result_no, exported_number_exports) ) else: self.failed( "Number of expected contact exports for '%s' WAS NOT EQUAL to actual number of exports - Expected: %d, Actual: %d" % (search_term, result_no, exported_number_exports) ) def test_hardcoded_search_terms(self): """Loops over the test with three hardcoded search terms""" search_terms = ("John", "e", "Smith") self._test_all(search_terms)