class MyelomaLabsView(view.View): post_url = 'myeloma-labs' def load(self, labInfo=None): try: WDW(self.driver, 20).until_not( EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) self.util = UtilityFunctions(self.driver) self.menu = menu.Menu(self.driver) self.header = header.AuthHeader(self.driver) self.form = self.driver.find_element_by_id('page-content-wrapper') buttons = self.form.find_elements_by_tag_name('button') inputs = self.form.find_elements_by_tag_name('input') self.add_new_labs = buttons[0] self.get_my_labs = buttons[1] # Is this here all the time? # Lab Values Chart chart_cont = self.driver.find_element_by_class_name( 'myeloma-labs-custom') self.lab_values_dropdown = chart_cont.find_element_by_tag_name( 'button') # Date range options range_cont = self.driver.find_element_by_class_name('datenfilter') date_buttons = range_cont.find_elements_by_tag_name('button') self.three_month_button = date_buttons[0] self.six_month_button = date_buttons[1] self.year_to_date_button = date_buttons[2] self.one_year_button = date_buttons[3] self.two_year_button = date_buttons[4] self.five_year_button = date_buttons[5] self.ten_year_button = date_buttons[6] self.all_button = date_buttons[7] # Custom date range inputs = range_cont.find_elements_by_tag_name('input') self.from_date_input = inputs[0] self.to_date_input = inputs[1] # Lab Values Table self.load_table() self.continue_button = buttons[10] # self.validate(labInfo) return True except (NoSuchElementException, StaleElementReferenceException, IndexError) as e: return False def validate(self, labInfo): failures = [] lInfo = self.clinical_tables[-1] if lInfo: if labInfo: if lInfo['dobd'] != labInfo['dobd']: failures.append('Table value: ' + '"' + str(lInfo['dobd']) + '"' + ' expected ' + '"' + str(labInfo['dobd']) + '"') # 1: Clinical Trials if lInfo['monoclonal'] != labInfo['monoclonal']: failures.append('Table value: ' + '"' + str(lInfo['monoclonal']) + '"' + ' expected ' + '"' + str(labInfo['monoclonal']) + '"') if lInfo['kappa'] != labInfo['kappa']: failures.append('Table value: ' + '"' + str(lInfo['kappa']) + '"' + ' expected ' + '"' + str(labInfo['kappa']) + '"') if lInfo['lambda'] != labInfo['lambda']: failures.append('Table value: ' + '"' + str(lInfo['lambda']) + '"' + ' expected ' + '"' + str(labInfo['lambda']) + '"') if lInfo['ratio'] != labInfo['ratio']: failures.append('Table value: ' + '"' + str(lInfo['ratio']) + '"' + ' expected ' + '"' + str(labInfo['ratio']) + '"') if lInfo['bone_marrow'] != labInfo['bone_marrow']: failures.append('Table value: ' + '"' + str(lInfo['bone_marrow']) + '"' + ' expected ' + '"' + str(labInfo['bone_marrow']) + '"') if lInfo['creatinine'] != labInfo['creatinine']: failures.append('Table value: ' + '"' + str(lInfo['creatinine']) + '"' + ' expected ' + '"' + str(labInfo['creatinine']) + '"') if lInfo['platelets'] != labInfo['platelets']: failures.append('Table value: ' + '"' + str(lInfo['platelets']) + '"' + ' expected ' + '"' + str(labInfo['platelets']) + '"') if lInfo['neutrophils'] != labInfo['neutrophils']: failures.append('Table value: ' + '"' + str(lInfo['neutrophils']) + '"' + ' expected ' + '"' + str(labInfo['neutrophili']) + '"') # if lInfo['blood'] != labInfo['blood']: # failures.append('Table value: ' + '"' + str(lInfo['blood']) + '"' + ' expected ' + '"' + str(labInfo['blood']) + '"') # 2: Current state if lInfo['calcium'] != labInfo['calcium']: failures.append('Table value: ' + '"' + str(lInfo['calcium']) + '"' + ' expected ' + '"' + str(labInfo['calcium']) + '"') if lInfo['blood_cell'] != labInfo['blood_cell']: failures.append('Table value: ' + '"' + str(lInfo['blood_cell']) + '"' + ' expected ' + '"' + str(labInfo['blood_cell']) + '"') if lInfo['hemoglobin'] != labInfo['hemoglobin']: failures.append('Table value: ' + '"' + str(lInfo['hemoglobin']) + '"' + ' expected ' + '"' + str(labInfo['hemoglobin']) + '"') if lInfo['lactate'] != labInfo['lactate']: failures.append('Table value: ' + '"' + str(lInfo['lactate']) + '"' + ' expected ' + '"' + str(labInfo['lactate']) + '"') if lInfo['albumin'] != labInfo['albumin']: failures.append('Table value: ' + '"' + str(lInfo['albumin']) + '"' + ' expected ' + '"' + str(labInfo['albumin']) + '"') if lInfo['immuno_g'] != labInfo['immuno_g']: failures.append('Table value: ' + '"' + str(lInfo['immuno_g']) + '"' + ' expected ' + '"' + str(labInfo['immuno_g']) + '"') if lInfo['immuno_a'] != labInfo['immuno_a']: failures.append('Table value: ' + '"' + str(lInfo['immuno_a']) + '"' + ' expected ' + '"' + str(labInfo['immuno_a']) + '"') if lInfo['immuno_m'] != labInfo['immuno_m']: failures.append('Table value: ' + '"' + str(lInfo['immuno_m']) + '"' + ' expected ' + '"' + str(labInfo['immuno_m']) + '"') if lInfo['platelets'] != labInfo['platelets']: failures.append('Table value: ' + '"' + str(lInfo['platelets']) + '"' + ' expected ' + '"' + str(labInfo['platelets']) + '"') if self.add_new_labs.text != 'Add New Labs': failures.append('AddLabsView: Unexpected add new labs button text') if len(failures) > 0: for failure in failures: print(failure) return False return True def load_table(self): # Table with saved Lab results at bottom of page # Read info from each row and return dictionary self.clinical_tables = [] # Table Header try: table_header = self.form.find_element_by_class_name( 'sticky-table-header-wrapper') except NoSuchElementException: # No lab results saved (or table not displayed yet) return None header_cells = table_header.find_elements_by_class_name( 'sticky-table-cell') header_keys = [ 'actions', 'dobd', 'monoclonal', 'kappa', 'lambda', 'ratio', 'bone_marrow', 'creatine', 'platelets', 'neutrophils', 'blood_cell', 'hemoglobin', 'lactate', 'albumin', 'immuno_g', 'immuno_a', 'immuno_m', 'calcium' ] # Table Body table_body = self.form.find_element_by_class_name( 'sticky-table-y-wrapper') # Actions, Lab date stationary_content = table_body.find_element_by_class_name( 'sticky-table-table') stationary_rows = stationary_content.find_elements_by_class_name( 'sticky-table-row') # self.clinical_tables.append({'delete': stationary_rows[0].find_element_by_class_name('delete')}) # Lab fields sliding_content = table_body.find_element_by_class_name( 'sticky-table-x-wrapper') sliding_rows = sliding_content.find_elements_by_class_name( 'sticky-table-row') for rowIndex, row in enumerate(stationary_rows): # print(rowIndex) rowInfo = {} # Info for an individual lab result stationary_row = row rowInfo['edit'] = stationary_row.find_element_by_class_name('edit') rowInfo['delete'] = stationary_row.find_element_by_class_name( 'delete') rowInfo['date'] = stationary_row.find_elements_by_class_name( 'sticky-table-cell')[1].text sliding_row = sliding_rows[rowIndex] cells = sliding_row.find_elements_by_class_name( 'sticky-table-cell') if rowIndex < 5: print(len(cells)) for cellIndex, cell in enumerate(cells): rowInfo[header_keys[cellIndex]] = cell.text.lower() if rowInfo: self.clinical_tables.append(rowInfo) def get_my_labs(self): self.add_new_labs.click() self.addLabsForm = addLabsForm.AddLabsForm(self.driver) WDW(self.driver, 10).until(lambda x: self.addLabsForm.load()) self.util.click_el(self.addLabsForm.get_my_labs_button ) # Should now be on /my-labs-facilities def add_new_lab(self, labInfo, action='save'): self.add_new_labs.click() self.addLabsForm = addLabsForm.AddLabsForm(self.driver) WDW(self.driver, 10).until(lambda x: self.addLabsForm.load()) self.addLabsForm.submit(labInfo, 'save') WDW(self.driver, 3).until_not( EC.presence_of_element_located((By.CLASS_NAME, 'modal-dialog'))) WDW(self.driver, 10).until_not( EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) def edit_delete_lab(self, testIndex=0, revisedLabInfo=None, action='delete', popUpAction='confirm'): try: test = self.clinical_tables[testIndex] except IndexError: print('No test w/ index: ' + str(testIndex)) return False if test: if action == 'delete': test['delete'].click() self.popUpForm = popUpForm.PopUpForm(self.driver) WDW(self.driver, 10).until(lambda x: self.popUpForm.load()) self.popUpForm.confirm(popUpAction) else: test['edit'].click() WDW(self.driver, 10).until(lambda x: self.addLabsForm.load()) self.addLabsForm.submit(revisedLabInfo, 'save') return True def delete_all_labs(self): while self.clinical_tables: self.edit_delete_lab() time.sleep(2) self.load()
class SingleDatePicker(): def __init__(self, driver): self.driver = driver self.util = UtilityFunctions(self.driver) self.months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] count = 0 loaded = False while not loaded and count < 5: loaded = self.load() count += 1 time.sleep(.2) def load(self): try: self.container = self.load_container() if self.container: self.month = self.container.find_element_by_class_name( 'cur-month') self.year = self.container.find_element_by_class_name( 'cur-year') self.day_cont = self.container.find_element_by_class_name( 'dayContainer') self.today = self.try_load_today() self.selected_day = self.try_load_selected_day() return True else: print('singleDatePicker: Could not find an open container') except NoSuchElementException: print('failed to load datepicker') return False def load_container(self): # For some reason has multiple 'months' of dates loaded. Month actually displayed is in last container containers = self.driver.find_elements_by_class_name( 'flatpickr-calendar') container = None for i, cont in enumerate(containers): classes = cont.get_attribute('class') if 'open' in classes: container = cont return container def try_load_today(self): # Won't have 'today' if input already has today's date or current month is not selected today = None try: today = self.day_cont.find_element_by_class_name('today') except NoSuchElementException: pass return today def try_load_selected_day(self): # May not have a day selected on displayed month (or at all) selectedEl = None try: selectedEl = self.day_cont.find_element_by_class_name( 'selected').text except NoSuchElementException: pass return selectedEl ########################### General ############################## def set_date(self, date): # Expects 'MM/DD/YYYY' format if date == 'current': self.set_current_date() else: self.set_year(date[-4:]) # raw_input('set year?') self.set_month(date[:2]) # raw_input('set month?') self.set_day(date[3:5]) # raw_input('set day?') self.load() def set_current_date(self): now = datetime.datetime.now() self.set_date(now.strftime("%m/%d/%Y")) def get_date(self): # Return datepicker's value in MM/DD/YYYY format (current selection, not input value) # day will be '' if nothing is selected ('MM//YYYY') month = self.month_int(self.month.text) year = self.year.get_attribute('value') day = self.day_int(self.selected_day) date = month + '/' + day + '/' + year return {'month': month, 'year': year, 'day': day, 'date': date} def set_year(self, year): print('setting year: ' + str(year)) current_year = self.year.get_attribute('value') count = 0 while year != current_year and count < 50: if current_year > year: # 2018 > 2017 year_down = self.container.find_element_by_class_name( 'arrowDown') self.util.click_el(year_down) elif current_year < year: year_up = self.container.find_element_by_class_name('arrowUp') self.util.click_el(year_up) time.sleep(.4) self.load() current_year = self.year.get_attribute('value') count += 1 def set_month(self, month): print('setting month: ' + str(month)) current_month = self.month_int(self.month.text) count = 0 while current_month != month and count < 12: if current_month > month: print(str(current_month) + " > " + str(month)) month_back = self.container.find_element_by_class_name( 'flatpickr-prev-month') self.util.click_el(month_back) elif current_month < month: print(str(current_month) + " < " + str(month)) month_next = self.container.find_element_by_class_name( 'flatpickr-next-month') self.util.click_el(month_next) time.sleep(.4) self.load() current_month = self.month_int(self.month.text) count += 1 def set_day(self, day): print('setting day: ' + str(day)) errorFree = False count = 0 while not errorFree and count < 10: try: days = self.day_cont.find_elements_by_class_name( 'flatpickr-day') for i, dayEl in enumerate(days): classes = dayEl.get_attribute('class') if 'nextMonthDay' not in classes and 'prevMonthDay' not in classes: # print(dayEl.text) if int(dayEl.text) == int(day): # print('clicking ' + dayEl.text) self.util.click_el(dayEl) errorFree = True except StaleElementReferenceException: print('failed to set day: ' + str(count)) count += 1 def validate_month(self, month): # Compare 'month' to picker's current month (MM format) matches = True # print('picker month: ' + str(self.month.text)) # print('expected raw: ' + str(month)) # print('expected parsed: ' + self.months[self]) if self.months[month - 1] != self.month.text: matches = False return matches def validate_day(self, day): # Compare 'day' to picker's current day (DD format) # Pass in None if not expecting a day selected # if self.selected_day: # print('picker day: ' + str(self.selected_day.text)) # else: # print('picker day: None') # print('expected: ' + str(day)) matches = False if day == self.selected_day or day == self.selected_day.text: # No day selected or values match matches = True return matches def validate_year(self, year): # Compare 'year' to picker's current year (YYYY format) # print('picker year: ' + str(self.year.get_attribute('value'))) # print('expected year: ' + str(year)) matches = True if self.year.get_attribute('value') != str(year): matches = False return matches def has_current_date(self): # Return 'current' if picker has today's date now = datetime.datetime.now() currentDate = 'current' now.strftime("%m/%d/%Y") if int(now.strftime("%Y")) != int(self.year.get_attribute('value')): print('Not current year: ' + str( now.strftime("%Y") + ', ' + str(self.year.get_attribute('value')))) currentDate = False if self.months[now.month - 1] != self.month.text: print('Not current month: ' + self.months[now.month - 1] + ', ' + str(self.month.text)) currentDate = False if int(now.day) != int(self.selected_day): print('Not current day: ' + str(now.day) + ', ' + self.selected_day) currentDate = False return currentDate def month_int(self, value): # Given name of month, return string of name converted to integer (January = '01') return str(self.months.index(value) + 1).zfill(2) def day_int(self, value): if value: return value.zfill(2) else: return ''
class ConsentFormView(view.View): post_url = 'consent-form' def load(self, expectedInfo=None, editMode=False): try: WDW(self.driver, 20).until_not(EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) self.util = UtilityFunctions(self.driver) self.menu = menu.Menu(self.driver) self.header = header.AuthHeader(self.driver) # print('0') # Verify consent form is in expected mode (normal or edit) if self.edit_mode() != editMode: print('ConsentForm: Incorrect mode. Expected editMode ' + str(editMode)) return False self.form = self.driver.find_elements_by_tag_name('form')[1] # print('1') try: self.facility_name = self.form.find_elements_by_class_name('font-weight-bold')[1].text except NoSuchElementException: # Facility name is not required field on previous page (for now) self.facility_name = None # print('2') self.load_preferences() # print('3') self.other_input = self.form.find_element_by_id('other_value') # print('4') # Patient Info self.first_name = self.form.find_element_by_id('patient_firstName') self.last_name = self.form.find_element_by_id('patient_lastName') self.rep_first_name = self.form.find_element_by_id('representative_firstName') self.rep_last_name = self.form.find_element_by_id('representative_lastName') self.date_input = self.form.find_element_by_id('dateField') # print('5') # Portal Info self.load_portal_login_info(editMode) # print('6') # Order is not same as displayed on page (float right) self.buttons = self.form.find_elements_by_class_name('green-hvr-bounce-to-top') self.agree_button = self.buttons[0] self.do_not_agree_button = self.buttons[1] self.print_button = self.buttons[2] self.back_button = self.buttons[3] # print('7') return self.validate(expectedInfo) except (NoSuchElementException, StaleElementReferenceException, IndexError) as e: return False def edit_mode(self): # Is consent form in edit mode? try: # Look for edit button for Portal Login Information el = self.driver.find_element_by_class_name('info-edit') return True except NoSuchElementException: return False def load_portal_login_info(self, editMode): self.edit_login_info_button = self.try_load_edit_login_info_button() if editMode and self.login_info_mode() == 'noneditable': # No inputs. Load text as values vals = self.driver.find_elements_by_class_name('account-val') self.username = self.util.get_text(vals[0]) self.password = self.util.get_text(vals[1]) self.url = self.util.get_text(vals[2]) else: # Editable. Load input elements self.username = self.form.find_element_by_id('portal_username') self.password = self.form.find_element_by_id('portal_password') self.url = self.form.find_element_by_id('portal_url') def try_load_edit_login_info_button(self): # Button for entering edit mode for 'Patient Portal Login Information' # Only exists when editing consent form try: return self.driver.find_element_by_class_name('info-edit') except NoSuchElementException: return None def login_info_mode(self): # Is login information editable? try: # Look for non-editable fields els = self.driver.find_elements_by_class_name('account-val') if len(els) == 3: return 'noneditable' except NoSuchElementException: return 'editable' def validate(self, expectedInfo): failures = [] if len(self.buttons) != 4: failure.append('ConsentForm: Unexpected number of form buttons. Loaded ' + str(len(self.buttons))) if len(self.preference_inputs) != 12: failure.append('ConsentForm: Unexpected number of preference inputs. Loaded ' + str(len(self.preference_inputs))) if expectedInfo: # Validate facilities pass if len(failures) > 0: for failure in failures: print(failure) return False return True def load_preferences(self): self.preference_inputs = self.form.find_elements_by_class_name('checkbox-custom') self.preferences = {} for inputEl in self.preference_inputs: inputId = inputEl.get_attribute('id') self.preferences[inputId] = inputEl # 'access_all_records' # 'lab_reports' # 'history' # 'admission' # 'medication' # 'xray' # 'paperwork' # 'consult' # 'mental' # 'alcohol' # 'hiv' # 'other' def set_preferences(self, info, other_comment=None): for key in self.preferences: if key in info: # Make sure it's selected if not self.preferences[key].is_selected(): self.util.click_el(self.preferences[key]) else: # Make sure it's de-selected if self.preferences[key].is_selected(): self.util.click_el(self.preferences[key]) if other_comment: self.util.set_input(self.other_input, other_comment) def get_preferences(self): selected_preferences = [] for inputEl in self.preference_inputs: if inputEl.is_selected(): selected_preferences.append(inputEl.get_attribute('id')) return selected_preferences def set_patient_info(self, info, inputMethod='typed'): # Patient if 'first name' in info: self.util.set_input(self.first_name, info['first name']) if 'last name' in info: self.util.set_input(self.last_name, info['last name']) # Representative (optional) if 'rep first name' in info: self.util.set_input(self.rep_first_name, info['rep first name']) if 'rep last name' in info: self.util.set_input(self.rep_last_name, info['rep last name']) # Date if 'date' in info: self.set_date(info['date'], inputMethod) def get_patient_info(self, current_date=True): patient_info = {} patient_info['first name'] = self.first_name.get_attribute('value') patient_info['last name'] = self.last_name.get_attribute('value') patient_info['rep first name'] = self.rep_first_name.get_attribute('value') patient_info['rep last name'] = self.rep_last_name.get_attribute('value') if current_date: # Return 'current' if date is today's date self.util.click_el(self.date_input) self.picker = singleDatePicker.SingleDatePicker(self.driver) patient_info['date'] = self.picker.has_current_date() else: patient_info['date'] = self.date_input.get_attribute('value') return patient_info def set_date(self, date, inputMethod='typed'): if inputMethod == 'typed': self.util.set_input(self.date_input, date) # Typing value via selenium won't update date displayed on picker. Need to press enter self.date_input.send_keys(Keys.RETURN) elif inputMethod == 'picker': self.util.click_el(self.date_input) self.picker = singleDatePicker.SingleDatePicker(self.driver) self.picker.set_date(date) def compare_date(self, date, date_source='input'): # Compare given date w/ value of (input) or (picker) if date_source == 'input': now = datetime.datetime.now() curDate = now.strftime("%m/%d/%Y") return curDate == self.date_input.get_attribute('value') elif date_source == 'picker': self.util.click_el(self.date_input) self.picker = singleDatePicker.SingleDatePicker(self.driver) picker_date = self.picker.get_date() print(str(picker_date['date']) + ' == ' + str(date)) return date == picker_date['date'] def set_portal_info(self, info): if self.edit_mode() and self.login_info_mode() == 'uneditable': self.util.click_el(self.edit_login_info_button) time.sleep(.4) self.load() if info.get('username', None): self.util.set_input(self.username, info['username']) if info.get('password', None): self.util.set_input(self.password, info['password']) if info.get('url', None): self.util.set_input(self.url, info['url']) def get_portal_info(self): portal_info = {} editMode = self.edit_mode() portalInfoMode = self.login_info_mode() if editMode and portalInfoMode == 'noneditable': # Info is not editable. Password will be replaced w/ * characters portal_info['username'] = self.username portal_info['password'] = self.password portal_info['url'] = self.url else: portal_info['username'] = self.username.get_attribute('value') portal_info['password'] = self.password.get_attribute('value') portal_info['url'] = self.url.get_attribute('value') return portal_info def action(self, action='submit'): if action == 'submit': self.util.click_el(self.agree_button) elif action == 'back': self.util.click_el(self.back_button) elif action == 'do not agree': self.util.click_el(self.do_not_agree_button)
class TreatmentsOutcomesView(view.View): post_url = 'about-me' def load(self, expectedValues=None, expectedState=None): try: WDW(self.driver, 10).until_not( EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) self.util = UtilityFunctions(self.driver) self.menu = menu.Menu(self.driver) self.header = header.AuthHeader(self.driver) self.state = self.load_state() if expectedState and expectedState != self.state: print('Wrong state! Expected ' + str(expectedState) + ', got ' + str(self.state)) return False if self.state == 'fresh': self.newAccountPopUpForm = newAccountPopUpForm.NewAccountPopUpForm( self.driver) # load new popup # todo: need new account to get this state pass else: try: # Only shows up when certain diagnoses are selected on 'Myeloma Diagnosis' self.view_options_button = self.driver.find_element_by_class_name( 'treatment_op_btn') except NoSuchElementException: self.view_options_button = None self.load_add_treatment_button() self.saved_tests = self.driver.find_elements_by_class_name( 'table_container') return self.validate(expectedValues) except (NoSuchElementException, StaleElementReferenceException, IndexError) as e: return False def load_state(self): # New user gets popup asking whether they have received treatments before (yes/no) # Todo: figure out how to load popup # Saved treatment? try: savedTable = self.driver.find_element_by_class_name( 'outer-mypataient-table') return 'saved' except NoSuchElementException: # normal? try: buttonCont = self.driver.find_element_by_class_name( 'custom1-add-treatment-btn') return 'normal' except NoSuchElementException: return 'fresh' def load_add_treatment_button(self): buttonCont = self.driver.find_element_by_class_name( 'custom1-add-treatment-btn') self.add_treatments_button = buttonCont.find_elements_by_tag_name( 'button')[0] def validate(self, expectedValues): self.failures = [] if expectedValues: print('validating expectedValues') meta = expectedValues.get('meta', None) if meta: for key, value in meta.iteritems(): if key == 'num_treatments': if value != len(self.saved_tests): self.failures.append( 'Treatments&Outcomes Meta: Expected ' + str(value) + ' treatments. Form has ' + str(len(self.saved_tests))) else: print('correct number of treatents: ' + str(value)) elif self.state == 'fresh': # todo: Validate text on 'fresh' popup print('validating fresh') pass else: if self.add_treatments_button and self.util.get_text( self.add_treatments_button) != 'Add Treatments': self.failures.append( 'treatmentsOutcomesView: Unexpected text on add treatment button' ) if self.state == 'saved': print('validating saved') # Verify tests have expected data extraTypes = [ 'bone strengtheners', 'antibiotics', 'antifungal' ] expectedTests = expectedValues.get('tests', {}) for testIndex, test in enumerate(expectedTests): print('T&O: Validating test: ' + str(testIndex)) # Test meta data testType = test['testMeta']['type'] numQuestions = len(test['questions']) # read data out of test's table # if only validating 1 test, make sure grabbing last loadedTest if len(expectedTests) == 1: testIndex = -1 savedTest = self.read_test(testIndex) # raw_input('savedTest: ' + str(savedTest)) savedData = savedTest['testData'] try: if testType == 'clinical': self.compare_nct(savedData['nct #'], test, testType) self.compare_treatments( savedData['treatment type'], test, testType) else: # All other treatment types have treatments and therapy type self.compare_therapy_type( savedData['therapy type'], test, testType) self.compare_treatments( savedData['treatments'], test, testType) if testType == 'stem cell': self.compare_start_date( self.convert_date( savedData['transplant date']), test, testType) else: self.compare_start_date( self.convert_date(savedData['start date']), test, testType) self.compare_end_date( self.convert_date(savedData['end date']), test, testType) if testType in extraTypes: # Bone Strengtheners, Antibiotics, Antifungal self.compare_frequency(savedData['frequency'], test, testType) else: # Chemo, Radiation, Stem Cell self.compare_side_effects( savedData['side effects'], test, testType) self.compare_outcome(savedData['outcome'], test, testType) except KeyError: print(savedData) raw_input('keyerror: ?') elif self.state == 'normal': print('validating normal') pass if len(self.failures) > 0: print('Failures!') for failure in self.failures: print(failure) raise NoSuchElementException( "Failed to load treatmentsOutcomesView") else: return True def read_test(self, testIndex): # 'actions': {'treatments': webEl, 'outcomes': webEl, 'sideEffects': webEl, 'delete': webEl} # 'testData': { # 'start date': 'Jan 2018', # 'end date': 'Current Treatment', # 'therapy type': 'Maintenance Therapy', # 'treatments': ['melphalan', 'Adriamycin (Removed On: Mar 2018) (Reason: Drug cost)'], # 'side effects': {'blood clots': {'intensity': 9}, 'irregular/rapid heartbeat': {'intensity': 2}} # } testData = {} treatments = [] sideEffects = {} actions = {} cont = self.saved_tests[testIndex] rows = cont.find_elements_by_tag_name('tr') testKeys = [ ] # ['start date', 'end date', 'therapy type', 'treatments', 'side effects'] for rowIndex, row in enumerate(rows): # Header values if rowIndex == 0: tds = row.find_elements_by_tag_name('td') for td in tds: testKeys.append(self.util.get_text(td).lower()) # Test values elif rowIndex == 1: tds = row.find_elements_by_tag_name('td') for tdIndex, td in enumerate(tds): key = testKeys[tdIndex] if tdIndex == len( tds) - 2: # Treatments List (2nd to last td) items = td.find_elements_by_class_name( 'treatments-lbl-span') for treatment in items: treatmentText = self.util.get_text( treatment).lower() treatments.append(treatmentText) # Clinical doesn't have items (just text) if not items: text = self.util.get_text(td) if text: treatments.append(text.lower()) else: raw_input('wtf?') # try: # treatments.append(self.util.get_text(td)).lower() # except AttributeError: # raw_input(str(key) + '?') testData[key] = treatments elif tdIndex == len( tds) - 1: # Last row: index=4 (3 for stem cell) # Side Effects (chemo, radiation, stem cell) items = td.find_elements_by_class_name( 'treatments-lbl-span') if len(items) > 0: for effect in items: # Leave in upper case. Data passed in is in upper case name = self.util.get_text( effect.find_element_by_tag_name('span')) intensity = int( self.util.get_text( effect.find_element_by_tag_name( 'div'))) sideEffects[name] = {'intensity': intensity} testData[key] = sideEffects else: # Frequency (Bone strengtheners, antibiotics, antifungal) # Only bone strengtheners have frequency (otherwise 'N/A') text = self.util.get_text(td).lower() print('text: ' + str(text)) if text: testData[key] = text else: # Might have no side effects (any type of treatment) testData[key] = sideEffects else: # Start date, end date, therapy type testData[key] = self.util.get_text(td).lower() # Outcome (no outcome for bone strengtheners, antibiotics, antifungal. Table only has 3 rows) elif rowIndex == 2 and len(rows) == 4: td = row.find_elements_by_tag_name('td')[ 1] # text is in 2nd td testData['outcome'] = self.util.get_text(td).lower() # Actions (last row) elif (rowIndex + 1) == len(rows): anchors = row.find_elements_by_tag_name('a') if len(anchors) == 4: actions['treatments'] = anchors[0] actions['outcomes'] = anchors[1] actions['sideEffects'] = anchors[2] actions['delete'] = anchors[3] elif len(anchors ) == 2: # bone strengtheners, antibiotics, antifungal actions['treatments'] = anchors[0] actions['delete'] = anchors[1] # print('done loading test: ' + str(testIndex)) return { 'actions': actions, 'testData': testData, } def convert_date(self, dateStr): # Input: 'mmm yyyy', Output; 'mm/yyyy' spaceIndex = dateStr.find(' ') # Should always be 3 if spaceIndex == 3: months = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ] monthName = dateStr[:3] year = dateStr[4:] month = str(months.index(monthName) + 1).zfill(2) return month + '/' + str(year) else: if dateStr != 'current treatment': print('Unexpected date format: ' + str(dateStr)) return dateStr def parse_sideEffects(self, info): # {'cardiovascular/circulatory system': { # 'irregular/rapid heartbeat': {'intensity': 2}, # 'blood clots': {'intensity': 9}} # } # converted to... # {u'irregular/rapid heartbeat': {'intensity': u'2'}, # u'blood clots': {'intensity': u'9'} # } sideEffects = {} if info: for category in info: for effect, value in info[category].iteritems(): sideEffects[effect] = value return sideEffects def calc_start_date(self, testType, test): # Stem Cell: question[3] unless it's induction therapy (question[2]=yes), then it's 8 if testType == 'stem cell': index = 3 for key in test['questions'][2]['options']: if key.lower() == 'yes': index = 8 return index def compare_start_date(self, savedVal, test, testType): questionIndicies = { 'stem cell': self.calc_start_date(testType, test), 'radiation': 2, 'chemo': 1, 'bone strengtheners': 3, 'antibiotics': 3, 'antifungal': 3, 'clinical': 2, } # Start Date (universal treatment option) questionIndex = questionIndicies[testType] expectedVal = test['questions'][questionIndex]['text'] if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected start date ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct start date') def compare_end_date(self, savedVal, test, testType): if testType == 'radiation': expectedVal = test['questions'][3]['text'] elif testType == 'chemo': expectedVal = 'current treatment' if test['questions'][3]['type'] == 'date': expectedVal = test['questions'][3]['text'] elif testType == 'clinical': expectedVal = 'current treatment' if test['questions'][4]['type'] == 'date': expectedVal = test['questions'][4]['text'] else: try: expectedVal = test['questions'][5][ 'text'] # If no question[5] it's 'current treatment' except (IndexError, KeyError) as e: # No end date expectedVal = 'current treatment' if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected end date ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct end date') def compare_therapy_type(self, savedVal, test, testType): if testType == 'radiation': expectedVal = 'radiation' elif testType == 'stem cell': expectedVal = 'stem cell transplant' elif testType == 'chemo': # If it's not maintenance therapy, ExpectedVal is option from 1st question # Index of maintenance therapy question depends on if treatment is 'current' or not expectedVal = 'current treatment' maintenanceIndex = 3 if test['questions'][3]['type'] == 'date': # Is a current treatment. Maintenance is index 4 maintenanceIndex = 4 isMaintenance = False for key in test['questions'][maintenanceIndex]['options']: if key.lower() == 'yes': expectedVal = 'maintenance therapy' else: # Don't pull from question options. Exact text does not match expectedVal = 'Chemotherapy / Myeloma Therapy'.lower() else: for key in test['questions'][1]['options']: expectedVal = key.lower() if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected therapyType ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct therapy type') def compare_side_effects(self, savedVal, test, testType): # Everything has sideEffects except for 'extra' treatments index = -1 if testType == 'stem cell': index = -2 expectedVal = self.parse_sideEffects( test['questions'][index]['options']) # print('expectedVal: ' + str(expectedVal)) if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected sideEffects ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct side effects') def compare_treatments(self, savedVal, test, testType): # SavedVal should be a list with all the treatment options expectedVal = None if testType == 'clinical': # Clinical shouldn't have multiple 'options', just text from question 4/5 # question[4] might be stop date if test['questions'][4].get('type', None) == 'input': expectedVal = test['questions'][4].get('text', None) else: expectedVal = test['questions'][5].get('text', None) if expectedVal: expectedVal = ['clinical trial: ' + expectedVal.lower()] else: print('Not evaluating treatments for testType: ' + str(testType)) if expectedVal: if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected treatment ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct treatment') def compare_frequency(self, savedVal, test, testType): # Only for Bone strengthener, antibiotics, antifungal if testType == 'bone strengtheners': for key in test['questions'][-1]['options']: expectedVal = key.lower() else: expectedVal = 'na' if savedVal != expectedVal: self.failures.append('T&Outcomes: Expected frequency ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct frequency') def compare_nct(self, savedVal, test, testType): expectedVal = None if testType == 'clinical': expectedVal = test['questions'][1]['text'].lower() if expectedVal and savedVal != expectedVal: self.failures.append('T&Outcomes: Expected NCT# ' + str(expectedVal) + ', loaded ' + str(savedVal)) else: print('correct nct') def compare_outcome(self, savedVal, test, testType): # Only for chemo, radiation, stem cell expectedOutcomes = [] index = -2 if testType == 'stem cell': index = -3 options = test['questions'][index]['options'] for optionName, value in options.iteritems(): expectedOutcomes.append(optionName.lower()) # 'options': { # 'I discontinued this treatment': { # 'type': 'select-all', # 'options': { # 'Too much travel': {}, # 'Other': {'comment': 'Discontinued comment: Treatment2'}, # }, # } if expectedOutcomes[0] == 'i discontinued this treatment': # There's subquestions. Get expected options for subquestion suboptions = options['I discontinued this treatment']['options'] for suboption, value in suboptions.iteritems(): expectedOutcomes.append(suboption.lower()) # Get comment if 'other' is selected if suboption.lower() == 'other': try: comment = value['comment'] expectedOutcomes.append(comment.lower()) except AttributeError: print('No comment') hasError = False for expectedOutcome in expectedOutcomes: if not expectedOutcome in savedVal: self.failures.append('T&Outcomes: Expected outcome ' + str(expectedOutcome) + ', loaded ' + str(savedVal)) hasError = True if not hasError: print('correct outcome') ############################ Utility Functions ############################### def delete_treatment(self): self.popUpForm = popUpForm.PopUpForm(self.driver) WDW(self.driver, 20).until(lambda x: self.popUpForm.load()) self.popUpForm.confirm('confirm') WDW(self.driver, 20).until_not( EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) def edit_treatments(self, editInfo, expectedInfo): self.editTreatmentForm = editTreatmentForm.EditTreatmentForm( self.driver) WDW(self.driver, 20).until(lambda x: self.editTreatmentForm.load()) if self.editTreatmentForm.edit_treatment(editInfo): WDW(self.driver, 20).until( lambda x: self.load({'tests': [expectedInfo]}, 'saved')) def edit_outcomes(self, editInfo, expectedInfo): self.popUpEditor = editTreatmentPopup.EditTreatmentPopup(self.driver) WDW(self.driver, 20).until(lambda x: self.popUpEditor.load()) if self.popUpEditor.edit_treatment(editInfo, 'outcomes'): WDW(self.driver, 20).until( lambda x: self.load({'tests': [expectedInfo]}, 'saved')) def edit_side_effects(self, editInfo, expectedInfo): self.popUpEditor = editTreatmentPopup.EditTreatmentPopup(self.driver) WDW(self.driver, 20).until(lambda x: self.popUpEditor.load()) if self.popUpEditor.edit_treatment(editInfo, 'side effects'): WDW(self.driver, 20).until( lambda x: self.load({'tests': [expectedInfo]}, 'saved')) def load_actions(self, tableContainer): lastRow = tableContainer.find_elements_by_tag_name('tr')[-1] links = lastRow.find_elements_by_tag_name('a') if len(links) == 4: return { 'treatments': links[0], 'outcomes': links[1], 'side effects': links[2], 'delete': links[3], } elif len(links) == 2: # Bone Strengtheners, Antibiotics, Anti Fungals return { 'treatments': links[0], 'delete': links[1], } def click_add_treatment(self): # Sometimes thinks there's an element in the way of button clicked = False count = 0 while not clicked and count < 5: # Has issues clicking for some reason. try: buttonCont = self.driver.find_element_by_class_name( 'custom1-add-treatment-btn') button = buttonCont.find_elements_by_tag_name('button')[0] self.util.click_el(button) clicked = True except WebDriverException: print('could not click add treatment button: ' + str(count)) time.sleep(.4) pass count += 1 if count == 5: print('failed to click add treatment button') def get_treatment_type(self, treatmentIndex): # Normal: Chemo, Radiation, Stem Cell, Clinical. # Extra: Bone strengtheners, antibiotics antifungal test = self.read_test(treatmentIndex) num_actions = len(test['actions']) if num_actions == 2: return 'extra' elif num_actions == 4: return 'normal' else: print('unexpected number of treatment actions: ' + str(num_actions)) return False ############################### Test Functions. #################################### def add_treatment(self, treatmentInfo, expectedInfo=None, expectedError=None, expectedWarnings=None): # ExpectedInfo should be list of expected tests if expectedInfo is None: expectedInfo = [treatmentInfo] try: # print(self.state) if self.state == 'normal' or self.state == 'saved': self.click_add_treatment() self.addTreatmentForm = addTreatmentForm.AddTreatmentForm( self.driver) WDW(self.driver, 10).until(lambda x: self.addTreatmentForm.load()) if self.addTreatmentForm.add_treatment(treatmentInfo): WDW(self.driver, 10).until( lambda x: self.load({'tests': expectedInfo}, 'saved')) else: print('Failed to add treatment') else: # todo: handle fresh popup pass return True except MsgError: # Is add treatment expected to fail? errorType = self.error['errorType'] if expectedError and errorType.lower() == expectedError.lower(): return True print(self.error['errorMsg']) if errorType == 'undefined': print('Undefined error: ' + self.error['errorText']) except WarningError: # Is form submission expected to have warning? unexpectedWarnings = [] if expectedWarnings: # Go through self.warnings and check each warningType matches an expectedWarning # Append warnings that aren't expected to unexpectedWarnings for i, warning in enumerate(self.warnings): expected = False warningType = warning['type'] for expectedWarning in expectedWarnings: if expectedWarning == warningType: expected = True if not expected: unexpectedWarnings.append(self.warnings[i]) if unexpectedWarnings: for unexpected in unexpectedWarnings: print(unexpected['msg']) if warningType == 'undefined': print('Undefined warning: ' + unexpected['text']) else: return True return True def edit_treatment(self, treatmentIndex, editType, expectedInfo=None, editInfo=None, popupAction='confirm'): if self.state == 'saved': actions = self.load_actions(self.saved_tests[treatmentIndex]) try: action = actions[editType] self.util.click_el(action) except KeyError: print(str(editType) + ' Is not a valid treatment option') raise KeyError('Not a valid treatment option') if editType == 'delete': self.delete_treatment() else: if editType == 'treatments': self.edit_treatments(editInfo, expectedInfo) elif editType == 'outcomes': self.edit_outcomes(editInfo, expectedInfo) elif editType == 'side effects': self.edit_side_effects(editInfo, expectedInfo) # self.clear_alert() print('Done editing: ' + str(editType)) def delete_all_treatments(self): if self.state == 'saved': num_treatments = len(self.saved_tests) for i, saved_test in enumerate(self.saved_tests): print('deleting treatment #' + str(i)) actions = self.load_actions(self.saved_tests[0]) try: self.util.click_el(actions['delete']) except KeyError: print('"delete" Is not a valid treatment option') raise KeyError('Not a valid treatment option') self.delete_treatment() # Should be 1 less treatment WDW(self.driver, 10).until(lambda x: self.load( {'meta': { 'num_treatments': num_treatments - (i + 1) }})) def view_options(self): if self.view_options_button: self.util.click_el(self.view_options_button) url = self.driver.current_url if '/treatment-options' not in url: return False else: print( 'Treatment & Outcomes view does not have "View Options" button' ) return False
class EditTreatmentPopup(): def __init__(self, driver): self.driver = driver self.util = UtilityFunctions(self.driver) def load(self, expectedValues=None): WDW(self.driver, 10).until_not(EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) self.container = self.driver.find_element_by_class_name('editroll') # Should only 1 on T&O view self.buttons = self.container.find_elements_by_class_name('green-hvr-bounce-to-top') return self.validate(expectedValues) def validate(self, expectedValues): self.failures = [] # Basic validation if len(self.buttons) != 2: self.failures.append('editTreatmentPopup: Expected 2 buttons, loaded ' + str(len(self.buttons))) if self.util.get_text(self.buttons[0]) != 'CANCEL': self.failures.append('editTreatmentPopup: Unexpected text on cancel button: ' + self.util.get_text(self.buttons[0])) if self.util.get_text(self.buttons[1]) != 'SAVE': self.failures.append('editTreatmentPopup: Unexpected text on save button: ' + self.util.get_text(self.buttons[1])) if expectedValues: print('editTreatmentPopup: Need to validate expectedValues') if len(self.failures) > 0: for failure in self.failures: print(failure) return False return True def parse_select_all(self, questionInfo, questionCont): done = False count = 0 while not done and count < 5: try: # Select options in specified in optionInfo # De-selecting options not contained in optionInfo name_checker = ['Severity of the side effects', 'Cost of the treatment', 'Too much travel'] radios = questionCont.find_elements_by_class_name('radio') suboption_filter = [] # Add index of any suboptions radio buttons to this list. Skip over them for i, radio in enumerate(radios): if i not in suboption_filter: inputs = radio.find_elements_by_tag_name('input') spans = radio.find_elements_by_tag_name('span') if len(inputs) == 0: print('EditTreatmentForm: radio option has no inputElements?') elif len(spans) == 0: print('EditTreatmentForm: radio option has no spanElements?') optionName = self.util.get_text(spans[0]) print('optionName: ' + optionName) optionInput = inputs[0] optionInfo = questionInfo.get(optionName, False) # raw_input('optionInfo: ' + str(optionInfo)) subOptions = False if optionInfo != False: # select input, enter comment, check for subquestions if not optionInput.is_selected(): self.util.click_radio(optionInput) self.util.set_input(radio, optionInfo.get('comment', '')) # Check for suboptions or select-all subOptions = optionInfo.get('options', False) if not subOptions: subOptions = optionInfo.get('select-all', False) else: # De-select, clear comment, update inputs (might have hidden subquestions) if optionInput.is_selected(): self.util.click_radio(optionInput) self.util.set_input(radio, '') inputs = radio.find_elements_by_tag_name('input') # Don't iterate over suboptions if len(inputs) > 1: for inputIndex, inputEl in enumerate(inputs): if inputIndex > 0: print('skipping ' + str(i + inputIndex)) suboption_filter.append(i + inputIndex) if subOptions: self.parse_select_all(subOptions, radio) done = True except StaleElementReferenceException: print('failed to parse select-all: ' + str(count)) count += 1 time.sleep(.2) if count == 5: print('EditTreatmentPopup: failed to parse select-all') def parse_complex(self, complexInfo, questionCont): # For questions w/ multiple sections (sideEffects, chemotherapy drugs, medications added/removed) # Loop through complexInfo and select given options for each category # De-select options not contained in complexInfo # Wait for categories to show up categories = None loaded = False count = 0 while not loaded and count < 5: # Doesn't immediately load categories = questionCont.find_elements_by_class_name('col-md-6') if categories: loaded = True else: time.sleep(.2) count += 1 question = {} for i, category in enumerate(categories): # Has issues loading category name sometimes. # Make sure it's loaded before looking for options loadedCategoryName = False count = 0 while not loadedCategoryName and count < 5: try: categoryName = self.util.get_text(category.find_element_by_class_name('treatment-group')) loadedCategoryName = True except NoSuchElementException: categoryName = None if categoryName: # Loaded name! Parse through category options categoryOptions = complexInfo.get(categoryName, False) options = {} for radio in category.find_elements_by_class_name('radio'): inputs = radio.find_elements_by_tag_name('input') labels = radio.find_elements_by_tag_name('label') label = labels[0] optionName = self.util.get_text(label) optionInput = label.find_element_by_tag_name('input') optionInfo = False if categoryOptions: optionInfo = categoryOptions.get(optionName, False) if optionInfo != False: # select input, enter comment/intensity if not optionInput.is_selected(): self.util.click_radio(optionInput) self.util.set_input(radio, optionInfo.get('comment', '')) self.set_intensity(radio, optionInfo.get('intensity', None)) else: # De-select, clear comment, update inputs (might have hidden subquestions) if optionInput.is_selected(): self.util.click_radio(optionInput) self.util.set_input(radio, '') inputs = radio.find_elements_by_tag_name('input') else: # Failed to find categoryName count += 1 time.sleep(.2) if complexInfo.get('date', None): print('complex question has date. Need to set it') def set_intensity(self, container, value): try: sliderEl = container.find_element_by_class_name('rc-slider-handle') except NoSuchElementException: print('SideEffectsForm: failed to load sliderEl') curValue = sliderEl.get_attribute('aria-valuenow') # Need to change intensity value? if value != curValue: xOffset = None # Every time offset doesn't work, increase by 5 and try again additionalOffset = 0 while str(curValue) != str(value) and additionalOffset < 50: if curValue != 1: # reset to base position AC(self.driver).drag_and_drop_by_offset(sliderEl, -200, 0).perform() # Calculate offset # Note: monitor and window sizes affect this. if xOffset != None: # First offset wasn't correct. Increment amount of offset additionalOffset += 4 xOffset = 11*(value - 1) + additionalOffset AC(self.driver).drag_and_drop_by_offset(sliderEl, xOffset, 0).perform() curValue = sliderEl.get_attribute('aria-valuenow') def set_input(self, container, value): # Return if able to set value into textarea or input in container. try: textareaEl = container.find_element_by_tag_name('textarea') textareaEl.clear() textareaEl.send_keys(value) return True except NoSuchElementException: try: inputEl = container.find_element_by_tag_name('input') if inputEl.get_attribute('type') == 'text': inputEl.clear() inputEl.send_keys(value) return True except NoSuchElementException: return False def edit_treatment(self, newInfo, popupType, action='save'): # Submit info if popupType == 'side effects': self.parse_complex(newInfo['options'], self.container) elif popupType == 'outcomes': self.parse_select_all(newInfo['options'], self.container) # Save or cancel if action == 'save': self.util.click_el(self.buttons[1]) elif action == 'cancel': self.util.click_el(self.buttons[0]) WDW(self.driver, 15).until_not(EC.presence_of_element_located((By.CLASS_NAME, 'overlay'))) return True