Home > OS >  Cannot input date to field with shadow-root (user-agent) with Selenium Python
Cannot input date to field with shadow-root (user-agent) with Selenium Python

Time:07-23

I am trying to write a stable code to input a date into calendar input field. Native Selenium inputs work only locally, but when I run this code in CICD I see that numbers are sometime inputted into wrong places.

For example, the timestamp is 2022-07-22 00:56:42. Expected input by user is 220720220056. By experimenting I found out that year works if there are two zeros in front of the year. Therefore, what I actually send is 22070020220056

    input_field = driver.find_element(By.XPATH, "//div[@role='dialog']//input[@type='datetime-local']")
    input_field.click()
    input_field.clear()
    input_field.send_keys(22070020220056)

<input _ngcontent-pau-c188="" clrinput="" type="datetime-local" name="expiry" aria-describedby="clr-form-control-9-helper" id="clr-form-control-9" >
#shadow-root (user-agent) == $0
<div pseudo="-webkit-datetime-edit" id="date-time-edit" datetimeformat="dd/MM/y, HH:mm">
    <div pseudo="-webkit-datetime-edit-fields-wrapper">
        <span role="spinbutton" aria-placeholder="dd" aria-valuemin="1" aria-valuemax="31" aria-label="Day" pseudo="-webkit-datetime-edit-day-field" aria-valuenow="25" aria-valuetext="25">25</span>
        <div pseudo="-webkit-datetime-edit-text">/</div>
        <span role="spinbutton" aria-placeholder="mm" aria-valuemin="1" aria-valuemax="12" aria-label="Month" pseudo="-webkit-datetime-edit-month-field" aria-valuenow="7" aria-valuetext="07">07</span>
        <div pseudo="-webkit-datetime-edit-text">/</div>
        <span role="spinbutton" aria-placeholder="yyyy" aria-valuemin="1" aria-valuemax="275760" aria-label="Year" pseudo="-webkit-datetime-edit-year-field" aria-valuenow="2022" aria-valuetext="2022">2022</span>
        <div pseudo="-webkit-datetime-edit-text">, </div>
        <span role="spinbutton" aria-placeholder="--" aria-valuemin="0" aria-valuemax="23" aria-label="Hours" pseudo="-webkit-datetime-edit-hour-field" aria-valuenow="0" aria-valuetext="00">00</span>
        <div pseudo="-webkit-datetime-edit-text">:</div>
        <span role="spinbutton" aria-placeholder="--" aria-valuemin="0" aria-valuemax="59" aria-label="Minutes" pseudo="-webkit-datetime-edit-minute-field" aria-valuenow="1" aria-valuetext="01">01</span>
    </div>
</div>
</input>

enter image description here

Field looks like this: enter image description here

I tried few other options to make the test more stable.

Option 1.

Tried to set the value directly.

driver.execute_script(f"arguments[0].setAttribute('value', '{my_timestamp}')", input_field)

Option 2

Tried to access shadow root:

date_field = driver.execute_script("return document.querySelector('input[type=datetime-local]').shadowRoot.getElementById('#date-time-edit')")
date_field.send_keys(my_timestamp)

Option 3

Tried to get parent element with execute_script instead of Selenium and send value:

date_field = driver.execute_script("return document.querySelector('input[type=datetime-local]')")
date_field.send_keys(my_timestamp)

Option 4

Tried to send text with a small delay before each letter:

    for letter in timestamp:
        time.sleep(0.1)
        print(f"Sending letter {letter}")
        date_field.send_keys(letter)

None of these methods worked on CICD, Only initial one and Option 3 always work locally.

I think the only stable solution would be the use of Javascipt code, but still not sure.

Any suggestion would be greatly appreciated.

CodePudding user response:

Ah yes, the shadow root. For me, what works is something like the following:

shadowRootElement = driver.execute_script('''return document.querySelector("selector for shadowRoot's parent").shadowRoot''')

shadowRootChild = driver.execute_script('''return arguments[0].querySelector("selector for shadowRoot's parent").shadowRoot''', shadowRootElement)

shadowRootChild.find_element(By.CSS_SELECTOR, 'input[type=datetime-local]').send_keys("This is a test");

CodePudding user response:

The <input> looks perfectly out of #shadow-root (user-agent) ambit.

<input _ngcontent-pau-c188="" clrinput="" type="datetime-local" name="expiry" aria-describedby="clr-form-control-9-helper" id="clr-form-control-9" >
#shadow-root (user-agent) == $0
    <div pseudo="-webkit-datetime-edit" id="date-time-edit" datetimeformat="dd/MM/y, HH:mm">
        <div pseudo="-webkit-datetime-edit-fields-wrapper">
        .
        .
        .
        </div>
    </div>
</input>

However, the desired element is a Angular element, so ideally to send a character sequence to the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use the following locator strategy:

  • Using XPATH:

    input_field = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@class='clr-input ng-pristine ng-valid ng-touched' and @name='expiry'][@type='datetime-local']")))
    driver.execute_script(f"arguments[0].setAttribute('value', '{my_timestamp}')", input_field)
    
  • Note: You have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
  • Related