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
Exemplo n.º 2
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 FullHealthMyelomaForm():

	def __init__(self, driver):
		self.driver = driver
		self.util = UtilityFunctions(self.driver)
		self.load()

	def load(self):
		WDW(self.driver, 20).until_not(EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))
		time.sleep(1)
		self.form = self.driver.find_elements_by_tag_name('form')[-1]
		self.sectionConts = self.form.find_elements_by_class_name('after-head-row')
		self.load_sections()
		self.save_button = self.form.find_element_by_tag_name('button')

		# self.sections = [
		# 	{'1': [
		# 		{'options': {
		# 			'yes': inputEl,
		# 			'no': inputEl,
		# 		}},
		# 		{'date': inputEl},
		# 	]},
		# ]

		# Get input for 1st section, 2st row, second question 'yes'
		# self.sections[0][1]['2']['options']['yes']

	def load_sections(self):
		self.sections = []
		for i, section in enumerate(self.sectionConts):
			# print('loading section: ' + str(i))
			# Contains primary and any visible secondary questions
			self.questionContainers = section.find_elements_by_class_name('ques_group_cls')
			self.subQuestionIndices = []
			questionList = []
			for questionIndex, questionContainer in enumerate(self.questionContainers):
				# print('loading question: ' + str(questionIndex))
				# Primary or secondary question?
				subquestions = questionContainer.find_elements_by_class_name('ques_group_cls')
				if len(subquestions) > 0:
					for subquestionIndex in xrange(len(subquestions)):
						subIndex = questionIndex+1 + subquestionIndex
						print('subquestion: ' + str(subIndex))
						self.subQuestionIndices.append(subIndex)

				if questionIndex not in self.subQuestionIndices:
					# Primary question
					questionList.append(self.load_questions(questionContainer))
			self.sections.append(questionList)

	def load_questions(self, questionContainer, isSecondary=False):
		question = {}
		questionIndex = None
		# First is primary. Any additional ones are secondary
		questionConts = questionContainer.find_elements_by_class_name('cls_survey_question')
		if isSecondary:
			questionConts = [questionContainer]

		for i, questionCont in enumerate(questionConts):
			textInput = None
			radioOptions = None
			options = {}
			secondary_questions = []
			if i == 0: # Primary
				try:
					# look for radio options
					radioContainers = questionCont.find_elements_by_class_name('dynamic-radio')
					for radioCont in radioContainers:
						inputs = radioCont.find_elements_by_tag_name('input')
						spans = radioCont.find_elements_by_tag_name('span')
						optionName = self.util.get_text(spans[0]).lower()
						options[optionName] = inputs[0]
					if len(radioContainers) == 0:
						textInput = questionCont.find_element_by_tag_name('input')
				except NoSuchElementException:
					pass

				# Look for an input

			else: # secondary
				secondary_questions.append(self.load_questions(questionCont, True))
			question['container'] = questionCont
			if options:
				question['options'] = options
			if textInput:
				question['textInput'] = textInput
			if secondary_questions:
				question['secondary_questions'] = secondary_questions

		return question
class MyelomaGeneticsView(view.View):
    post_url = 'myeloma-genetics'

    def load(self, riskInfo=None):
        self.util = UtilityFunctions(self.driver)
        try:
            WDW(self.driver, 20).until_not(
                EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))

            self.menu = menu.Menu(self.driver)
            self.header = header.AuthHeader(self.driver)

            self.load_test_table()

            # When user has already filled out info
            # addDiagnosisButtons = self.driver.find_elements_by_class_name('addDiagnoisisButton')
            # self.add_fish_button = addDiagnosisButtons[0]
            # self.add_gep_button = addDiagnosisButtons[1]
            # self.add_ngs_button = addDiagnosisButtons[2]

            # buttons = self.driver.find_elements_by_tag_name('button')
            # self.upload_file_button = buttons[2]

            # cont = self.driver.find_element_by_class_name('genetics-btn')
            # self.continue_button = cont.find_element_by_tag_name('button')

            # # self.load_fish_table()
            # # self.load_gep_table()
            # # self.load_ngs_table()
            # # self.load_highRisk_table()

            # self.container = self.driver.find_element_by_id('page-content-wrapper')
            # tooltips = self.container.find_elements_by_tag_name('img')
            # self.fish_tooltip = tooltips[0]
            # self.gep_tooltip = tooltips[1]
            # self.ngs_tooltip = tooltips[2]
            # self.high_risk_tooltip = tooltips[3]

            # When user hasn't filled anything out
            # todo
            return True
        except (NoSuchElementException, StaleElementReferenceException,
                IndexError) as e:
            return False

    def load_fish_table(self):
        self.fish_tests = []
        fishTable = ''
        try:
            fishTable = self.driver.find_element_by_id('fish_table')
            rows = fishTable.find_elements_by_class_name('table_row')
        except NoSuchElementException:
            pass
        labInfo = []  # add text from each header row to values list
        if fishTable:
            for rowIndex, row in enumerate(rows):
                labResult = {}
                divs = row.find_elements_by_tag_name('div')
                tds = row.find_elements_by_tag_name('td')
                # for divIndex, div in enumerate(divs):
                for tdIndex, td in enumerate(tds):
                    if rowIndex == 0:
                        labInfo.append(td.text.lower())
                    else:
                        key = labInfo[tdIndex]
                        if key.lower() == 'actions':
                            actions = []
                            self.edit_button = row.find_element_by_class_name(
                                'edit-treatment-icon')
                            self.delete_button = row.find_element_by_class_name(
                                'delete-treatment-icon')
                            actions.append(self.edit_button)
                            actions.append(self.delete_button)
                            labResult[key] = actions
                        else:
                            text = td.text
                            labResult[key] = text

                self.fish_tests.append(labResult)

    def load_gep_table(self):
        self.gep_tests = []
        gepTable = ''
        try:
            gepTable = self.driver.find_element_by_id('gep_table')
        except NoSuchElementException:
            pass
        if gepTable:
            rows = gepTable.find_elements_by_class_name('table_row')
            labInfo = []  # add text from each header row to values list
            for rowIndex, row in enumerate(rows):
                labResult = {}
                divs = row.find_elements_by_tag_name('div')
                tds = row.find_elements_by_tag_name('td')
                # for divIndex, div in enumerate(divs):
                for tdIndex, td in enumerate(tds):
                    if rowIndex == 0:
                        labInfo.append(td.text.lower())
                    else:
                        key = labInfo[tdIndex]
                        if key.lower() == 'actions':
                            actions = []
                            self.edit_button = row.find_element_by_class_name(
                                'edit-treatment-icon')
                            self.delete_button = row.find_element_by_class_name(
                                'delete-treatment-icon')
                            actions.append(self.edit_button)
                            actions.append(self.delete_button)
                            labResult[key] = actions
                        else:
                            text = td.text
                            labResult[key] = text
                if labResult:
                    self.gep_tests.append(labResult)

    def load_ngs_table(self):
        self.ngs_tests = []
        ngsTable = ''
        try:
            ngsTable = self.driver.find_element_by_id('ngs_table')
            rows = ngsTable.find_elements_by_class_name('table_row')
        except NoSuchElementException:
            pass
        labInfo = []  # add text from each header row to values list
        if ngsTable:
            for rowIndex, row in enumerate(rows):
                labResult = {}
                tds = row.find_elements_by_tag_name('td')
                # for divIndex, div in enumerate(divs):
                for tdIndex, td in enumerate(tds):
                    if rowIndex == 0:
                        labInfo.append(td.text.lower())
                    else:
                        key = labInfo[tdIndex]
                        if key.lower() == 'actions':
                            actions = []
                            self.edit_button = row.find_element_by_class_name(
                                'edit-treatment-icon')
                            self.delete_button = row.find_element_by_class_name(
                                'delete-treatment-icon')
                            actions.append(self.edit_button)
                            actions.append(self.delete_button)
                            labResult[key] = actions
                        else:
                            text = td.text
                            labResult[key] = text

                self.ngs_tests.append(labResult)

    def load_highRisk_table(self):
        self.highRiskTable = self.driver.find_element_by_id('yesno_table')
        rows = self.highRiskTable.find_elements_by_class_name('table_row')
        labInfo = []
        self.highRisk_tests = {}
        self.highRisk_tests[
            'edit'] = self.highRiskTable.find_element_by_class_name(
                'edit-treatment-icon')
        # {'High Beta-2 Microglobulin': 'Yes',
        # 	'High Lactate Dehydrogenase': 'I dont know',
        # 	'Low albumin': 'I dont know',
        # 	'edit': webElement,
        # }
        for i, row in enumerate(rows):
            if i > 0 and i < 4:
                tds = row.find_elements_by_tag_name('td')
                for tdIndex, td in enumerate(tds):
                    if tdIndex == 0:
                        name = td.text
                    else:
                        value = td.text
                self.highRisk_tests[name] = value

    def validate_gep_test(self, gepInfo):
        failures = []
        if len(self.gep_tests) > 0:
            loadedInfo = self.gep_tests[-1]
        else:
            loadedInfo = self.gep_tests
        if loadedInfo:
            if self.convert_date(
                    loadedInfo['date'].lower()) != gepInfo['test_gep_date']:
                failures.append(
                    'GEP Table: Expecting ' + '"' +
                    str(gepInfo['test_gep_date']) + '"' + ', got ' + '"' +
                    str(self.convert_date(loadedInfo['date'].lower())) + '"')
            if loadedInfo['comment'] != gepInfo['gep_comment']:
                failures.append('GEP Table: Expecting ' + '"' +
                                str(gepInfo['gep_comment']) + '"' + ', got ' +
                                '"' + str(loadedInfo['comment']) + '"')

            if len(failures) > 0:
                for failure in failures:
                    print(failure)
                raise NoSuchElementException(
                    'Failed to load myelomaGeneticsView')
        else:
            pass

    def validate_risk_table(self, riskInfo):
        failures = []
        if riskInfo:
            rows = self.highRiskTable.find_elements_by_class_name('table_row')
            for i, row in enumerate(rows):
                tds = row.find_elements_by_tag_name('td')
                if i == 0:
                    if tds[0].text != 'Test':
                        failures.append(
                            'High Risk Table: Expecting text "Test", got ' +
                            '"' + str(tds[0].text) + '"')
                    if tds[1].text != 'Answer':
                        failures.append(
                            'High Risk Table: Expecting text "Answer", got ' +
                            '"' + str(tds[1].text) + '"')
                if i == 1:
                    if tds[0].text != 'High Beta-2 Microglobulin':
                        failures.append(
                            'High Risk Table: Expecting text "High Beta-2 Microglobulin", got'
                            + '"' + str(tds[0].text) + '"')
                    if tds[1].text.replace("'", '') != riskInfo['high_b2m']:
                        failures.append('High Risk Table: Expecting text ' +
                                        '"' + str(riskInfo['high_b2m']) + '"' +
                                        ' got ' + '"' + str(tds[1].text) + '"')
                if i == 2:
                    if tds[0].text != 'High Lactate Dehydrogenase':
                        failures.append(
                            'High Risk Table: Expecting text "High Lactate Dehydrogenase", got'
                            + '"' + str(tds[0].text) + '"')
                    if tds[1].text.replace("'", '') != riskInfo['high_ldh']:
                        failures.append('High Risk Table: Expecting text ' +
                                        '"' + str(riskInfo['high_ldh']) + '"' +
                                        ' got ' + '"' + str(tds[1].text) + '"')
                if i == 3:
                    if tds[0].text != 'Low albumin':
                        failures.append(
                            'High Risk Table: Expecting text "Low albumin", got '
                            + '"' + str(tds[0].text) + '"')
                    if tds[1].text.replace("'", '') != riskInfo['low_albumin']:
                        failures.append('High Risk Table: Expecting text ' +
                                        '"' + str(riskInfo['low_albumin']) +
                                        '"' + ' got ' + '"' +
                                        str(tds[1].text) + '"')

            if len(failures) > 0:
                for failure in failures:
                    print(failure)
                raise NoSuchElementException(
                    'Failed to load myelomaGeneticsView')

    def add_fish_test(self, fishInfo, action='save'):
        self.add_fish_button.click()
        self.fishTestForm = fishTestForm.FishTestForm(self.driver)
        WDW(self.driver, 10).until(lambda x: self.fishTestForm.load())
        self.fishTestForm.submit(fishInfo, action)
        WDW(self.driver, 10).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 add_gep_test(self, gepInfo, action='cancel'):
        self.add_gep_button.click()
        self.gepTestForm = gepTestForm.GepTestForm(self.driver)
        WDW(self.driver, 10).until(lambda x: self.gepTestForm.load())
        self.gepTestForm.submit(gepInfo, action)
        WDW(self.driver, 10).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')))
        self.load()
        self.validate_gep_test(gepInfo)

    def add_ngs_test(self, ngsInfo, action='save'):
        self.add_ngs_button.click()
        self.ngsTestForm = ngsTestForm.NgsTestForm(self.driver)
        WDW(self.driver, 10).until(lambda x: self.ngsTestForm.load())
        self.ngsTestForm.submit(ngsInfo, action)
        WDW(self.driver, 10).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_test(self,
                  testType,
                  testIndex,
                  testValues,
                  action='delete',
                  popUpAction='confirm'):
        test = self.get_test(testType, testIndex)

        if testType == 'fish':
            if action == 'edit':
                test['actions'][0].click()
            else:
                test['actions'][1].click()
                self.popUpForm = popUpForm.PopUpForm(self.driver)
                WDW(self.driver, 10).until(lambda x: self.popUpForm.load())
                self.popUpForm.confirm(popUpAction)

        elif testType == 'gep':
            if action == 'edit':
                test['actions'][0].click()
            else:
                test['actions'][1].click()
                self.popUpForm = popUpForm.PopUpForm(self.driver)
                WDW(self.driver, 10).until(lambda x: self.popUpForm.load())
                self.popUpForm.confirm(popUpAction)

        elif testType == 'ngs':
            if action == 'edit':
                test['actions'][0].click()
            else:
                test['actions'][1].click()
                self.popUpForm = popUpForm.PopUpForm(self.driver)
                WDW(self.driver, 10).until(lambda x: self.popUpForm.load())
                self.popUpForm.confirm(popUpAction)
        else:
            if action == 'edit':
                self.highRisk_tests['edit'].click()
                self.edit_high_risk(testValues, 'save')
            else:
                print('Error: Edit High Risk Test action not possible')

        WDW(self.driver, 10).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_high_risk(self, riskInfo, action='save'):
        self.editHighRiskForm = editHighRiskForm.EditHighRiskForm(self.driver)
        WDW(self.driver, 10).until(lambda x: self.editHighRiskForm.load())
        self.editHighRiskForm.submit(riskInfo, action)
        WDW(self.driver, 10).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')))
        self.validate_risk_table(riskInfo)

    def upload_file(self, action='cancel'):
        self.upload_file_button.click()
        self.uploadFileForm = uploadFileForm.UploadFileForm(self.driver)
        WDW(self.driver, 10).until(lambda x: self.uploadFileForm.load())
        self.uploadFileForm.confirm(action)
        WDW(self.driver, 10).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 get_test(self, testType, testIndex):
        if testType == 'fish':
            return self.fish_tests[testIndex]
        elif testType == 'gep':
            return self.gep_tests[testIndex]
        elif testType == 'ngs':
            return self.ngs_tests[testIndex]
        else:
            return self.highRisk_tests

    def tooltip(self):
        p = self.container.find_elements_by_class_name('tooltip-p')
        index = p[0].text.find(' ')
        if p[0].text[:index] != 'FISH':
            return False

        if self.util.get_text(
                p[1]
        ) != 'Gene Expression Profiling (GEP) is the measurement of the activity, or expression, of thousands of genes at once. This test can help identify standard risk and high risk genomic features of the myeloma cells in more depth.':
            print('tooltip not clicked correctly: ' +
                  str(self.util.get_text(p[1])))
            return False

        if self.util.get_text(
                p[2]
        ) != 'Next Generation Sequencing looks at the myeloma DNA and RNA and identifies how the mutations are functioning, how the myeloma cells are evolving and how your myeloma may respond to treatment. Currently, NGS testing is typically performed at myeloma academic centers only.':
            print('tooltip not clicked correctly: ' +
                  str(self.util.get_text(p[2])))
            return False

        if self.util.get_text(
                p[3]
        ) != 'Risk in myeloma is tied to disease stage, chromosomal abnormalities, disease biology, and gene expression.  In the Myeloma Genetics page we will gather more details about risk.':
            print('tooltip not clicked correctly: ' +
                  str(self.util.get_text(p[3])))
            return False
        return True

    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 load_test_table(self):
        self.genetic_tests = []
        tables = self.driver.find_elements_by_class_name('divTable')
        for tableIndex, table in enumerate(tables):
            rows = table.find_elements_by_class_name('divTableRow')
            if tableIndex == 0:
                for rowIndex, row in enumerate(rows):
                    cells = row.find_elements_by_class_name('divTableCell')
                    if rowIndex == 0:
                        self.headerInfo = []
                        for cell in cells:
                            self.headerInfo.append(cell.text)
class HealthLifestyleForm():
    def __init__(self, driver):
        self.driver = driver
        self.util = UtilityFunctions(self.driver)
        self.load()

    def load(self):
        WDW(self.driver, 20).until_not(
            EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))
        time.sleep(1)
        self.form = self.driver.find_elements_by_tag_name('form')[-1]
        self.sectionConts = self.form.find_elements_by_class_name(
            'after-head-row')

        self.load_sections()
        self.save_button = self.form.find_element_by_tag_name('button')
        # print('sections: ' + str(self.sections))

        # self.validate()
        return True

    def load_sections(self):
        self.sections = []
        for i, section in enumerate(self.sectionConts):
            # print('loading section: ' + str(i))
            # Contains primary and any visible secondary questions
            self.questionContainers = section.find_elements_by_class_name(
                'ques_group_cls')
            self.subQuestionIndices = []
            questionList = []
            for questionIndex, questionContainer in enumerate(
                    self.questionContainers):
                # print('loading question: ' + str(questionIndex))
                # Primary or secondary question?
                subquestions = questionContainer.find_elements_by_class_name(
                    'ques_group_cls')
                if len(subquestions) > 0:
                    for subquestionIndex in xrange(len(subquestions)):
                        subIndex = questionIndex + 1 + subquestionIndex
                        print('subquestion: ' + str(subIndex))
                        self.subQuestionIndices.append(subIndex)

                if questionIndex not in self.subQuestionIndices:
                    # Primary question
                    questionList.append(self.load_questions(questionContainer))
            self.sections.append(questionList)

    def load_questions(self, questionContainer, isSecondary=False):
        question = {}
        questionIndex = None
        # First is primary. Any additional ones are secondary
        questionConts = questionContainer.find_elements_by_class_name(
            'cls_survey_question')
        if isSecondary:
            questionConts = [questionContainer]

        for i, questionCont in enumerate(questionConts):
            textInput = None
            radioOptions = None
            options = {}
            secondary_questions = []
            if i == 0:  # Primary
                try:
                    # look for radio options
                    radioContainers = questionCont.find_elements_by_class_name(
                        'dynamic-radio')
                    dropdownContainers = questionCont.find_elements_by_class_name(
                        'is-clearable')
                    for radioCont in radioContainers:
                        inputs = radioCont.find_elements_by_tag_name('input')
                        spans = radioCont.find_elements_by_tag_name('span')
                        optionName = self.util.get_text(spans[0]).lower()
                        options[optionName] = inputs[0]
                    if dropdownContainers:
                        question['dropdowns'] = dropdownContainers

                    if len(radioContainers) == 0 and len(
                            dropdownContainers) == 0:
                        textInput = questionCont.find_element_by_tag_name(
                            'input')
                except NoSuchElementException:
                    pass

                # Look for an input

            else:  # secondary
                secondary_questions.append(
                    self.load_questions(questionCont, True))
            question['container'] = questionCont
            if options:
                question['options'] = options
            if textInput:
                question['textInput'] = textInput
            if secondary_questions:
                question['secondary_questions'] = secondary_questions

        return question

    def set_dropdown(self, container, value):
        # Figure out if you need to click 'Select-value-label' or 'Select-placeholder' element
        dropdown_preSet = False
        try:
            dropdown_value = container.find_element_by_class_name(
                'Select-value-label')
            dropdown_placeholder = None
            dropdown_preSet = True
        except NoSuchElementException:
            dropdown_value = None
            dropdown_placeholder = container.find_element_by_class_name(
                'Select-placeholder')

        # click it
        if dropdown_preSet:
            dropdown_value.click()
        else:
            dropdown_placeholder.click()

        # load options in dropdown
        options = {}
        try:
            menu = self.form.find_element_by_class_name('Select-menu-outer')
            divs = menu.find_elements_by_tag_name('div')
            for i, div in enumerate(divs):
                if i != 0:
                    options[div.text.lower()] = divs[i]
        except NoSuchElementException:
            print('Unable to find dropdown items for first diagnosis')

        # click option
        try:
            option = options[value.lower()]
            option.click()
        except (IndexError, KeyError) as e:
            print('invalid index: ' + value)
            for option in options:
                print(option)
Exemplo n.º 6
0
class ForgotPwView(view.View):
    post_url = 'forgot-password'

    def load(self):
        self.util = UtilityFunctions(self.driver)
        try:
            # Crap on left
            self.forgotPwForm = forgotPwForm.ForgotPwForm(self.driver)
            self.signIn_link = self.driver.find_elements_by_tag_name('a')[-1]
            self.validate()
            return True
        except (NoSuchElementException, StaleElementReferenceException,
                IndexError) as e:
            return False

    def validate(self):
        failures = []
        if self.util.get_text(self.signIn_link) != 'Sign In':
            failures.append(
                '1. Sign In link. Expecting text "Sign In", got "' +
                self.util.get_text(self.signIn_link) + '"')
        if len(failures) > 0:
            print(failures)
            raise NoSuchElementException('Failed to load HomeView')

    def createErrorObj(self, errorText):
        errorType = 'undefined'
        errorMsg = ''

        if 'confirm your email address' in errorText:
            errorType = 'confirmation'
            errorMsg = 'homeView.login: Confirmation error'
        elif 'invalid username or password' in errorText:
            errorType = 'invalid credentials'
            errorMsg = 'homeView.login: Invalid Credentials error'

        return {
            'text': errorText,
            'type': errorType,
            'msg': errorMsg,
        }

    def reset_password(self,
                       email,
                       expectedErrorType=None,
                       expectedWarning=None):
        try:
            if self.forgotPwForm.submit_form(email):
                # Should be on home page
                url = self.driver.current_url
                if '/about-me' not in url:  # Didn't end up on right page
                    self.error = self.readErrors()
                    self.warning = self.forgotPwForm.read_warning()
                    if self.error:
                        raise MsgError('Login Error')
                    elif self.warning:
                        raise WarningError('Login Warning')
            return True
        except MsgError:
            # Is login expected to fail?
            errorType = self.error['type']
            if expectedErrorType and errorType.lower(
            ) != expectedErrorType.lower():
                print(self.error['msg'])
                if errorType == 'undefined':
                    print('Undefined error: ' + self.error['text'])
            else:
                return True
        except WarningError:
            # Is pw reset form expected to have warning?
            warningType = self.warning['type']
            if expectedWarning and warningType.lower(
            ) != expectedWarning.lower():
                print(self.warning['msg'])
                if warningType == 'undefined':
                    print('Undefined warning: ' + self.warning['text'])
            else:
                return True
        return False

    def click_link(self, link):
        if link == 'sign in':
            self.signIn_link.click()
class VaccinationsSurveyForm():
    def __init__(self, driver):
        self.driver = driver
        self.util = UtilityFunctions(self.driver)

    def load(self):
        WDW(self.driver, 20).until_not(
            EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))
        time.sleep(1)
        self.form = self.driver.find_elements_by_tag_name('form')[1]
        buttons = self.form.find_elements_by_tag_name('button')

        self.close_button = buttons[0]
        self.save_button = buttons[1]
        self.cancel_button = buttons[2]
        self.load_form()
        self.loadedData = self.questionList

        return True

    def load_form(self):
        self.questionContainers = self.form.find_elements_by_class_name(
            'ques_group_cls')
        self.subQuestionIndices = []
        self.questionList = []
        for questionIndex, questionContainer in enumerate(
                self.questionContainers):
            # print('loading question: ' + str(questionIndex))
            # Primary or secondary question?
            subquestions = questionContainer.find_elements_by_class_name(
                'ques_group_cls')
            if len(subquestions) > 0:
                for subquestionIndex in xrange(len(subquestions)):
                    subIndex = questionIndex + 1 + subquestionIndex
                    print('subquestion: ' + str(subIndex))
                    self.subQuestionIndices.append(subIndex)

            if questionIndex not in self.subQuestionIndices:
                # Primary question
                self.questionList.append(
                    self.load_questions(questionContainer))

    def load_questions(self, questionContainer, isSecondary=False):
        question = {}
        questionIndex = None
        # First is primary. Any additional ones are secondary
        questionConts = questionContainer.find_elements_by_class_name(
            'question')

        if isSecondary:
            questionConts = [questionContainer]

        for i, questionCont in enumerate(questionConts):
            # print('loading questionCont: ' + str(i))
            textInput = None
            radioOptions = None
            options = {}
            secondary_questions = []
            if i == 0:  # Primary
                try:
                    # look for radio options
                    radioContainers = questionCont.find_elements_by_class_name(
                        'dynamic-radio')
                    for radioCont in radioContainers:
                        inputs = radioCont.find_elements_by_tag_name('input')
                        spans = radioCont.find_elements_by_tag_name('span')
                        optionName = self.util.get_text(spans[0]).lower()
                        options[optionName] = inputs[0]
                    if len(radioContainers) == 0:
                        textInput = questionCont.find_element_by_tag_name(
                            'input')
                except NoSuchElementException:
                    pass

                # Look for an input

            else:  # secondary
                # Some 'question' elements don't have questions
                if len(questionCont.find_elements_by_tag_name('input')) > 0:
                    # print('loading secondary question: ' + str(i))
                    secondary_questions.append(
                        self.load_questions(questionCont, True))
            question['container'] = questionCont
            if options:
                question['options'] = options
            if textInput:
                question['textInput'] = textInput
            if secondary_questions:
                question['secondary_questions'] = secondary_questions
        # print('returning: ' + str(question))
        return question

    def submit(self, mrdInfo, action='cancel'):
        for questionIndex, question in enumerate(mrdInfo):
            print('answering question: ' + str(questionIndex))
            loadedQuestion = self.loadedData[questionIndex]

            secondaryInfo = question.get('secondary', None)
            questionOptions = loadedQuestion.get('options', None)
            textarea = loadedQuestion.get('textInput', None)
            dropdowns = loadedQuestion.get('dropdowns', None)
            multipleDropdown = question.get('multiple_dropdown')

            if questionOptions:
                WDW(self.driver, 20).until_not(
                    EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))
                inputEl = questionOptions[question['option']]
                inputEl.click()
                if not inputEl.is_selected():
                    print('Clicked input, but it is not selected')
                    return False

            if textarea:
                textarea.send_keys(question.get('textInput', None))

            if dropdowns:
                if multipleDropdown:
                    self.form.set_dropdown(
                        dropdowns[0], question.get('multiple_dropdown', None))
                    AC(self.driver).send_keys(Keys.ESCAPE).perform()
                else:
                    self.form.set_dropdown(dropdowns[0],
                                           question.get('dropdown', None))

            if secondaryInfo:  # Question has secondary response
                # Reload question and get loadedInfo for secondary question
                WDW(self.driver, 20).until(lambda x: self.load())
                loadedSecondaryInfo = self.loadedData[questionIndex].get(
                    'secondary_questions', None)

                secondaryText = secondaryInfo.get('text', None)
                secondaryOptions = secondaryInfo.get('options', None)
                if secondaryText:
                    print(loadedSecondaryInfo)
                    textInput = loadedSecondaryInfo[0]['textInput']
                    if textInput:
                        textInput.clear()
                        textInput.send_keys(secondaryText)
                    else:
                        print('could not find textarea for question[' +
                              str(questionIndex) + ']')
                else:
                    radioOptions = loadedSecondaryInfo[0]['options']
                    radioOptions[secondaryOptions].click()

            time.sleep(1)
        if action == 'save':
            self.save_button.click()
        else:
            self.cancel_button.click()
        return True
Exemplo n.º 8
0
class DatePicker():
    """Date picker for MonthYear input"""
    def __init__(self, driver, container):
        self.driver = driver
        # Throw exception if container doesn't contain date stuff
        cont = container.find_element_by_class_name('Select--single')
        self.container = container
        self.util = UtilityFunctions(self.driver)

    def load(self, expectedState=None):
        try:
            # self.picker_state = self.get_picker_state()
            # if self.picker_state == 'wrong container':
            #   print('wrong datepicker container')
            #   return False
            # else:
            dropdownConts = self.container.find_elements_by_class_name(
                'Select--single')
            if len(dropdownConts) < 2:
                print('not enough dropdown containers')
                return False

            self.month_cont = dropdownConts[0]
            self.year_cont = dropdownConts[1]

            return True
        except (NoSuchElementException, StaleElementReferenceException) as e:
            print('failed to load datePicker')
            return False

    def get_picker_state(self):
        state = 'normal'
        # Make sure container has datePicker in it
        try:
            cont = self.container.find_element_by_class_name('Select--single')
        except NoSuchElementException:
            state = 'wrong container'
        return state


########################### General ##############################

    def set_date(self, date):
        month = self.parse_date(date, 'month')
        year = self.parse_date(date, 'year')
        self.load()
        print('setting date')
        print(month)
        print(year)
        WDW(self.driver,
            10).until(lambda x: self.set_dropdown(self.month_cont, month))
        WDW(self.driver,
            10).until(lambda x: self.set_dropdown(self.year_cont, year))

        # Wait for datepicker to disappear
        time.sleep(.4)

    def set_dropdown(self, container, value):
        # Figure out if you need to click 'Select-value-label' or 'Select-placeholder' element
        dropdown_preSet = False
        try:
            dropdown_value = container.find_element_by_class_name(
                'Select-value-label')
            dropdown_placeholder = None
            dropdown_preSet = True
        except NoSuchElementException:
            dropdown_value = None
            dropdown_placeholder = container.find_element_by_class_name(
                'Select-placeholder')

        # Only continue if value isn't already set
        if dropdown_value and self.util.get_text(dropdown_value) == value:
            return True

        # click it
        if dropdown_preSet:
            dropdown_value.click()
        else:
            dropdown_placeholder.click()
        # load options in dropdown
        options = {}
        count = 0
        loaded = False
        while not loaded and count < 5:
            try:
                menu = container.find_element_by_class_name(
                    'Select-menu-outer')
                divs = menu.find_elements_by_tag_name('div')
                for i, div in enumerate(divs):
                    if i != 0:
                        options[self.util.get_text(div).lower()] = divs[i]
                loaded = True
            except NoSuchElementException:
                print('Unable to find dropdown items for datepicker')
                count += 1

        if count == 5 or not options:
            print('Failed to load date dropdown options')
            return False

        # click option
        try:
            option = options[value.lower()]
            option.click()
            return True
        except (IndexError, KeyError) as e:
            print('invalid date option: ' + value)
            for option in options:
                print(option)

    def parse_date(self, dateStr, dateType):
        # Given dateStr "mm/yyyy", parse and return month or year
        divider = dateStr.index('/')
        # divider should always be 2
        if divider != 2:
            print('Trying to set invalid date: ' + str(dateStr))
        if dateType == 'month':
            months = [
                'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                'Oct', 'Nov', 'Dec'
            ]
            return months[int(dateStr[:divider]) - 1]
        else:
            year = dateStr[divider + 1:]
            return year
Exemplo n.º 9
0
class CurrentHealthForm():

	def __init__(self, driver, expectedValues=None):
		self.driver = driver
		self.util = UtilityFunctions(self.driver)
		self.load(expectedValues)

	def load(self, expectedValues):

		WDW(self.driver, 10).until_not(EC.presence_of_element_located((By.CLASS_NAME, 'overlay')))
		self.form = self.driver.find_elements_by_tag_name('form')[-1]
		inputs = self.form.find_elements_by_tag_name('input')
		self.question_elements = self.form.find_elements_by_class_name('custom-current-health')
		self.questions = []
		for i, question in enumerate(self.question_elements):
			self.load_question(self.question_elements[i])

		tooltips = self.form.find_elements_by_tag_name('img')
		self.blood_pressure_tooltip = tooltips[0]
		self.blood_clot_tooltip = tooltips[1]
		self.neuropathy_tooltip = tooltips[2]

		self.continue_button = self.form.find_element_by_class_name('submitForm')
		self.validate(expectedValues)
		return True

	def load_question(self, container):
		# Load question title (label), value, and any secondary questions and their values
		labels = container.find_elements_by_tag_name('label')
		question_label = self.util.get_text(labels[0])
		value = None
		secondaryQuestions = []

		# Value: None if not set
		options = ['yes', 'no', 'dont know']
		for i, label in enumerate(labels):
			if i > 0 and i < 4:
				classes = label.get_attribute('class')
				if 'active' in classes:
				 	value = options[i - 1]
		# Find secondary questions
		if value == 'yes':
			secondary_container = container.find_element_by_class_name('custom-history_label')
			secondary_questions = container.find_elements_by_class_name('form-check')

			for secondary_question in secondary_questions:
				secondary_label = self.util.get_text(secondary_question)
				secondary_input = secondary_question.find_element_by_tag_name('input')

				selected = secondary_input.is_selected()

				secondaryQuestions.append({secondary_label: selected})

		question = {
			'name': question_label,												# name: Kidney Conditions
			'value': value,																# value: 'yes'
			'secondaryQuestions': secondaryQuestions, 		# secondaryQuesitons: [
		} 																								# {'Mild kidney problems (renal impairment)': False},
		self.questions.append(question)										# {'Severe kidney problems or on dialysis': False},]

	def validate(self, expectedValues):
		failures = []
		if expectedValues:

			# meta validation
			try:
				meta_validators = expectedValues['meta']
				for key, value in meta_validators.iteritems():
					if key == 'num_questions' and value != len(self.questions):
						failures.append('CurrentHealthForm Meta: Expected ' + str(value) + ' questions. Form has ' + str(len(self.questions)))
			except KeyError:
				# No meta validation
				pass

			# Form validation
			# expectedValues should be dictionary containing {'questions': []}
			expectedQuestions = None
			try:
				expectedQuestions = expectedValues['questions']
			except KeyError:
				# No form validation
				pass
			if expectedQuestions:
				# Check # of questions match
				if len(expectedQuestions) != len(self.questions):
					failures.append('CurrentHealthForm: Expecting ' + str(len(expectedQuestions)) + ' questions. Loaded '
						+ str(len(self.questions)))
				else:
					# Each key in each expectedQuestion (secondaryQuestions, name, value) should exist in loadedQuestion and match it's value
					for i, expectedQuestion in enumerate(expectedQuestions):
						loadedQuestion = self.questions[i]
						# print('comparing ' + str(i) + ': ' + str(expectedQuestion))
						# print('with ' + str(loadedQuestion))
						# raw_input('?')
						for key, expectedValue in expectedQuestion.iteritems():
							try:
								if loadedQuestion[key] != expectedValue:
									failures.append('CurrentHealthForm: Question ' + str(i) + ' expected value "'
										+ expectedValue + '". Loaded "' + loadedQuestion[key] + '"')
							except (TypeError, KeyError) as e:
								# raw_input(str(self.questions[i]))
								failures.append('CurrentHealthForm: Expected Key "' + key + '". Not found in question ' + str(i))

		if len(failures) > 0:
			for failure in failures:
				print(failure)
			raise NoSuchElementException('Failed to load CurrentHealthForm')

	def submit(self, questionInfo, action):
		try:
			questionInfo = questionInfo['questions']
		except KeyError:
			pass

		results = []
		for i, question in enumerate(questionInfo):
			print('answering question: ' + str(i))
			results.append(self.answer_question(i, question))

		if action == 'submit':
			self.continue_button.click()
		return True

	def answer_question(self, index, questionInfo):
		container = self.question_elements[index]
		labels = container.find_elements_by_tag_name('label')
		question_label = self.util.get_text(labels[0])
		labelIndex = {'yes': 1, 'no': 2, 'dont know': 3}

		# If right question, set value
		if question_label == questionInfo['name']:
			i = labelIndex[questionInfo['value']]
			labels[i].click()

			# Handle setting any secondary questions
			if questionInfo['value'] == 'yes' and questionInfo['secondaryQuestions']:
				expectedSecondaryInfo = questionInfo['secondaryQuestions']
				secondary_container = container.find_element_by_class_name('custom-history_label')
				secondary_questions = container.find_elements_by_class_name('form-check')

				# Check # of secondary questions
				if len(secondary_questions) != len(questionInfo['secondaryQuestions']):
					print('CurrentHealth question "' + str(index) + '" expects ' + str(len(questionInfo['secondaryQuestions']))
						+ '. Loaded ' + str(len(secondary_questions)))
					return False

				# Set value for each secondary question
				for i, question in enumerate(secondary_questions):
					question_name = self.util.get_text(question)
					input_el = question.find_element_by_tag_name('input')
					print(input_el)

					if input_el.is_selected() != expectedSecondaryInfo[i][question_name]:
						self.util.click_radio(input_el)
					# else:
					# 	print(str(index) + ' already has correct value')

		else:
			print('Index "' + str(index) + '": Expecting ' + question_label + ' to equal ' + questionInfo['name'])
			return False
		return True

	def tooltip(self):
		p = self.form.find_elements_by_class_name('tooltip-p')
		self.blood_pressure_tooltip.click()
		if self.util.get_text(p[0]).lower() != 'blood pressure is the pressure exerted on walls of the blood vessels by circulating blood. along with body temperature, respiratory rate, and pulse rate, blood pressure is one of the four main vital signs monitored by medical professionals.':
			print('tooltip not clicked correctly:' + str(self.util.get_text(p[0]).lower()))
			return False

		self.blood_clot_tooltip.click()
		if self.util.get_text(p[1]).lower() != 'deep vein thrombosis (dvt) occurs when a blood clot (thrombus) forms in one or more of the deep veins in your body, usually in your legs. deep vein thrombosis can cause leg pain or swelling, but also can occur with no symptoms.':
			print('tooltip not clicked correctly:' + str(self.util.get_text(p[1]).lower()))
			return False
			
		self.neuropathy_tooltip.click()
		if self.util.get_text(p[2]).lower() != 'neuropathy is gradual onset of numbness, prickling or tingling in your feet or hands, which can spread upward into your legs and arms.':
			print('tooltip not clicked correctly:' + str(self.util.get_text(p[2]).lower()))
			return False
		return True
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