diff --git a/main.py b/main.py index ee8a45f..da9e5f6 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +import os import re import csv import urllib.parse as urlparse @@ -10,133 +11,151 @@ from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait -BASE_URL = "https://crm-dev.caat.org.uk/" -USERNAME = "roxie" -PASSWORD = "" +class BaseTester: + BASE_URL = "https://crm-dev.caat.org.uk/" + USERNAME = "roxie" + PASSWORD = "" -fireFoxOptions = webdriver.FirefoxOptions() -fireFoxOptions.headless = True -browser = webdriver.Firefox(options=fireFoxOptions) + def __init__(self): + fireFoxOptions = webdriver.FirefoxOptions() + fireFoxOptions.headless = True + self.browser = webdriver.Firefox(options=fireFoxOptions) + self.wait = WebDriverWait(self.browser, 20) + def login(self): + """ Login to civicrm so we can continue with the proper cookies """ + self.browser.get(self.BASE_URL) + username = self.browser.find_element_by_id("edit-name") + password = self.browser.find_element_by_id("edit-pass") + submit = self.browser.find_element_by_id("edit-submit") + username.send_keys(self.USERNAME) + password.send_keys(self.PASSWORD) + submit.click() -def login(): - """ Login to civicrm so we can continue with the proper cookies """ - browser.get(BASE_URL) - username = browser.find_element_by_id("edit-name") - password = browser.find_element_by_id("edit-pass") - submit = browser.find_element_by_id("edit-submit") - username.send_keys(USERNAME) - password.send_keys(PASSWORD) - submit.click() - - wait = WebDriverWait(browser, 20) - # Wait for the js elements load so we know the cookies are good. - wait.until( - EC.visibility_of_element_located( - ( - By.CSS_SELECTOR, - "#widget-6 > div:nth-child(1) > div:nth-child(1) > h3:nth-child(4)" + # Wait for the js elements load so we know the cookies are good. + self.wait.until( + EC.visibility_of_element_located( + ( + By.CSS_SELECTOR, + "#widget-6 > div:nth-child(1) > div:nth-child(1) > h3:nth-child(4)" + ) ) ) - ) - -def test_contactexport(search_term: str): - search_url = "https://crm-dev.caat.org.uk/civicrm/contact/search" - browser.get(search_url) - search_box = browser.find_element_by_id("sort_name") - search_box.send_keys(search_term) - search_box.send_keys(Keys.ENTER) - wait = WebDriverWait(browser, 60) - wait.until( - EC.visibility_of_element_located( - ( - By.ID, - "alpha-filter" #wait for table to load - ) - ) - ) - results_text = browser.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]) - - browser.find_element_by_id("CIVICRM_QFID_ts_all_4").click() - browser.find_element_by_id("select2-chosen-4").click() - browser.find_element_by_id("select2-result-label-15").click() - wait.until( - EC.visibility_of_element_located((By.CSS_SELECTOR, ".crm-block")) - ) - browser.save_screenshot("screenshot.png") - export_page_url = browser.current_url - parsed = urlparse.urlparse(export_page_url) - qf_key = parse_qs(parsed.query)['qfKey'] - - session_cookie = {} - for cookie in browser.get_cookies(): - if re.findall(r"^SSESS.*", cookie.get("name")): - session_cookie = cookie - if not session_cookie: - print("NO SESSION COOKIE FOUND. Are you logged in?") - return - - session = requests.Session() - session.cookies.update({session_cookie["name"]: session_cookie["value"]}) - data = { - "qfKey": qf_key, - "entryURL": "https://crm-dev.caat.org.uk/civicrm/contact/search", - "_qf_Select_next": "Continue", - "exportOption": 1, - "mergeOption": 0, - "postal_greeting": 1, - "addressee": 1, - } - req = session.request( - "POST", - "https://crm-dev.caat.org.uk/civicrm/contact/search", - data=data - ) - with open("tmp.csv", "w") as csv_file: - csv_file.write(req.text) - with open("tmp.csv", "r") as csv_file: - # Dict reader should remove headers - exported_csv = csv.DictReader(csv_file) - exported_number_exports = sum(1 for row in exported_csv) - - if exported_number_exports == (result_no): - print( - "TEST PASSED: Number of expected contact exports for '{}' matches actual number of exports - Expected: {}, Actual: {}" - .format(search_term, result_no, exported_number_exports) - ) - else: - print( - "TEST FAILED: Number of expected contact exports for '{}' WAS NOT EQUAL to actual number of exports - Expected: {}, Actual: {}" - .format(search_term, result_no, exported_number_exports) + def logout(self): + self.browser.get(self.BASE_URL + "/user/logout") + # Wait for the next page to load to finish logging out + self.wait.until( + EC.visibility_of_element_located((By.ID, "tabs-wrapper")) ) - # search > contact > add something in the name thing > select all button > change magic dropdown to export > continue and it will do the download + def find_element_by_id(self, *args, **kwargs): + return self.browser.find_element_by_id(*args, **kwargs) + + def find_element_by_css_selector(self, *args, **kwargs): + return self.browser.find_element_by_css_selector(*args, **kwargs) + + def wait_until_visible(self, locator): + return self.wait.until(EC.visibility_of_element_located(locator)) -def logout(): - wait = WebDriverWait(browser, 20) - browser.get(BASE_URL + "/user/logout") - # Wait for the next page to load to finish logging out - wait.until(EC.visibility_of_element_located((By.ID, "tabs-wrapper"))) +class ContactExport(BaseTester): + def __init__(self): + super().__init__() + self.search_url = "https://crm-dev.caat.org.uk/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): + session_cookie = {} + for cookie in self.browser.get_cookies(): + if re.findall(r"^SSESS.*", cookie.get("name")): + session_cookie = cookie + if not session_cookie: + print("NO SESSION COOKIE FOUND. Are you logged in?") + raise RuntimeError("No session cookie found.") + + session = requests.Session() + session.cookies.update( + {session_cookie["name"]: session_cookie["value"]} + ) + qf_key = self.get_export_id() + data = { + "qfKey": qf_key, + "entryURL": "https://crm-dev.caat.org.uk/civicrm/contact/search", + "_qf_Select_next": "Continue", + "exportOption": 1, + "mergeOption": 0, + "postal_greeting": 1, + "addressee": 1, + } + req = session.request( + "POST", + "https://crm-dev.caat.org.uk/civicrm/contact/search", + data=data + ) + return req + + def calculate_exported_contacts_number(self): + req = self.download_csv() + file_name = "/tmp/exportedRecords.csv" + with open(file_name, "w") as csv_file: + csv_file.write(req.text) + with open(file_name, "r") as csv_file: + # Dict reader should remove headers + exported_csv = csv.DictReader(csv_file) + exported_number_exports = sum(1 for row in exported_csv) + os.remove(file_name) + return exported_number_exports + + def get_export_id(self) -> str: + export_page_url = self.browser.current_url + parsed = urlparse.urlparse(export_page_url) + return parse_qs(parsed.query)['qfKey'] + + def test(self, search_term: str): + try: + self.login() + 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.wait_until_visible( + (By.ID, "alpha-filter") + ) #wait for table to load + + 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.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")) + + req = self.download_csv() + exported_number_exports = self.calculate_exported_contacts_number() + if exported_number_exports == (result_no): + print( + "TEST PASSED: Number of expected contact exports for '{}' matches actual number of exports - Expected: {}, Actual: {}" + .format(search_term, result_no, exported_number_exports) + ) + else: + print( + "TEST FAILED: Number of expected contact exports for '{}' WAS NOT EQUAL to actual number of exports - Expected: {}, Actual: {}" + .format(search_term, result_no, exported_number_exports) + ) + finally: + self.logout() + self.browser.close() -try: - login() - test_contactexport("john") - test_contactexport("j") - test_contactexport("e") - #wait_for_download() - logout() -finally: - try: - browser.close() - except: - pass +if __name__ == "__main__": + ContactExport().test("John")