refactor: improved contact export tests

This commit is contained in:
Roxie Gibson 2021-01-25 21:21:14 +00:00
parent abdcce6042
commit 90e1d6e119
Signed by untrusted user: roxxers
GPG Key ID: 5D0140EDEE123F4D
4 changed files with 53 additions and 57 deletions

4
.gitignore vendored
View File

@ -3,4 +3,6 @@
geckodriver.log geckodriver.log
*.png *.png
*.lock *.lock
.vscode .vscode
*.pyc
*__pycache__

View File

@ -28,7 +28,7 @@ class BaseTester:
logging.basicConfig( logging.basicConfig(
level="INFO", level="INFO",
format="%(message)s", format="%(message)s",
datefmt="[%X]", datefmt="[%X]", # TODO: Change date format
handlers=[RichHandler()] handlers=[RichHandler()]
) )
self.log = logging.getLogger("civiCRM-tester") self.log = logging.getLogger("civiCRM-tester")
@ -145,6 +145,12 @@ class BaseTester:
class SearchExportTester(BaseTester): class SearchExportTester(BaseTester):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
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"
def _get_export_id(self) -> str: def _get_export_id(self) -> str:
"""Parses url to get the param used to ID what search we are currently doing""" """Parses url to get the param used to ID what search we are currently doing"""
export_page_url = self.browser.current_url export_page_url = self.browser.current_url
@ -153,7 +159,37 @@ class SearchExportTester(BaseTester):
self.debug("got qf_key '%s' from url" % qf_key) self.debug("got qf_key '%s' from url" % qf_key)
return qf_key return qf_key
def download(self, data: dict) -> requests.Response: def _get_contact_search_number(self) -> int:
"""Grabs the number of reported matches in a search on civicrm page"""
results = 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)"
)
matches = re.findall(r"(\d+)", results.text)
# Should just be one match in normal cases
result_no = int(matches[0])
return result_no
def _wait_for_search_to_load(self):
"""Wrapper to wait for a contact search to load
MUST BE CALLED AFTER YOU HAVE SEARCHED"""
# "alpha-filter" is element of the table
self.wait_until_visible((By.ID, "alpha-filter"))
self.debug("table of results has loaded")
def _select_option_from_magic_dropdown(self, option_id: str):
"""
Wrapper to click an option from the dropdown menu within the search on civicrm.
Magic dropdown because it literally is not how dropdowns should work at all
All options have an ID but this can change depending on the context of how you get to the search page
MUST BE CALLED WHEN ON THE SEARCH RESULTS PAGE
"""
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(option_id).click()
self.wait_until_visible((By.CSS_SELECTOR, ".crm-block"))
def download_export(self, data: dict) -> requests.Response:
""" """
Download exports from searches manually using requests Download exports from searches manually using requests
This is because managing downloads within Selenium is a nightmare This is because managing downloads within Selenium is a nightmare
@ -175,10 +211,8 @@ class SearchExportTester(BaseTester):
# Most of this data is replicating the export settings so that the response is the csv data # Most of this data is replicating the export settings so that the response is the csv data
data = { data = {
"qfKey": self._get_export_id(), "qfKey": self._get_export_id(),
"entryURL": self.base_url + "/civicrm/contact/search", "entryURL": self.search_url,
**data # Add provided export data required for specific export requests **data # Add provided export data required for specific export requests
} }
res = session.request( res = session.request("POST", self.search_url, data=data)
"POST", self.base_url + "/civicrm/contact/search", data=data
)
return res return res

View File

@ -1,8 +1,6 @@
import csv import csv
import io import io
import re
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from .base import SearchExportTester from .base import SearchExportTester
@ -16,14 +14,10 @@ class ContactExport(SearchExportTester):
self.desc( self.desc(
"Testing if exporting contacts from a search returns a CSV file with all expected contacts." "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" self.contact_exportoption_id = "select2-result-label-15"
def download_csv(self): def download_csv(self):
# Data of the request that is specific for this export and not genertic like qr_key # Data of the request that is specific for this export and not generic like qr_key
data = { data = {
"_qf_Select_next": "Continue", "_qf_Select_next": "Continue",
"exportOption": 1, "exportOption": 1,
@ -31,7 +25,7 @@ class ContactExport(SearchExportTester):
"postal_greeting": 1, "postal_greeting": 1,
"addressee": 1, "addressee": 1,
} }
return self.download(data) return self.download_export(data)
def calculate_exported_contacts_number(self) -> int: def calculate_exported_contacts_number(self) -> int:
""" """
@ -41,7 +35,7 @@ class ContactExport(SearchExportTester):
res = self.download_csv() res = self.download_csv()
csv_file = io.StringIO(res.text) csv_file = io.StringIO(res.text)
# Dict reader should remove headers # DictReader removes header from count
exported_csv = csv.DictReader(csv_file) exported_csv = csv.DictReader(csv_file)
exported_number_exports = sum(1 for row in exported_csv) exported_number_exports = sum(1 for row in exported_csv)
self.debug( self.debug(
@ -66,24 +60,9 @@ class ContactExport(SearchExportTester):
search_box.send_keys(search_term) search_box.send_keys(search_term)
search_box.send_keys(Keys.ENTER) search_box.send_keys(Keys.ENTER)
self.debug("searching for contacts with term '%s'" % search_term) self.debug("searching for contacts with term '%s'" % search_term)
self.wait_until_visible( self._wait_for_search_to_load()
(By.ID, "alpha-filter") result_no = self._get_contact_search_number()
) #wait for table to load self._select_option_from_magic_dropdown(self.contact_exportoption_id)
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() exported_number_exports = self.calculate_exported_contacts_number()
if exported_number_exports == (result_no): if exported_number_exports == (result_no):

View File

@ -1,8 +1,6 @@
import io import io
import re
from pdfminer.high_level import extract_text from pdfminer.high_level import extract_text
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from .base import SearchExportTester from .base import SearchExportTester
@ -16,12 +14,9 @@ class SteeringCommitteePrintLabels(SearchExportTester):
self.desc( self.desc(
"Testing the pdf labels for the SteeringCommittee show all contacts names" "Testing the pdf labels for the SteeringCommittee show all contacts names"
) )
self.search_url = self.base_url + "/civicrm/contact/search"
self.group_dropdown = "s2id_autogen2" self.group_dropdown = "s2id_autogen2"
self.search_button = "_qf_Basic_refresh" self.search_button = "_qf_Basic_refresh"
self.mail_label_option = "select2-result-label-19" self.mail_label_option = "select2-result-label-19"
self.contact_selectall_id = "CIVICRM_QFID_ts_all_4"
self.contact_dropdown_id = "select2-chosen-4"
# Using this to count amount of people in the exported pdf # Using this to count amount of people in the exported pdf
# This will fail if someone is added that doesn't have a UK adddress # This will fail if someone is added that doesn't have a UK adddress
self.pdf_search_string = "UNITED KINGDOM" self.pdf_search_string = "UNITED KINGDOM"
@ -32,24 +27,10 @@ class SteeringCommitteePrintLabels(SearchExportTester):
group_dropdown.click() group_dropdown.click()
group_dropdown.send_keys("Steering Committee" + Keys.ENTER) group_dropdown.send_keys("Steering Committee" + Keys.ENTER)
self.find_element_by_id(self.search_button).click() self.find_element_by_id(self.search_button).click()
self.wait_until_visible( self._wait_for_search_to_load()
(By.ID, "alpha-filter") result_no = self._get_contact_search_number()
) #wait for table to load
self.debug("table of results has loaded")
# TODO: Refactor this in base class as a helper function because we do this in another test
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.debug("exporting results using the magic dropdown")
self.find_element_by_id(self.contact_selectall_id).click() self._select_option_from_magic_dropdown(self.mail_label_option)
self.find_element_by_id(self.contact_dropdown_id).click()
self.find_element_by_id(self.mail_label_option).click()
self.wait_until_visible((By.CSS_SELECTOR, ".crm-block"))
# By omitting the field, we are effectively disabling the do not mail filter # By omitting the field, we are effectively disabling the do not mail filter
data = { data = {
"_qf_default": "Label:submit", "_qf_default": "Label:submit",
@ -58,7 +39,7 @@ class SteeringCommitteePrintLabels(SearchExportTester):
"location_type_id": "", "location_type_id": "",
"_qf_Label_submit": "Make+Mailing+Labels" "_qf_Label_submit": "Make+Mailing+Labels"
} }
res = self.download(data) res = self.download_export(data)
pdf_text = extract_text(io.BytesIO(res.content)) pdf_text = extract_text(io.BytesIO(res.content))
label_count = pdf_text.count(self.pdf_search_string) label_count = pdf_text.count(self.pdf_search_string)
if result_no == label_count: if result_no == label_count: