示例#1
0
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 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