Selelnium - Python | Date of Birth fields by using Label

一个人想着一个人 提交于 2020-05-17 08:46:23

问题


I would like to create GENERIC python code which will fill in the day, month and year to the correct field.

BUT not sure how to.

In the first example, we can see that we have a linkage between label and input by using for parameter (BUT we need to take for parameter from the label and somehow check if it will contain DAY, MONTH and e.t.c..)

In the second example, we can see that input does not have any IDs, by the span wrapper. So we can link label with span and then somehow by using following::/input[0,1,2] find DAY,MONTH and e.t.c..

QUESTION: is it any possible way to create generic code which will work for the first and second examples? ANy best practices?

First website:

<div data-readonly="False">
   <label for="Applicants_0__DateOfBirth">Date of birth</label>
   <div class="rhsForm">
      <input type="text" class="split-date-hidden hasDatepicker" id="dp1587032701992">
      <input class="split-date-day" data-val="true" data-val-number="Please enter a valid date (day)" data-val-range="Please enter a valid date (day)" data-val-range-max="31" data-val-range-min="1" id="Applicants_0__DateOfBirth_Day" maxlength="2" name="Applicants[0].DateOfBirth.Day" placeholder="DD" type="text" value="">
      <span class="field-validation-valid" data-valmsg-for="Applicants[0].DateOfBirth.Day" data-valmsg-replace="true"></span>
      <span class="split-date-separator">&nbsp;</span>
      <input class="split-date-month" data-val="true" data-val-number="Please enter a valid date (month)" data-val-range="Please enter a valid date (month)" data-val-range-max="12" data-val-range-min="1" id="Applicants_0__DateOfBirth_Month" maxlength="2" name="Applicants[0].DateOfBirth.Month" placeholder="MM" type="text" value="">
      <span class="field-validation-valid" data-valmsg-for="Applicants[0].DateOfBirth.Month" data-valmsg-replace="true"></span>
      <span class="split-date-separator">&nbsp;</span>
      <input class="split-date-year" data-val="true" data-val-number="Please enter a valid date (year)" data-val-range="Please enter a valid date (year)" data-val-range-max="5000" data-val-range-min="1000" id="Applicants_0__DateOfBirth_Year" maxlength="4" name="Applicants[0].DateOfBirth.Year" placeholder="YYYY" type="text" value="">
      <span class="field-validation-valid" data-valmsg-for="Applicants[0].DateOfBirth.Year" data-valmsg-replace="true"></span>
      <img class="split-date-calendar-button" src="./Create a case _ the Coventry for intermediaries 3_files/CalendarIcon.png" alt="Show calendar">
      <span class="field-validation-valid" data-valmsg-for="Applicants[0].DateOfBirth" data-valmsg-replace="true"></span>
   </div>
</div>

Second website:

<div class="sel formItemContainer" f-class="EntryRow" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False">
    <div class="emc" id="Entry.Customer.C1.BirthDateEmc" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False"></div>
    <label class="sc" for="Entry.Customer.C1.BirthDate" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False">Date of birth</label>
    <div class="si" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False">
      <span f-class="PatternEntry" f-iscustom="True" f-valuetype="Date" f-minimumlength="3" f-validationname="date of birth" f-isrequired="True" f-isrequiredrule="System.True" f-isreadonlyrule="Data.Customers.C1.AuthenticatedOrPersonalDetailsReadOnly" id="Entry.Customer.C1.BirthDate" value="23/02/1990" f-entryname="Customer.C1.BirthDate" f-submitsdata="True" class="date" xmlns:msxsl="urn:schemas-microsoft-com:xslt" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False" f-readonlyruleresult="False">
        <input type="text" f-class="PatternPart" f-iscustom="True" f-behaviours="formItemChanged" value="444" maxlength="2" size="2" f-parttype="substring" f-partstart="1" f-partlength="2" f-isreadonly="False" f-hasreadonlyrulebeenappliedbefore="True" c-originalvalue="23/02/1989">
        <span f-class="PatternPart" f-parttype="static" f-value="/" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False">/</span>
        <input type="text" f-class="PatternPart" f-iscustom="True" f-behaviours="formItemChanged" value="02" maxlength="2" size="2" f-parttype="substring" f-partstart="4" f-partlength="2" f-isreadonly="False" f-hasreadonlyrulebeenappliedbefore="True" c-originalvalue="23/02/1989">
        <span f-class="PatternPart" f-parttype="static" f-value="/" f-hasreadonlyrulebeenappliedbefore="True" f-isreadonly="False">/</span>
        <input type="text" f-class="PatternPart" f-iscustom="True" f-behaviours="formItemChanged" value="1989" maxlength="4" size="4" f-parttype="substring" f-partstart="7" f-partlength="4" f-isreadonly="False" f-hasreadonlyrulebeenappliedbefore="True" c-originalvalue="23/02/1989">
        </span>
    </div>
</div>

Let's use the parameters:

d = '01'
m = '02'
y = '1933'

ar = [d,m,y]

Then the potential code will be:

l = 'Date of birth'
fls = browser.find_elements_by_xpath('//label[contains(.,"{}")]'.format(l))
    if fls:
        # loop through array <<ar>> and pass each value one by one  
        element = browser.find_elements_by_xpath('//*[@id="{}"]'.format(fls[0].get_attribute("for")))

        if element:
            containtInput = element[0].tag_name.lower() == "input"
            if containtInput:
                x = element[0].find_elements_by_xpath(./following::/input[0])
                x.send_keys(value)
                break

回答1:


I don't think it is a good idea to spend too much time on a generic solution when a page specific solution is easy when it is done well. If you are sure that all the pages you want to use use the DD/MM/YYYY format and all the fields are numeric then you may try something like this:

def fill_date(input_holder_div, data):
    fields = input_holder_div.find_elements_by_xpath('./input[@type="text"]')
    for i in range(3):
        fields[-i-1].clear()
        fields[-i-1].send_keys(data[-i-1])

my_date = [11, 11, 1980]
# fill_date(driver.find_element_by_xpath('//*[@f-class="EntryRow"]'), my_date)
# fill_date(driver.find_element_by_xpath('//*[@class="rhsForm"]'), my_date)

Calling the function with the proper parent and the data and the job is done. The -i-1 part is required to fill the last 3 input fields only and ignore the hidden input field if such element is present. But there are side effects.

What if the page does not contain a parent element which contains only these 3 input text fields. What if you encounter a page where the date format is YYYY/MM/DD or the months are in a select by name...

If you want to do very similar or the same workflow on two different layouts, then you probably should check out the page object approach. The concept is that you define in a class how to do things on a page and then just call the methods and they do what they meant to do.

Example:

class BasePage:

    def __init__(self, driver):
        self.driver = driver

    @staticmethod
    def _fill(input_element, data):
        input_element.clear()
        input_element.send_keys(data)


class FirstPage(BasePage):

    def fill_day(self, data):
        field = self.driver.find_element_by_xpath('//*[@class="split-date-day"]')
        self._fill(field, data)


class SecondPage(BasePage):

    def fill_day(self, data):
        field = self.driver.find_element_by_xpath('//*[@id="Entry.Customer.C1.BirthDate"]/input')
        self._fill(field, data)

You have FirstPage and SecondPage classes, which know how to do stuff, like how to fill the day input field. If you complete those two classes (and add the fill_month and fill_year methods) you can handle date fills with the same logic:

def fill_date(page, data):
    page.fill_day(data[0])
    page.fill_month(data[1])
    page.fill_year(data[2])


first_page = FirstPage(driver)
second_page = SecondPage(driver)

if first_page_is_loaded:
    fill_date(first_page, my_data)
else:
    fill_date(second_page, my_data)

If the workflow of the pages is very similar, all you need to do is to use the right page object. You may handle minor differences by moving some logic to the page object, and use the same flow in the main logic.



来源:https://stackoverflow.com/questions/61501307/selelnium-python-date-of-birth-fields-by-using-label

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!